目次: ROCK64/ROCKPro64
ROCKPro64のシリアル文字化け問題に進展がありました。結論から先に言えば、現在のlinux-nextのI/Oドメインaudio_gpio3d4a_msの電圧設定が間違っていそうです。直したらシリアルの波形が綺麗になりました。
RK3399はI/Oドメイン(正式な名前かどうか知らない)といって、いくつかの出力ピンがグループになっています。グループごとに電源ピンがあり、電源ピンに何Vを供給しているか設定する必要があるようです。audio_gpio3d4a_msドメインの電源はAPIO5_VDD端子です。
要はAPIO5_VDD端子に1.8Vを供給するなら、audio_gpio3d4a_msドメインの設定も1.8Vにする必要があり、APIOD5_VDD端子に3.0Vを供給するなら、audio_gpio3d4a_msドメインの設定も3.0Vにする必要があります。
ROCKPro64の回路図を見ると、P.4のPower Domain Mapというページにaudio_gpio3d4a_msには電源IC(RK808)のVLDO7が繋がっていて、1.8Vだと書いてあります。linux-nextはこの記述を見て設定していると思われます。
しかしP.16の回路図を見ると、APIO5_VDD端子にはVCC_3V0(その先はVLDO8)という3.0V出力ピンが繋がっています。つまりROCKPro64の回路図は自己矛盾しています。
配線ミスってるとか、そんなのありかよ……と思いつつP.16の回路図を信じることにして、audio_gpio3d4a_msを3.0V設定にするパッチをLKMLに送りました。
偉そうに書いていますが、私はP.16の回路図には全く気づいておらず、LKMLのナイスガイ達に助けられました。ありがたいことです。
UART2信号が出ているGPIO4_C3ピンはgpio1830_gpio4cdドメインに属しており、audio_gpio3d4a_msドメインでは「ない」です。にも関わらず、なぜかaudio_gpio3d4a_msドメインの設定ミスでUART2の波形がおかしくなります。
Power Domain Mapと回路図の意図を整理すると、Power Domain Mapの設計は、下記の通りです。
一方の回路図はというと、全然接続が違いますし、端子がなかったりします。
推測ですが、意図せずに2つのドメインで電源ラインVLDO8を共有したために、audio_gpio3d4a_msドメインの設定ミスが、gpio1830_gpio4cd側のドライブ能力に影響していると思われます。
VLDO8に想定してない負荷が掛かっているような気がしますが、大丈夫なんですかね……??まあ、コスパ重視だし、趣味のおもちゃですから、燃えたり爆発したりしなければ問題ないのかな。
(補足)audio_gpio3d4a_msドメインの設定は、GRF_IO_VSELレジスタ(アドレス0xff77e640)のビット1です。
目次: GCC
世界からgccがなくなるとどうなるのか?と思ったので、試してみました。その世界では、少なくともターゲットとなる実機上でセルフコンパイルが可能になるまで、別の環境(例えばPCなど)で、
を用いて世界を構築する必要があります。何もかも試すのは不可能なので、必要最小限の要素として、
を試すことにします。
最近はclangとgccは互換性も高いし、楽勝でしょ〜などと生半可な知識で楽観視していましたが、実際やると何かもう全然ダメです。そもそもx86向けのビルドが成功しません。クロスコンパイルなんか以ての外です。
RISC-Vの人たちがGCCに真っ先に対応して、LLVMを放置している理由はこれかなあ?特にGNU, Linux系システムをビルドしようと思ったら、LLVMだけでは話にならないのでは……??
まずはU-Bootです。
$ make CC=clang defconfig $ make CC=clang
うまくいきました。さすが!ARMとかAArch64向けなら、U-Bootは良い選択肢のはずです。RISC-Vは違うブートローダを使うので意味ありませんけど。
次はLinuxです。
$ make CC=clang defconfig $ make CC=clang HOSTCC scripts/asn1_compiler HOSTCC scripts/extract-cert Compiler lacks asm-goto support. make: *** [arch/x86/Makefile:298: checkbin] Error 1
序盤でコケます。どうしたら良いんでしょう、これ。回避方法が見当たりません。
$ mkdir build $ cd build $ ../configure --prefix="/usr" CC=clang ... configure: error: *** These critical programs are missing or too old: compiler *** Check the INSTALL file for required versions.
まずconfigureが通りません。門前払いです。どうもclangを使ったとき、configureはGCC 3.x系だと思うようで、そんな古いコンパイラはダメよ?と怒られてしまいます。どうしろと。
GNU系列のglibcはclangに対応するとは思えませんし、newlibなら何とかしてくれるはず。
$ mkdir build $ cd build $ ../newlib/configure --disable-multilib CC=clang CXX=clang++ ... In file included from ../../../newlib/libc/ssp/gets_chk.c:39: In file included from /home/katsuhiro/share/projects/oss/newlib-cygwin/newlib/libc/include/limits.h:132: In file included from /usr/lib/llvm-7/lib/clang/7.0.1/include/limits.h:37: /usr/include/limits.h:145:5: error: function-like macro '__GLIBC_USE' is not defined #if __GLIBC_USE (IEC_60559_BFP_EXT) ^ 1 error generated.
ええ、そう思っていた時代が私にもありました。救世主だと勝手に思っていましたが、まさかのコンパイルできず。
いずれの手順もCC=clangを付けなければ(=GCCを使えば)成功することは確かめていますが、私の実行したビルド手順が正しい保証はありません。
GCC → clangへの切り替えを行う際に「CC=clangを付ける」が正しい手順とは限らないからです。ソフトウェアによってはclang専用に別のビルド手順が存在するかもしれません。
ビルド失敗していることからもわかる通り、私は正しいビルド手順は発見できていません。知っていたらぜひ教えて欲しいです……。
メモ: 技術系の話はFacebookから転記しておくことにした。いろいろ追記した。
目次: LLVM
いつも忘れるので、C言語のコードから、オブジェクトコード、LLVM IRビットコード、LLVM IR、アセンブラを生成する方法をメモしておきます。
C Source (.c) -> Object code (.o)
$ clang --target=riscv64 a.c -c -o a.o
C Source (.c) -> LLVM IR (.ll)
$ clang -c -S -emit-llvm a.c
C Source (.c) -> LLVM IR bitcode (.bc)
$ clang -c -emit-llvm a.c
LLVM IR (.ll) -> Assembly code (.S)
$ llc --march=riscv32 a.ll
LLVM IR (.ll) -> Object code (.o)
$ llc --march=riscv32 -filetype=obj a.ll
目次: マンガ紹介
お気に入りのマンガ紹介シリーズ。
「我が驍勇(ぎょうゆう)にふるえよ天地」は最近あまり見ない厳つい感じのタイトルですね。
異世界転生物に多いのですが、
「〜したら〜でした」
「〜が〜なんですが」
「〜は〜します」
のような説明的なタイトルって、個人的には冗長であまり好きじゃないです。面白いんだから、大丈夫だよ!もっと自信もって言い切って!!なんてことを思います。
その点、この本はタイトルからして目に留まって、とても印象的でした。
目次: LLVM
ふとClangのmain関数ってどこにあるんだろう?と思って、grepしたのですが、それらしい箇所がありません。
GDBでClangのmainにブレーク掛けてみると、llvm/tools/clang/tools/driver/driver.cppがヒットしました。んん?clangディレクトリではなく、llvmディレクトリにあるんですか?ちょっと初見ではわかりませんでした。GDBありがとう。
ClangというかLLVMの困ったところは、シンボルが多すぎてGDBの起動に数分かかることです。GDBがメモリを1.5GBほど使うのも特徴的です。デバッグのために1GBメモリを使うなんて今まで見たことありません。
この時点で既に低性能PCお断り感がビシビシ出ていますが、LLVMの極めつけはリンク時にリンカがメモリ8GBも使う(しかも1プロセスで)ことです。
その辺のショボいPCではデバッグがどうこう言う前に、そもそもビルドできず門前払いです。LLVMムチャクチャが過ぎる……。
LLVMにはRISC-V向けの実装があるのですが、デフォルトでは有効になっていないようです。LLVMのCMakeLists.txtのLLVM_ALL_TARGETSにRISCVを足します。
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ee6b77990b3..ce8f24afad1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -327,6 +327,7 @@ set(LLVM_ALL_TARGETS
MSP430
NVPTX
PowerPC
+ RISCV
Sparc
SystemZ
WebAssembly
ビルドすればRISC-V用のLLVMやツールチェーンがビルドできます。
LLVMは何も指定せずにビルドすると、対応可能な全てのアーキテクチャに対応したバイナリをビルドしようとします。ビルドがメチャクチャ遅いので、cmakeにLLVM_TARGETS_TO_BUILDでビルド対象を1つだけに制限すると、ビルド、特に最後のリンクが速くなります。
$ cmake -G Ninja \ -D LLVM_TARGETS_TO_BUILD="RISCV" \ -D CMAKE_C_COMPILER=clang \ -D CMAKE_CXX_COMPILER=clang++ \ -D LLVM_USE_LINKER=gold \ -D CMAKE_BUILD_TYPE=RelWithDebInfo \ -D LLVM_ENABLE_ASSERTIONS=ON \ ../llvm $ ninja
CMAKE_BUILD_TYPEに渡せる値は何種類かあります。Debugだとリンク時間がバカみたいに長く、リビルドが辛いです。Releaseだとビルドは速いですがデバッガがほぼ使えず、デバッグが辛いです。リリース相当だけどデバッグシンボルは付けるRelWithDebInfoが普段遣いには良いかもしれません。
メモ: 技術系の話はFacebookから転記しておくことにした。いろいろ追記した。
目次: LLVM
コンパイラが良くわからないまま放置してきましたが、最近、きつねさんでもわかるLLVM(アマゾンへのリンク)を買って読んでいます。
タイトルの通りLLVMのフロントエンド、バックエンドをコードを交えて紹介する書籍です。かなりマニアックですね……。本の中でも言及されていますが、本を読むだけより、実際にコードを動かして試すのがおすすめとのことです。
コードを変更するにせよ、そのまま動かすにせよ、まずビルドできないと始まらないので、ビルドにチャレンジします。環境はDebian Testingです。
$ gcc --version gcc (Debian 8.2.0-21) 8.2.0 Copyright (C) 2018 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
まずは何も考えずにcmake, makeしてみました。
$ mkdir build $ cmake ../llvm $ make ... [ 74%] Building NVCC (Device) object projects/openmp/libomptarget/deviceRTLs/nvptx/CMakeFiles/omptarget-nvptx.dir/src/omptarget-nvptx_generated_omp_data.cu.o In file included from /usr/include/host_config.h:50, from /usr/include/cuda_runtime.h:78, from <command-line>: /usr/include/crt/host_config.h:119:2: error: #error -- unsupported GNU version! gcc versions later than 7 are not supported! #error -- unsupported GNU version! gcc versions later than 7 are not supported! ^~~~~ CMake Error at omptarget-nvptx_generated_omp_data.cu.o.Debug.cmake:215 (message): Error generating /home/katsuhiro/share/projects/oss/clang/build/projects/openmp/libomptarget/deviceRTLs/nvptx/CMakeFiles/omptarget-nvptx.dir/src/./omptarget-nvptx_generated_omp_data.cu.o make[2]: *** [projects/openmp/libomptarget/deviceRTLs/nvptx/CMakeFiles/omptarget-nvptx.dir/build.make:135: projects/openmp/libomptarget/deviceRTLs/nvptx/CMakeFiles/omptarget-nvptx.dir/src/omptarget-nvptx_generated_omp_data.cu.o] エラー1 make[1]: *** [CMakeFiles/Makefile2:39936: projects/openmp/libomptarget/deviceRTLs/nvptx/CMakeFiles/omptarget-nvptx.dir/all] エラー2 make: *** [Makefile:152: all] エラー2
エラーメッセージを素直に解釈するとGCC 7より後だとダメっぽいです。GCC 6.0を使おうと思いましたが、Debian Testingにgcc-6というパッケージはありますが、g++-6は見当たりません。LLVMはC++ のコードがあるのでGCCだけではビルドできないのです。無念……。
ひとまずGCCは諦め、Clangを試してみます。
$ clang --version clang version 7.0.1-6 (tags/RELEASE_701/final) Target: x86_64-pc-linux-gnu Thread model: posix InstalledDir: /usr/bin
通常と異なるコンパイラを使うときはcmakeにCMAKE_C_COMPILERとCMAKE_CXX_COMPILER変数を渡します。さて、ビルドできるでしょうか?
$ cmake -G Ninja -D CMAKE_C_COMPILER=clang -D CMAKE_CXX_COMPILER=clang++ ../llvm $ ninja
コンパイラのバージョンに敏感だと、将来ビルドできなくなりそうで不安になりますが、それはさておき。とりあえずビルドに成功したので、今後はclangを使うことにしましょう。
LLVMのビルドはリンクで死ぬほどメモリを使う(1プロセスが8GB使ったりする)ので、16コアCPUだからといってninja -j16などとするとリンクの時にメモリが足りなくなってリンカがクラッシュします。
恐ろしいことにメモリ32GBだと全然足りなくて、ninja -j8でもクラッシュします。LLVMの開発者は一体どんなモンスターマシンでビルドしているんでしょうか……。
私のPCはもうメモリを増設できない(空いているDIMMスロットがない)ので、対象アーキテクチャを減らすか、ビルドの並列数を減らして、メモリを節約するしかなさそうです。
目次: ROCK64/ROCKPro64
ROCKPro64シリアル文字化けの話のまとめ、第二章。ROCKPro64は「U-Bootだと文字化けしない」という指摘をいただいたので確認したところ、確かに文字化けしません。
Drive Strengthの設定はデフォルト値(3mA)のままにも関わらず、オシロスコープでUART TX側の波形を見るとRise/Fall Timeが77ns/59nsと優秀な値です。
とりあえずボード不良ではなかったことがわかって良かったものの、何が原因でlinux-nextは文字化けしているかわからず、振出しに戻ってしまいました。
電源ONから波形を観察し続けるとlinux-nextもブートプロンプトの途中までは波形が綺麗です。linux-nextは途中で波形が鈍る設定をわざとしていることになります。
原因がわからないので、当てずっぽうでデバイスツリーの色々なノードをON/OFFしていったところ、io_domainsノードのaudio-supplyプロパティを変更するとUART TXの波形が劣化することがわかりました。
このプロパティを読み取るドライバはdrivers/power/avs/rockchip-io-domain.cにあります。追ってみるとRK3399のGRFのレジスタ0xff77e640のbit 1(audio_gpio3d4a_ms)の値を設定していました。仕様書を見るとIO domain(とは何だ?)の駆動電圧を設定するビットでした。クリアすると3.0V、セットすると1.8Vの意味です。
現在のlinux-nextは1.8V設定にしており、波形が鈍っています。U-Bootはレジスタに何も設定しないらしく、デフォルトの3.0V設定のままでした。
試しにlinux-next起動後、UART TXの波形が鈍ったことを確認したのちに、audio_gpio3d4a_msを無理やりクリア、つまりIO domain works as 3.0V設定に変えてみたところ、波形がシャキーンと綺麗になりました。
ああー、原因はこれだ。
レジスタの値を色々変えてみたところ、bit 1 audio_gpio3d4a_msを3.0Vにするか、bit 1 audio_gpio3d4a_msとbit 3 gpio1830_gpio4cd_msを両方とも1.8V設定に変えると直ることがわかりました。
しかしROCKPro64の回路図を見ると、GPIO1830は3.0Vで、VCCA1V8は1.8Vに設定する方が正しいように見えます。
正しいはずの設定になのにUARTの波形が鈍ってしまい、設定を間違えているはずのU-BootはUARTの波形が綺麗です。どうしてこうなるのか良くわかりません。原因はわかったものの、真因がわからなくて直し方もわからない、困ったタイプですね。
IO domainを3.0Vに変更し、Drive Strength 12mAの設定と組み合わせると、Rise/Fall Timeが30ns/34nsとさらに速くなります。
IO domain 3.0V + Drive Strength 12mAのときのROCKPro64シリアル出力の波形
あまりに急激に立ち上がりすぎるせいか、良く見るとRise Edgeがオーバーシュートしていますね……。
メモ: 技術系の話はFacebookから転記しておくことにした。図を追加した。
ツールのソースコードは GitHubに置いています。
前職のころレジスタダンプと、レジスタ値書き換えのためのfaという素敵なアプリ(Free Accessの略と聞いた)を使っていました。
このアプリは、/dev/mem経由でメモリの指定したアドレスを読んだり書いたりできるアプリです。何だそんなもの……と思うかもしれませんが、低レイヤデバッグには便利でして、開発の皆さんが愛用していたことを覚えています。
オリジナルのfaはデカくて無駄の多いコードだったので、何年か前に全部捨てて書き直しました。さらに他の人が書き直していなければ、今も使われているのではなかろうか?
なんと転職後もレジスタダンプが必要なシーンによく遭遇します。半導体の仕事と低レイヤデバッグは切っても切れない関係みたいです。
最初はカーネルドライバを書いてreadlで読んで、printkして…、などとやっていましたが、あまりにも面倒くさくてやってられません。やっぱりfaのようなものが欲しいなあと思い立ち、土日でパパパーっと書いて、GitHubに放り込んでおきました。
アプリの実装は /dev/memをmmapして読み書きするだけで、特に知識も要りません。たぶん誰でも書けます。
アプリの名前ですが、Free AccessだとWi-Fiスポットみたいで変だな……と思って、ma(memaccess, memory accessの略)にしておきました。memory dumpにしたかったのですが、有名なツールと同じ名前で紛らわしいのでやめました。
もしmemory dumpでレジスタ読み書きができれば、わざわざアプリを作る必要はなかったのですが、しかしmemory dumpはバイナリで出力する方に重きを置いており、エディト機能もなさそうで、設計の方向性が違いました……。残念。
目次: OpenCL
先日(2018年11月14日の日記参照)動かしたOpenVX + OpenCVのデモをAArch64上でも動かそうと思います。クロスコンパイルではなくARM上でセルフコンパイルします。環境はDebian 9、ボードはROCKPro64です。
前回同様OpenVXライブラリをビルドする必要がありますが、単純にmakeするとビルドに失敗します。
[GCC] Compiling C99 vx_debug.c gcc: error: unrecognized argument in option '-mabi=aapcs-linux' gcc: note: valid arguments to '-mabi=' are: ilp32 lp64 gcc: error: unrecognized command line option '-mapcs'; did you mean '--specs'? gcc: error: unrecognized command line option '-mno-sched-prolog'; did you mean -Wno-sign-promo'? gcc: error: unrecognized command line option '-mno-thumb-interwork'; did you mean '-fno-sched-interblock'? concerto/finale.mak:289: recipe for target '/home/katsuhiro/projects/openvx/out/LINUX/aarch64/release/module/debug/vx_debug.o' failed
Makefileに不要なオプションが指定されていてビルドが失敗しているようなので、削除します。
diff --git a/concerto/compilers/gcc.mak b/concerto/compilers/gcc.mak
index aca2556..0295e39 100644
--- a/concerto/compilers/gcc.mak
+++ b/concerto/compilers/gcc.mak
@@ -125,9 +125,9 @@ endif
endif
ifeq ($(TARGET_FAMILY),ARM)
-$(_MODULE)_COPT += -mapcs -mno-sched-prolog -mno-thumb-interwork
+#$(_MODULE)_COPT += -mapcs -mno-sched-prolog -mno-thumb-interwork
ifeq ($(TARGET_OS),LINUX)
-$(_MODULE)_COPT += -mabi=aapcs-linux
+#$(_MODULE)_COPT += -mabi=aapcs-linux
endif
endif
ちなみにcmakeによるビルドも可能ですが、ARMに対応できていないように見えます。
diff --git a/cmake_utils/CMake_linux_tools.cmake b/cmake_utils/CMake_linux_tools
.cmake
index caaa017..dc2371f 100644
--- a/cmake_utils/CMake_linux_tools.cmake
+++ b/cmake_utils/CMake_linux_tools.cmake
@@ -32,10 +32,10 @@ if(BUILD_X64)
else()
if (TARGET_CPU STREQUAL "Atom")
# architecture will be according to ATOM
- set(ARCH_BIT -m32 )
+ # set(ARCH_BIT -m32 )
else ()
# need to force a more modern architecture than the degault m32 (i386).
- set(ARCH_BIT "-m32 -march=core2" )
+ # set(ARCH_BIT "-m32 -march=core2" )
endif (TARGET_CPU STREQUAL "Atom")
endif()
正しい直し方ではありませんが、とりあえずx86向けの設定を改造して、x86用のオプションを外すとビルドが通ります。
OpenVXライブラリのビルドが通ったら、サンプルをビルドします。
$ cd openvx_tutorial/tutorial_exercises/solution_exercise1 $ g++ -I ../include -L /path/to/openvx/out/LINUX/aarch64/release/ solution_exercise1.cpp \ -lopencv_imgproc -lopencv_highgui -lopencv_core -lopenvx
もしcmakeでライブラリを作った場合は、ライブラリの生成先ディレクトリが異なります。下記のようにします。
$ cd openvx_tutorial/tutorial_exercises/solution_exercise1 $ g++ -I ../include -L /path/to/openvx/build/sample/framework/ solution_exercise1.cpp \ -lopencv_imgproc -lopencv_highgui -lopencv_core -lopenvx
実行する際は、HDMI出力などのGUI画面に表示してもよいですし、vncserverなどの画面にも表示できます。下記の例はvncserverに表示する例です。
$ DISPLAY=:1 \ LD_LIBRARY_PATH=/path/to/openvx/out/LINUX/aarch64/release/ \ ./a.out
もしcmakeでビルドしたライブラリを使う場合、ライブラリがバラバラのディレクトリに置かれているため、LD_LIBRARY_PATHに指定するパスがやや長くなります。
$ DISPLAY=:1 \ LD_LIBRARY_PATH=/path/to/openvx/build/sample/framework/:/path/to/openvx/build/sample/targets/c_model/:/path/to/openvx/build/sample/vxu/:/path/to/openvx/build/libraries/extras/:/path/to/openvx/build/libraries/debug/ \ ./a.out
もしcmakeでビルドしたライブラリでトラブルが起きたときは、cmake -DCMAKE_BUILD_TYPE=RelWithDebInfoと指定してデバッグ情報を有効にしてビルドすることで、デバッグしやすくなります。
TightVNCサーバーを使うとアプリケーションの実行時に下記の警告が出ます。
Xlib: extension "RANDR" missing on display ":1".
警告が出ても動作はするのですが、気になる方は下記のようにTigerVNCをインストールするなど、RANDRに対応したVNCサーバーを使ってください。
# apt-get install tigervnc-standalone-server
< | 2019 | > | ||||
<< | < | 03 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | - | 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 | - | - | - | - | - | - |
合計:
本日: