コグノスケ


link 未来から過去へ表示  link 過去から未来へ表示(*)

link もっと前
2019年6月26日 >>> 2019年7月23日
link もっと後

2019年6月27日

ROCK64の音がlinux-nextで鳴らなくなった

目次: ROCK64/ROCKPro64

ある時からlinux-nextでROCK64のPCMデバイスが全部消えて、一切音が鳴らなくなっていました。ROCKPro64も同じようです。

結論だけ先に言うと、この問題は既にALSA MLで指摘されていて、下記のコミットをリバートすると直ります。

問題のコミット
commit b9f2e25c599bbbf0646957e07ebb72b942c286cc
Author: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Date:   Thu Jun 20 09:49:33 2019 +0900

    ASoC: soc-core: use soc_find_component() at snd_soc_find_dai()

    snd_soc_find_dai() finds component first via specified
    snd_soc_dai_link_component, and find DAI from it.

    We already have soc_find_component() to find component,
    but soc_find_dai() has original implementation to find component.

    We shouldn't have duplicate implementation to do same things.
    This patch uses soc_find_component() at soc_find_dai()

    Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
    Signed-off-by: Mark Brown <broonie@kernel.org>

これは散々調べた後で知りました。悲しい。せっかくなので調べたこともメモしておきます。

ASoCとコンポーネントの登録

最近、ALSA SoC Layer(以下、ASoC)は、ルネサスの森本さんという方の尽力により、実装がかなり変わっているのですが、その一部がバグっていたようです。

ASoCは大まかにいうと、登録と組み合わせの2段階に分かれています。

ドライバのprobe時に、2つのcomponentを登録します。正式な呼び名がわからないので、ここではとりあえずPCMとDMACのcomponentと呼びます。

PCM componentはDAI(Digital Audio Interface)を持っています。DAIはPCMデータの入出力インタフェースのことらしいです。他にもCODECと呼ばれる、PCMデータ(デジタル音声)←→ アナログ音声に変換するドライバもcomponentとして扱われています。

サウンドカードのドライバは、複数のcomponentを組み合わせて、PCMの入出力やアナログ音声出力などを実現する仕組みです。

もう少しコード寄りに説明するとPCM componentはdevm_snd_soc_register_component() を使い、DMAC componentはdevm_snd_dmaengine_pcm_register() を使って登録します。

これらの関数を呼び出すと、

PCM用のcomponent登録時

devm_snd_soc_register_component()
  snd_soc_register_component()
    snd_soc_add_component()
      snd_soc_register_dais()
        soc_add_dai()          ★DAIをcomponentに登録★
      snd_soc_component_add()
        list_add(&component->list, &component_list); ★componentをリストに登録★
DMAC用のcomponent登録時

devm_snd_dmaengine_pcm_register()
  snd_dmaengine_pcm_register()
    snd_soc_add_component()
      snd_soc_component_add()
        list_add(&component->list, &component_list); ★componentをリストに登録★

このような経路を辿ります。

一方、componentを組み合わせる際は、

componentを組み合わせてサウンドカードを登録

devm_snd_soc_register_card()
  snd_soc_register_card()
    snd_soc_bind_card()
      snd_soc_instantiate_card()
        soc_bind_dai_link()
          snd_soc_find_dai()
            soc_find_component() ★最近変更された部分、適切なcomponentを探す、しかし…★

このように処理されます。

問題の箇所

前置きがかなり長くなりましたが、上記の処理のうちsnd_soc_find_dai() の変更にバグがあるようです。元々は関数内にcomponentを探す処理が記述されていましたが、処理は削除されsoc_find_component() で適切なコンポーネントを探してくる、という実装に変わりました。

先ほど説明した通り、大抵のASoCドライバはPCM用のcomponentをdevm_snd_soc_register_component() で、DMAC用のコンポーネントをdevm_snd_dmaengine_pcm_register() で登録しますが、かなり残念なことに双方とも全く同じ名前で登録されてしまいます。

例えばROCKPro64で /sys/kernel/debug/asoc/componentsを見ると、

