前回のSCR1の記事ではriscv-toolsのビルドを行い、spikeを使ってRISC-Vのバイナリの実行が可能なことを確認した。
今回はビルドしたRISC-V用のtoolchainを使ってriscv-testsをSCR1向けにビルドしVivadoのシミュレータでシミュレーションを実行してみたい。
SCR1シミュレーション向けのビルド環境について
SCR1の環境では以下の3つのシミュレータ向けの環境が準備されている。
- vcs
- modelsim
- ncsim
上記の中でなんとか実行できそうなのはIntel FPGA向けに機能限定版が提供されているmodelsimくらいか。とはいえ、以下の10,000ラインの制限があるので厳しそう。
SCR1のgithub環境の最上位ディレクトリに登録されているMakefile(以下)にはSCR1のシミュレーション実行に必要なビルド処理が一式含まれている。
scr1 └── Makefile
例えば以下のようなものだ。
- SCR1自体のコンフィグレーション(SCR1の外部I/Fの選択やサポートする命令セットなど)
- シミュレーションで実行するテストの選択とビルド(実際のビルドの制御はサブディレクトリのMakefileが行う)
- シミュレーションの実行(vcs/modelsim/ncsim)
そのためmake
の実行時の引数を変更することで、SCR1のコンフィグレーション、シミュレーション用バイナリのビルド〜指定したシミュレーションの実行までを一気に実行することが可能だ。
SCR1+Vivadoシミュレータでのriscv-testsの実行
基本的な手順はSCR1のgithubリポジトリの手順に従うがVivadoのシミュレータで実行するので、そのあたりだけ適宜変更していく。
riscv-testsの準備
前項に記載したように、トップのMakefile中にシミュレーション用バイナリのビルドが含まれておりSCR1のリポジトリの手順に従うことでシミュレーション用のバイナリを生成できるので、まずはバイナリを生成していく。
riscv-toolsの設定
riscv-toolsのビルド時にすでに設定していれば不要だが、ビルド後にインストールしたRISC-Vのコンパイラへのパス設定を行っておく
$ cd <RISC-Vのコンパイラのパス> $ export PATH=$PATH:$PWD
riscv-testsの準備
クロスコンパイラのパス設定が終わったら、riscv-testsを準備する。環境変数設定でriscv-testsの場所を指定する作りになっているので、クローンする場所は自由に変更可能。
一応、SCR1の手順では使用するriscv-testsのリビジョンの指定があるのでそれに従っておく。
$ git clone https://github.com/riscv/riscv-tests
$ cd riscv-tests
$ git checkout a9433c4daa287fbe101025f2a079261a10149225
チェックアウトが終わったら、環境変数RSICV_TEST
を設定して、SCR1環境がriscv-testsの場所を認識できるようにする。
$ export RSICV_TEST=<riscv-testsのディレクトリ>
ここまでを行うとSCR1環境のMakefileを使ってシミュレーション用のバイナリを生成することが可能になる。
riscv-testsのビルド
手順に従うと以下のコマンドを実行すると、シミュレーションまでの一連の処理が実行される。
make run_<SIMULATOR> BUS=<AHB, AXI> RVE=<0, 1> RVM=<0, 1> IPIC=<0, 1>
例えば以下のように実行する。
make run_vcs BUS=AHB RVE=1 RVM=1 IPIC=1
上記のコマンドでは
- SCR1の外部I/FはAXI
- サポートする命令セットはRV21EM
- IPICを使用する構成
- VCSでシミュレーションを実行
となる。
ところで以前の記事でriscv-toolsをビルドした際には32bit-CPU環境のクロスコンパイラを生成している。SCR1のMakfileではデフォルトの設定がriscv64-unknown-elf-
になっておりそのまま実行するとエラーになってしまう。そのため、実行前にコマンドの部分だけを修正しておく。
修正する場所はMakefileのL.34のCROSS_PREFIX
を修正する
#export CROSS_PREFIX ?= riscv64-unknown-elf- export CROSS_PREFIX ?= riscv32-unknown-elf-
make
コマンド実行時にビルドされるテストはコマンド実行時のSCR1のコンフィグレーションによって決定される作りとなっており、今回目的とするriscv-testsをビルドするためにはRVM=1
を指定する必要がある。
ということで今回は以下のコマンドにてビルドを実行する。
$ make run_vcs BUS=AXI RVM=1
riscv-testsのビルドが通ると以下のように選択したシミュレータによるシミュレーションを実行しようとしてエラーが発生する(以下はVCSを選択した場合)。
/bin/sh: 2: vcs: not found Makefile:22: ターゲット 'build_vcs' のレシピで失敗しました make[1]: *** [build_vcs] エラー 127 make[1]: ディレクトリ '/home/dnn-admin/workspace/hw/study/1000_scr1/scr1/src' から出ます Makefile:95: ターゲット 'run_vcs' のレシピで失敗しました make: *** [run_vcs] エラー 2
ビルド時の全ログはこちら
バイナリのビルドが終わるとbuildというディレクトリに各種riscv-testsのテストごとに以下の3つのデータが生成される。
通常のフローだと上記のバイナリ生成の後にシミュレータにxxx.hexをデータとして入力することでriscv-testsが実行されるが、今回はシミュレータが違うのでそこをVivado向けに変更していく
Vivado向けの設定
以下のようにシミュレーション実行時にはいくつかの設定を$value$plusargs
を使ってシミュレーション環境に渡している。
# scr1_top_tb_ahb.sv - L.105 - L.108 $value$plusargs("imem_pattern=%h", imem_req_ack_stall); $value$plusargs("dmem_pattern=%h", dmem_req_ack_stall); $value$plusargs("test_info=%s", s_info); $value$plusargs("test_results=%s", s_results);
これらの設定の意味は以下の通り。
パラメータ | 説明 |
---|---|
imem_pattern | imem(命令フェッチ用のI/F)からのメモリアクセス発行時のメモリの遅延設定。FFFFFFFF - no delay, 00000000 - random delay, 00000001 - max delay |
dmem_pattern | dmem(データフェッチ用のI/F)からのメモリアクセス発行時のメモリの遅延設定。設定値はimem_patternと同様。 |
test_info | シミュレーション実行対象となるRISC-Vバイナリのリスト |
test_results | シミュレーションの実行結果が出力されるファイルのパス |
というわけでVivadoシミュレータの設定を行い、上記の設定をシミュレータに渡すように設定を行う必要がある。が、やり方を知らないので調べるところから。
ロジックシミュレータのガイドによると、xsim
のコマンド引数に-testplusarg <arg>
を渡せば設定が可能なようだ。
引数 | 説明 |
---|---|
-testplusarg <arg> |
plusargsが$test$plusargs および$value$plusargs システム関数で使用されるように指定します |
"PROJECT MANAGER"の"Settings"を開き”Simulation”の項目を開くと画面右側から"Simulation"のタブが選択可能になる↓。
この"Simulation"タブの一番下にxim.simulate.xsim.more_options
という項目があるので、ここに上記4項目の設定を追加する。
-testplusarg imem_pattern=FFFFFFFF -testplusarg imem_pattern=FFFFFFFF-testplusarg test_info=<test_infoのパス> -testplusarg test_results=<出力ログのパス>
なお、上記のtest_infoはmake
コマンド実行時に生成されるシミュレーションを実行するバイナリファイルのリストになっており、RISC-Vのバイナリと同様にbuildディレクトリの下に生成されている。
riscv-testsの実行
前項の設定を行い、シミュレーションを実行してみる。
、、、と、エラーが出て止まった。。
FATAL_ERROR: Vivado Simulator kernel has discovered an exceptional condition from which it cannot recover. Process will terminate. For technical support on this issue, please open a WebCase with this project attached at http://www.xilinx.com/support.
Vivadoを立ち上げたコンソールの方にもスタックトレースが。。
*** Error in `xsim.dir/scr1_top_tb_axi_behav/xsimk': double free or corruption (!prev): 0x0000000001c7ed50 ***
とりあえずメモリ周りで何かが起きた模様。
Vivado上のソースを見るとSCR1に接続しているメモリモデルのメモリ初期化の処理で止まっているようなので、とりあえずコメントアウトして再実行。
シミュレーションは実行されたが、メモリからデータが出てこない。
そして以下の警告が。
WARNING: File h referenced on /home/dnn-admin/workspace/hw/study/fpga-scr1/scr1/src/tb/scr1_memory_tb_axi.sv at line 148 cannot be opened for reading. Please ensure that this file is available in the current working directory.
scr1/scr1/src/tb/scr1_memory_tb_axi.sv at line 148
ここはメモリにRISC-Vのバイナリを読み込む$readmemh
の実行部分なのでファイルが開けずにRISC-Vのバイナリがメモリに読み込まれてないことになり、シミュレーションの挙動とも一致する。
always @(negedge rst_n) begin //memory = '{SIZE{'0}}; if(stuff_file.len()>0) $readmemh(stuff_file,memory); # L.148 end
上記のstuff_file
テストベンチのトップ階層で"test_info"ファイルの情報を元に設定されている。
最終的にはtest_infoの情報から実行できるようにしたいが、とりあえずシミュレーションが動くかどうかを確認をするために、上記stuff_file
の部分を直接buildディレクトリ以下にある適当なxxx.hexファイルを示すように書き換える(ここではaddi.hexを使用)。
always @(negedge rst_n) begin //memory = '{SIZE{'0}}; $readmemh("./scr1/build/addi.hex", memory); // 修正後 //if(stuff_file.len()>0) $readmemh(stuff_file,memory); end
この状態で実行してみると、、
動いた!!
メモリから読み出されている値も"addi.dump"の値と一致している。
00000200 <_start>: 200: f1402573 csrr a0, mhartid 204: e101 bnez a0, 204 <_start+0x4>
ということで、なんとかビルドしたRISC-Vのバイナリをシミュレーション環境に読み込ませて、SCR1が動く環境が出来た。
ここまでに記載したようにとりあえず...の対策をいくつか施して動かした部分もあるし、実はこのシミュレーションも正常に終わってなかったりしているので、引き続きもう少しシミュレーション環境の調査を行っていくつもりだが、今日はここまで。