ハードウェアの気になるあれこれ

技術的に興味のあることを調べて書いてくブログ。主にハードウェアがネタ。

RISC-Vの実装の1つ - SCR1の解析 - riscv-testsの実行

スポンサーリンク

前回のSCR1の記事ではriscv-toolsのビルドを行い、spikeを使ってRISC-Vのバイナリの実行が可能なことを確認した。

tech-diningyo.hatenablog.com

今回はビルドした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のシミュレータで実行するので、そのあたりだけ適宜変更していく。

github.com

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"のタブが選択可能になる↓。

f:id:diningyo-kpuku-jougeki:20180905123717p:plain

この"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 ***

とりあえずメモリ周りで何かが起きた模様。

f:id:diningyo-kpuku-jougeki:20180905123743p:plain

Vivado上のソースを見るとSCR1に接続しているメモリモデルのメモリ初期化の処理で止まっているようなので、とりあえずコメントアウトして再実行。

シミュレーションは実行されたが、メモリからデータが出てこない。

f:id:diningyo-kpuku-jougeki:20180905123821p:plain

そして以下の警告が。

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

この状態で実行してみると、、

f:id:diningyo-kpuku-jougeki:20180905123848p:plain

動いた!!

メモリから読み出されている値も"addi.dump"の値と一致している。

00000200 <_start>:
 200:  f1402573     csrr     a0,  mhartid
 204:  e101         bnez     a0,  204         <_start+0x4>

ということで、なんとかビルドしたRISC-Vのバイナリをシミュレーション環境に読み込ませて、SCR1が動く環境が出来た。

ここまでに記載したようにとりあえず...の対策をいくつか施して動かした部分もあるし、実はこのシミュレーションも正常に終わってなかったりしているので、引き続きもう少しシミュレーション環境の調査を行っていくつもりだが、今日はここまで。