ASoC登録済みcomponent一覧を見る方法
root@rockpro64:/# cat /sys/kernel/debug/asoc/components
hdmi-audio-codec.3.auto
ff870000.spdif
ff870000.spdif
ff8a0000.i2s
ff8a0000.i2s
ff890000.i2s
ff890000.i2s
ff880000.i2s
ff880000.i2s
spdif-dit
snd-soc-dummy

このように、同じ名前のcomponentが2つ登録されていることがわかります。今回のバグの件をさておいても、名前が重複しているのはイマイチですよね……。

組み合わせる際はdevm_snd_soc_register_component() で登録した方、つまりPCM用のcomponent(こいつがDAIを持っている)を探してこなければ、PCMデバイスは正常に登録されません。

しかしsoc_find_component() は動きがおかしくて、devm_snd_dmaengine_pcm_register() で登録した方のコンポーネントを返してしまいます。

結果、DAIが見つけることができず、エラーになってしまい、1つもサウンドカードが登録されないままドライバの登録処理が終わります。

もう少し早く知りたかった

この問題を散々調べた後で、既にALSA MLにて指摘されていたことを知りました。

ALSA MLを最初に調べれば、こんなにコード解析しなくても良かったなあ、と思う一方で、そもそもどういうバグかわからないと、メールは探せないので、鶏と卵ですね。

それと、今に始まったことではありませんが、ASoCは似たような名前の関数が多くて混乱します。先ほど説明にも出ましたが、snd_soc_add_component() とsnd_soc_component_add() なんて、一見で違いがわかりません。何でこんな変な名前にしたんだろう……。

メモ: 技術系の話はFacebookから転記しておくことにした。大幅に追記。

編集者:すずき(2022/05/22 15:29)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2019年7月4日

HiFive Unleashedの動作周波数

目次: RISC-V

SiFive FU540のコア動作周波数は簡単に見ることはできなかったので、求め方をメモしておきます。

アドレス0x10000000にPRCI(Power Reset Clocking Interrupt)のレジスタがありますので、実機でその辺をダンプします。

突然ダンプしますって言われても、どうしたら良いんですか?という方は拙作のmemaccess(GitHubへのリンク)をお使いください。使い慣れたツールがあれば、RISC-V上でビルドすれば使えます(UnleashedはLinuxが動くので)。

私の持っているHiFive Unleashedでは下記のようになっていました。

PRCIレジスタ領域のダンプ
10000000 c0000000 82110ec0 00000000 82110dc0
10000010 80000000 00000000 00000000 82128ec0
10000020 80000000 00000000 0000002f 00000004

COREPLL周波数を司るレジスタは、corepllcfg0(offset: 0x04)です。値は0x82110ec0ですね。

  • [ 5: 0] divr = 0x0
  • [14: 6] divf = 0x3b = 59
  • [17:15] divq = 0x2
  • [20:18] range = 3'b100 => 33MHz

レジスタの各フィールドはこんな意味になっています。計算式は、

COREPLL周波数の計算式
COREPLL = 33.33MHz / (divr + 1) * 2 * (divf + 1) / 2 ^ divq

ですので、上記の値を当てはめますと、

COREPLL周波数
COREPLL
= 33.33MHz / (0 + 1) * 2 * (59 + 1) / 2 ^ 2
= 33.33 * 120 / 4 = 999.99MHz≒1GHz

すなわち1GHz駆動であることがわかります。

ウソは書いていないつもりですが、情報源が気になる方はFU540の仕様書 "Chapter.7 Cloking and Reset" の章を見てください。

FU540の仕様書はSiFiveのサイト(FU540のサイトへのリンク)から、誰でもゲットできます。ページの下側かつ左側にある "FU540-C000 Manual" と書いてあるリンクです。

ARMの場合は簡単

Unleashedは面倒でしたが、Rockchip系(に限らないと思いますが)のSoCは /sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_max_freqを見ると簡単に最大動作周波数を取得できます。

