lynxeyedの電音鍵盤

MBDとFPGAと車載で使うデバイスの備忘録

Chiselを使ったRISC-Vの勉強(4. プロジェクトへの機械語の読み込みの自動化)

今更ながら環境を整える

VSCodeにChiselプラグインを入れつつ頑張っていたのですが、IDEがオブジェクトやクラスの階層を把握していないため、補完機能が乏しいことなどから限界を感じてました。

いつも参考にさせていただいている、diningyo氏(id:diningyo-kpuku-jougeki)のブログ

Scalaの勉強 - 統合開発環境IntelliJ IDEAのインストール - ハードウェアの気になるあれこれ

というわけでIntelliJ IDEAに乗り換えました。すごく快適。最初っからこうしていればよかった。


f:id:Lynx-EyED:20200504114858p:plain

機械語の生成

いままでCPUロジックに与えるhexはハンドアセンブルしていましたが、そろそろ限界を感じています。
例えば、JAL命令。


f:id:Lynx-EyED:20200504020102p:plain
相対アドレスに使われるimmはこんなにビットシャッフルしているし、20bit(省略されているがLSBの1bit含めると21bit)長で、2の補数を取ります。
こんなの毎回のように手動アセンブラやってたら脳が停止してしまいます。それに、間違った機械語を記述していたのに気づかずデコーダを作ったら収拾がつかなくなります。

これに関してはみなさん工夫されているようです。

RISC-V(RV32I)のアセンブリから機械語への翻訳(簡易) - Qiita

a163236氏によるscala記述のアセンブラです。機械語がバイナリ文字列で出力されるので、コピペでChiselプロジェクトに貼り付けられるのが魅力。

さて、自分はscalaアセンブラとか記述できないので、実直にriscv64-unknown-elf-asとodコマンドを用いる方向にしました。


参考1:Chisel-Templateを使ってオリジナルデザインを作ってみるチュートリアル (3. CPUのコアのDebug-Trace作成) - FPGA開発日記
参考2:【 od 】コマンド――ファイルを8進数や16進数でダンプする:Linux基本コマンドTips(93) - @IT


Linuxやwsl環境で32bit(=4byte)長ごとに改行された可読できる機械語を出力するには以下のようにします。(アセンブラファイルはtest.s、欲しいファイルはtest.hexという名前とします。)

riscv64-unknown-elf-as test.s -o test.o
riscv64-unknown-elf-objcopy --gap-fill 0 -O binary test.o test.bin
od -An -tx4 -w4 test.bin >> test.hex


test.hexはこんな感じになります。

00000013
00100093
00100113
00200193
00300213
00400293
00500313
00600393
00700413
01b00e13
01c00e93
….

1行あたり32bitで、16進数表記です。
これならコピペしたり、scalaからSource.fromFileでオープンすることも可能です。
このブログの最後に明記しますが、Makefileを記述したので、make asmコマンドでワンストップで生成できます。
Scalaからこのファイルをオープンするにはどうしたらいいでしょう。
以下のようにしました。 間違ってたらご指摘ください。

val s = Source.fromFile("test.hex")
var bufs :Array[String] = _
try {
    bufs = s.getLines.toArray
} finally {
    s.close()
}
// このあと、Arrayから読み出すコードを記述する

ここまでのコード

コードは今後も漸進的に更新されるので、以下のように-bでタグを指定してcloneするのがいいと思います。
macOSな方はGNU odを使う関係上以下のようにしてcoreutilsをインストールしてください。

brew install coreutils

BSD odと区別するためなのはわかってるつもりですけど、GNU odをgodってするのどうかと思いますね………。
どうでもいいですけど。

git clone http://github.com/panda5mt/KyogenRV -b 0.0.10 --depth 1 
cd KyogenRV/

アセンブラは(プロジェクトフォルダ)/src/sw/test.sにあります。適宜書き換えてみてください。

nano src/sw/test.s

------- 補足:riscv-gnu-toolchainの導入(まだ導入していない人向け) -------
今回のコードからriscv-gnu-toolchainが必須となります。
こちらからソースからビルドした方がいいかも。
GitHub - riscv/riscv-gnu-toolchain: GNU toolchain for RISC-V, including GCC
パッケージ管理がディストリビューションごとに違うので、依存ファイルの導入はMacの場合を書きます。

brew install python3 gawk gnu-sed gmp mpfr libmpc isl zlib expat coreutils

riscv-gnu-toolchainを導入します。

git clone --recursive https://github.com/riscv/riscv-gnu-toolchain
cd riscv-gnu-toolchain
git submodule update --init --recursive
./configure --prefix=/opt/riscv --enable-multilib
make

PATHを/opt/riscv/binに通します。

nano ~/.bash_profile

# または
nano ~/.bashrc

.bashrcまたは.bash_profileに以下を追加

export PATH=$PATH:/opt/riscv/bin

source ~/.bash_profileまたはsource ~/.bashrcでPATHを通します。
------- 補足終わり -------

保存後、プロジェクトのルートフォルダで

make asm

するとアセンブルがはじまります。
また依存関係の解決をMakefileにさせているのでtest.sに変更があった場合は

make test

したときに同時にアセンブルも行います。(riscv-gnu-toolchainが導入されていて、PATHが通っていることが前提です。)
ビルドが完了すると(project_root)/src/sw/test.hexが生成されます。

話題は変わりますが、上記プロジェクトには分岐命令の一部を実装しています。
この分岐命令の話などは、また次回の記事で。