RK3328の各コアの最大動作周波数
$ for i in /sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_max_freq ; do echo $i; cat $i; done
/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
1296000
/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_max_freq
1296000
/sys/devices/system/cpu/cpu2/cpufreq/cpuinfo_max_freq
1296000
/sys/devices/system/cpu/cpu3/cpufreq/cpuinfo_max_freq
1296000
RK3399の各コアの最大動作周波数
$ for i in /sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_max_freq ; do echo $i; cat $i; done
/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
1416000
/sys/devices/system/cpu/cpu1/cpufreq/cpuinfo_max_freq
1416000
/sys/devices/system/cpu/cpu2/cpufreq/cpuinfo_max_freq
1416000
/sys/devices/system/cpu/cpu3/cpufreq/cpuinfo_max_freq
1416000
/sys/devices/system/cpu/cpu4/cpufreq/cpuinfo_max_freq
1800000
/sys/devices/system/cpu/cpu5/cpufreq/cpuinfo_max_freq
1800000

簡単で良いですね。こういう細かい使い勝手はRISC-Vはこれからでしょうか。とはいえ世界はRISC-V旋風が吹き荒れているそうなので、次第に充実していくことでしょう。

メモ: 技術系の話はFacebookから転記しておくことにした。大幅に追記。

編集者:すずき(2021/06/28 15:25)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2019年7月5日

ARMとRISC-VでCoreMark対決

目次: RISC-V

先日購入したHiFive Unleashedが異様に遅く感じるので、手持ちの64bitコア同士でベンチマーク対決をしてみました(2019年12月5日、Raspberry Pi 3の結果を追記)。以前、モナコインのマイナーでベンチマークしたとき(2019年5月27日参照)は、Cortex-A53の1/4くらいの性能でした。

  • Rockchip RK3399(Cortex-A72 / 1.8GHz x 2, Cortex-A53 / 1.4GHz x 4)
  • Rockchip RK3328(Cortex-A53 / 1.3GHz x 4)
  • Broadcom BCM2837(Cortex-A53 / 1.2GHz x 4, 32bit mode)
  • SiFive FU540(Rocket / 1GHz x 4)

ベンチマークはCoreMarkを使いました。コンパイル条件は下記の通りです。

  • RK3399, RK3328: GCC-6.3.0 Ofast
  • BCM2837: GCC-6.3.0 Ofast, 32bit
  • FU540: GCC-8.3.0 Ofast

RK3399, RK3328はDebian arm64 Stableを使っています。StableはRISC-Vに対応していませんので、FU540だけはDebian riscv64 Unstableを使っています。BCM2837はRaspbianです。

測定の結果は、

  • RK3399: Iterations/Sec : 10242.753252
  • RK3328: Iterations/Sec : 4427.390791
  • BCM2837: Iterations/Sec : 4008.016032
  • FU540: Iterations/Sec : 2255.130422

RK3328とFU540は2倍の差です。動作周波数の差は1.3倍ですから、インオーダーのコア同士にしては性能差があります。

RK3399は異様に速いです。もしかするとA72側で動いているかもしれません。CoreMarkは特定のCPUに張り付ける方法が良くわからないですね……。

メモ: 技術系の話はFacebookから転記しておくことにした。多少追記。後日追記。

編集者:すずき(2021/06/28 15:35)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2019年7月7日

Debian Busterが来た

いつもやっているapt-get dist-upgradeを実行して、ろくに読まずにYes, Yesと適当に答えていたら、家のサーバーのDebianをStretchからBusterにアップグレードしてしまいました。

アップグレードすること自体に何も悪い点はないですが、何も今日、刈谷のホテルからやる必要は全くなかったなあ、と反省しきりです。これで起動しなくなったら、明日の夜にアクセスできなくなって困りますね……。

今回は幸いなことに再起動後も元気に動作していたので、何ら被害はありませんでした。設定を大幅に弄っている場合など、たまに起動しなくなることがあるので、今後は遠隔地から大胆なアップデートをするのはやめておきます。

メモ: 技術系?の話はFacebookから転記しておくことにした。追記&文を組み換えた。

編集者:すずき(2019/08/25 22:41)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2019年7月12日

OpenVX on OpenCL

目次: OpenCL

会社の人にOpenVXの別実装があることを教えてもらったので、試してみました。

以前、ソフトウェア実装のOpenVXライブラリを動かしました(2018年11月14日の日記参照)が、AMDのOpenVXの実装(GitHubへのリンク)を使うと、GPUでOpenVXを動かすことができます。

AMDのOpenVX実装ではありますが、OpenCLを使うのでGPUはRadeonである必要はなく、IntelのGPUでもOKです。これが共通APIたるOpenCLの良いところですね。私は現状Radeonを持っていませんので、Intelの内蔵GPUで動かしてみようと思います。

動かし方

まずOpenVXライブラリをビルドします。Debianであればopencl-c-headers辺りが必要になるはずです。またGPUドライバとしてIntel GPUドライバのOSS実装であるbeignetを使います。Debianであればbeignet-dev, beignet-opencl-icd辺りのパッケージでインストールできます。

AMD OpenVXライブラリのビルド
$ git clone https://github.com/GPUOpen-ProfessionalCompute-Libraries/amdovx-core
$ cd amdovx-core

$ mkdir build
$ cd build
$ cmake ../
$ make -j4

テストには前回も活躍したOpenVXアプリを使用します。OpenCVのバージョンは3.2です。もし古いバージョンのOpenCVを使っている場合は -lopencv_videoioオプションを外してください(おそらく「そのようなライブラリは存在しない」とエラーが出る)。

OpenVXサンプルアプリケーションのビルド
g++ solution_exercise1.cpp -Wall -I../include \
  -lopencv_video -lopencv_videoio -lopencv_highgui -lopencv_imgproc -lopencv_core \
  -lopenvx -L/path/to/amdovx-core/build/lib

前回とほぼ同じですので、さほど難しくないと思います。

GPUの実力

ビルドできましたので、実行……をする前に、vxProcessGraphの前後に時間計測のコードを入れておきます。

時間計測のパッチ

diff --git a/tutorial_exercises/solution_exercise1/solution_exercise1.cpp b/tutorial_exercises/solution_exercise1/solution_exercise1.cpp
index c7b8e21..ebc07e5 100644
--- a/tutorial_exercises/solution_exercise1/solution_exercise1.cpp
+++ b/tutorial_exercises/solution_exercise1/solution_exercise1.cpp
@@ -30,6 +30,8 @@
  *          Kari Pulli             <kari.pulli@gmail.com>
  */
 
+#include <sys/time.h>
+
 ////////
 // Include OpenCV wrapper for image capture and display.
 #include "opencv_camera_display.h"
@@ -368,6 +370,8 @@ int main( int argc, char * argv[] )
     // Process the video sequence frame by frame until the end of sequence or aborted.
     for( int frame_index = 0; !gui.AbortRequested(); frame_index++ )
     {
+        struct timeval st, ed, el;
+
         ////////********
         // Copy the input RGB frame from OpenCV to OpenVX.
         // Use vxAccessImagePatch and vxCommitImagePatch APIs (see "VX/vx_api.h").
@@ -407,8 +411,11 @@ int main( int argc, char * argv[] )
         //      if the frame_index == 0 (i.e., the first frame of the video
         //      sequence), otherwise, select the feature tracking graph.
         //   2. Use ERROR_CHECK_STATUS for error checking.
+        gettimeofday(&st, NULL);
         ERROR_CHECK_STATUS( vxProcessGraph( frame_index == 0 ? graphHarris : graphTrack ) );
-
+        gettimeofday(&ed, NULL);
+        timersub(&ed, &st, &el);
+        printf("ProcessGraph:%d.%06d[s]\n", (int)el.tv_sec, (int)el.tv_usec);
 
         ////////********
         // To mark the keypoints in display, you need to access the output

実行環境は下記のとおりです。

  • CPU: Pentium J4205/1.50GHz
  • Mem: DDR3L-1600 8GB x 2
  • GPU: Intel HD Graphics 505/250MHz(J4205内蔵)

最初にソフトウェア版のライブラリを実行します。

OpenVXサンプルアプリケーション(ソフトウェア版OpenVX)
$ LD_LIBRARY_PATH=/path/to/openvx1.1/out/LINUX/x86_64/release/ ./a.out

OK: FILE ../../tutorial_videos/PETS09-S1-L1-View001.avi 768x480
LOG: [ status = -1 ] Hello there!

ProcessGraph:0.254740[s]
ProcessGraph:0.183655[s]
ProcessGraph:0.181082[s]
ProcessGraph:0.180022[s]
ProcessGraph:0.182914[s]
ProcessGraph:0.180622[s]
...

最初のフレームはHarrisCornerによる角検出、それ以降のフレームはトラッキングに要した時間です(そういう内容のデモです)。トラッキングに大体180ms程度、掛かっている様子がわかります。

次に内蔵GPUで実行します。

OpenVXサンプルアプリケーション(GPU版OpenVX)
$ DISPLAY=:1 LD_LIBRARY_PATH=/path/to/amdovx-core/build/lib ./a.out

OK: FILE ../../tutorial_videos/PETS09-S1-L1-View001.avi 768x480
LOG: [ status = -1 ] Hello there!

LOG: [ status = 0 ] OK: OpenVX using GPU device#0 (Intel(R) HD Graphics Broxton 0) [OpenCL 2.0 beignet 1.3] [SvmCaps 0 0]

ProcessGraph:0.030192[s]
ProcessGraph:0.016439[s]
ProcessGraph:0.015872[s]
ProcessGraph:0.015629[s]
ProcessGraph:0.015629[s]
ProcessGraph:0.015679[s]
...

トラッキングに16ms程度しか掛かりません。正直言ってGPUとしてはローエンドの下の方ですが、J4205のCPU処理と比較すると圧倒的に速いです。GPU恐るべしですね。

編集者:すずき(2023/09/24 11:57)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2019年7月15日

埼玉を洪水から守る

首都圏外郭放水路 庄和排水機場(埼玉県春日部市)の調圧水槽と第一立坑(たてこう)の見学に行きました。


庄和排水機場の外観

首都圏外郭放水路とは、洪水多発地域の中川流域(埼玉県の東部)を洪水から保護するため、中川、綾瀬川といった中小河川の水を地下経由で引き込み、ポンプで引き上げて江戸川に放流する仕組みです。


首都圏外郭放水路の概要

ちなみに国の施設でして、管轄は国土交通省(サイトへのリンク)です。

見学

見学コースの一つである、調圧水槽は、地下神殿との呼び名もあるほどで、広大な空間とたくさんの柱があります。

柱の役割がわかっていなかったのですが、係の方の説明によると、周りの地下水の浮力で調圧水槽が浮き上がってしまうので、重い天井と柱で、水槽を下に押しつけているそうです。


調圧水槽

第一立坑は高さ70mの大迫力で、一番上の壁沿いに組まれた足場から下を見ることができます。私は高いところが苦手でして、非常に怖かったです。足が進まないし、変な汗が止まりません。

怖すぎて壁際にずっとしがみついていたため、写真を撮る余裕がありませんでした。一緒に行ったみなさまが高いところが平気なようで、写真をバシバシ撮っていましたので、一枚恵んでもらいました。


第一立坑(たてこう)

高いところ(立坑)はもう懲り懲りですが……、今回参加したコースとは別の見学コース(排水ポンプ室に入れる)もあるらしいので、別コースにもぜひ行ってみたいですね。

編集者:すずき(2019/08/25 23:50)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2019年7月18日

C言語とCPUアーキテクチャと除算命令

目次: C言語とlibc

今まであまりCPUアーキテクチャの違いを感じたことはありませんが、除算命令を触っていたところ、アーキテクチャによってかなり動きが違っていて面白かったので、メモしておきます。

プログラムは下記のとおりです。

-1による除算

#include <stdio.h>
#include <limits.h>

void f(int a, int b)
{
        printf("mul:%08x * %08x = %08x\n", a, b, a * b);
        printf("div:%08x / %08 = %08x\n", a, b, a / b);
}

int main(int argc, char *argv[])
{
        f(INT_MAX, -1);
        f(INT_MIN + 1, -1);
        f(INT_MIN, -1);     //乗算、除算の動作は未定義
        f(INT_MAX, 0);      //除算の動作は未定義
}

初めに断っておくと、コメントを打った箇所については、C言語上の仕様上、動作が未定義です。つまり、どんなことでも起こり得ます。不定な結果が返ることもあるし、プログラムが停止することだってあります。

未定義動作も色々

このプログラムをx86 (x86_64, Ryzen 7 2700), ARM (AArch64, Cortex A53), RISC-V (RV64GC, SiFive FU540) のLinux上でそれぞれ実行してみます。

各アーキテクチャでの実行結果

#### x86_64 ####

mul:7fffffff * ffffffff = 80000001
div:7fffffff / ffffffff = 80000001
mul:80000001 * ffffffff = 7fffffff
div:80000001 / ffffffff = 7fffffff
mul:80000000 * ffffffff = 80000000
Floating point exception


#### AArch64 ####

mul:7fffffff * ffffffff = 80000001
div:7fffffff / ffffffff = 80000001
mul:80000001 * ffffffff = 7fffffff
div:80000001 / ffffffff = 7fffffff
mul:80000000 * ffffffff = 80000000
div:80000000 / ffffffff = 80000000
mul:7fffffff * 00000000 = 00000000
div:7fffffff / 00000000 = 00000000


#### RV64GC ####

mul:7fffffff * ffffffff = 80000001
div:7fffffff / ffffffff = 80000001
mul:80000001 * ffffffff = 7fffffff
div:80000001 / ffffffff = 7fffffff
mul:80000000 * ffffffff = 80000000
div:80000000 / ffffffff = 80000000
mul:7fffffff * 00000000 = 00000000
div:7fffffff / 00000000 = ffffffff

当然ながら、動作が定義されている演算は、どのアーキテクチャでも同じ結果です。当たり前ですね。

  • INT_MAX * (-1) = INT_MIN + 1
  • INT_MAX / (-1) = INT_MIN + 1
  • (INT_MIN + 1) * (-1) = INT_MAX
  • (INT_MIN + 1) / (-1) = INT_MAX
  • INT_MAX * 0 = 0

一方で動作が未定義の演算は、かなり挙動が変わります。

  • INT_MIN * (-1) = INT_MIN
  • INT_MIN / (-1) = クラッシュ (x86_64), INT_MIN (AArch64, RV64GC)
  • INT_MAX / 0 = クラッシュ (x86_64), 0 (AArch64), -1 (RV64GC)

個性が出ますね。

x86の除算命令の奇妙な仕様

先ほどの例でx86上でINT_MIN / (-1) の除算がクラッシュする原因はidiv命令の仕様です。

Intelの命令仕様書(Intel Architectures Software Developer Manual: Vol 2)のIDIV - Signed Divideのページを見ると、保護モード例外 #DEが発生する条件として、

  • ソース・オペランド(除数)が0である場合
  • デスティネーションに対して符号付きの結果(商)が大きすぎる場合

この2条件が挙げられています。INT_MIN / (-1) は結果が32bitで表現できないため、後者に引っ掛かるわけです。

異常な演算に対して例外を発生させる設計思想なら分かりますが、乗算命令は異常な結果でも素通しなのに、除算命令は異常な結果だと例外発生します。片手落ちの不思議な仕様です。変なの……。

編集者:すずき(2023/08/19 19:34)

コメント一覧

  • hdkさん(2019/07/20 00:23)
    x86の除算例外は8086/8088の頃からありました。乗算については、8ビット同士を掛けて16ビットを出すか、16ビット同士を掛けて32ビットを出すかしかなかったので、異常な結果というのがそもそもなかったんですよね。(下位ビットだけ使うのはCコンパイラーの勝手なので。) 今はIMUL命令のオペランドが増えて同一ビット幅の答えを返す命令もありますが、例外がないのは名残か、あるいは、同じく例外がないシフトと足し算の命令の代わりに使われることを意図したかでしょうか。想像ですが。
  • すずきさん(2019/07/20 10:56)
    MUL については、結果が倍のビット幅になっていたからという理屈もわかるんですが、加算、減算はオーバーフローしたらOFをセットするだけなのに、「除算だけ」オーバーフローで例外を発生させるのは、変な仕様です。。。
  • すずきさん(2019/07/20 11:02)
    OFをセットして例外を出したければINTOでオーバーフロー例外(#OF)を発生させるのがx86の仕様に思えるのですが、除算だけ特別というかわざわざ除算例外(#DE)なんて用意しているのも不思議です……。
  • hdkさん(2019/07/24 07:25)
    加算減算は符号のありなしどちらも命令が同じですから、オーバーフローで即例外ってわけにはいかないですね。まぁ確かに除算も不正な解を出してフラグを立てる実装もありそうですが、除算回路が止まっちゃうのかなーという気も... ちなみにAAM命令でも0を指定すれば#DE発生させられます。
  • すずきさん(2019/07/24 22:22)
    AAM(ASCII Adjust AX After Multiply)って使ったことないですが、乗算系の命令でも #DE 発生するんですね。
    一貫性が無い感じが x86 らしいといえばらしいです。。。
  • hdkさん(2019/07/25 00:02)
    あっ、AAMはマニュアルのオペレーションを見ていただくとわかりますが中身は除算命令ですので、乗算系とは言えない気がします。DIV命令と違って8ビットを8ビットで割って8ビットの商と余りを出すので(全部符号なし整数)、0除算以外に例外が発生する条件はありません。
open/close この記事にコメントする



2019年7月21日

RISC-Vの命令

目次: RISC-V

最近、何かと関わっているRISC-Vの理解のため、エミュレータを書いてみています。先日購入したHiFive Unleashed(2019年5月26日の日記参照)の1st ROMと2nd ROMを拝借して、Linuxがブートする辺りまで作るのが当面の目標です。

スクラッチから作ると辛いので、ARMv5のエミュレータememu(GitHubへのリンク)をベースにして改造して作っています。まがりなりにもARMv5が動いているんだから、RISC-Vも楽勝だろうと思いきや、世の中そんなに甘くありませんでした。

最初にコケたのはUnalignedな命令ロードです。RISC-VのC拡張をサポートする場合32bit境界ではないアドレスから、32bit命令をロードする場合があります。ARMv5ではUnalignedアクセス例外が発生します。

RISC-Vの命令エンコード

まだ完成していないので、現時点での感想ですが、RISC-Vの命令エンコードは比較的わかりやすい気がします。ただ、ブランチ命令のオフセットは、下記のような並びになっていて、不思議な配置です。


RISC-Vのブランチ命令

今まで見た中で一番見づらいものは、C拡張命令のバイナリです、これは異様に見づらいです。しかしC拡張の目的(命令長を削るため16bit長に無理して詰めている)からすると、仕方ないでしょうね。

編集者:すずき(2021/11/26 11:42)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
2019年6月26日 >>> 2019年7月23日
link もっと後

管理用メニュー

link 記事を新規作成

<2019>
<<<06>>>
------1
2345678
9101112131415
16171819202122
23242526272829
30------

最近のコメント5件

  • link 02年8月4日
    lxbfYeaaさん (07/12 10:11)
    「555」
  • link 24年6月17日
    すずきさん (06/23 00:12)
    「ありがとうございます。バルコニーではない...」
  • link 24年6月17日
    hdkさん (06/22 22:08)
    「GPSの最初の同期を取る時は見晴らしのい...」
  • link 24年5月16日
    すずきさん (05/21 11:41)
    「あー、確かにdpkg-reconfigu...」
  • link 24年5月16日
    hdkさん (05/21 08:55)
    「システム全体のlocale設定はDebi...」

最近の記事3件

  • link 24年8月10日
    すずき (08/12 16:23)
    「[Linuxを調べる - initrdとカーネル引数] 目次: Linux今どき(?)のinitrdとカーネル引数の渡し方を知...」
  • link 23年4月10日
    すずき (08/12 15:08)
    「[Linux - まとめリンク] 目次: Linuxカーネル、ドライバ関連。Linuxのstruct pageって何?Linu...」
  • link 24年8月5日
    すずき (08/11 23:27)
    「[debootstrapと他アーキテクチャバイナリとbinfmt_misc] 目次: Linux以前、Debianのrootf...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 08/12 16:23