前回のSCR1ネタではVivadoシミュレータを使用した際に$readmemh
がうまく行かない問題を解析していった。
今回はもうひとつ残っているシミュレーションが正常に終わらない問題について解析していく。
これね↓。
実はこのシミュレーションも正常に終わってなかったりしているので、引き続きもう少しシミュレーション環境の調査を行っていくつもり
シミュレーションが終わらない問題
現状の状態でシミュレーションを実行すると、Vivadoのシミュレータで設定できる最大シミュレーション時間に到達したためシミュレーションが終了している状態にある。
現在のシミュレーションに関する設定は以下の画像の通りで、シミュレーションの最大実行時間は3usになっている。
シミュレーションの波形は以下のような感じ。
黄色のフラグが立っている2295ns以降にAXIバスの動きが一切止まっている状態なのに、シミュレーション自体はタイムアウトの3usまで実行されている状態にある。
シミュレーションの終了条件
この「3usで終了する」という動作が意図した動作の可能性もあるので、先にこのSCR1のシミュレーション環境の終了条件について確認しておく。
scr1_top_tb_axi.svに以下のように明示的な$finish
が存在しており、ここに到達すればシミュレーションが終了するはずである。
// scr1_top_tb_axi.sv - L.180 - L.213 forever begin if ($feof(f_info)) break; ret_val = $fscanf(f_info, "%s\n", i_memory_tb.stuff_file); i_top.i_core_top.i_pipe_top.i_tracelog.test_name = i_memory_tb.stuff_file; $write("\033[0;34m---Test: %s\033[0m\n", i_memory_tb.stuff_file); reset(); forever begin @(posedge clk) if (i_top.i_core_top.i_pipe_top.curr_pc == SCR1_EXIT_ADDR) begin bit test_pass; test_pass = (i_top.i_core_top.i_pipe_top.i_pipe_mprf.mprf_int[10] == 0); tests_total += 1; tests_passed += test_pass; $fwrite( f_results, "%s\t\t%s\n", i_memory_tb.stuff_file, (test_pass ? "PASS" : "__FAIL") ); if (test_pass) $write("\033[0;32mTest passed\033[0m\n"); else $write("\033[0;31mTest failed\033[0m\n"); break; end end end $display("\n#--------------------------------------"); $display("# Summary: %0d/%0d tests passed", tests_passed, tests_total); $display("#--------------------------------------\n"); $fclose(f_info); $fclose(f_results); $finish();
この$finish
に到達するためには以下の2つのforever
ループを抜けなければならないことがわかる
- 外側の
forever
ループ :f_info
ファイルのEOFに到達すること - 内側の
forever
ループ : SCR1内部のcurr_pc
がSCR1_EXIT_ADDR
に到達すること
現在のシミュレーションの状態
ここで先程のシミュレーション波形をもう一度確認してみる。AXIバスの動きが無くなった部分を拡大したすると以下のようになっていた。
波形中の各信号io_axi_imem_***
はSCR1から出力されるRISC-Vの命令リード用のAXI I/Fとなっており、この中のio_axi_imem_araddr
がSCR1から出力される次の命令のアドレスとなっている。
この信号が0x0になる前の最後の値は
io_axi_imem_araddr = 0x4ac
となっている。
先に確認した内側のforever
ループの脱出条件となるがSCR1_EXIT_ADDR
は同じファイルに定義されており、以下の通りである。
// scr1_top_tb_axi.sv - L.13 - 16 //------------------------------------------------------------------------------ // Local parameters //------------------------------------------------------------------------------ localparam logic [`SCR1_XLEN-1:0] SCR1_EXIT_ADDR = 32'h000000F8;
このことから、2つあるforever
ループのうち内側のループの終了条件に到達していないことが原因で$finish
に辿り着かないため、シミュレーションが終了しないことがわかった。
ここからは実際のテストコードを見ていこう。
現在実行しているのはriscv-testsの中から適当に選択したaddi命令のテストになっている。波形デバッグの際には実際のソースではなく、テストのビルド時に生成される*.dumpを見るほうがいいのでそちらを確認していく。なお、*.dumpファイルはSCR1の環境においてはビルド時に"build"ディレクトリ以下にELFファイルと一緒に生成されるようにMakefileに定義されている。
- scr1/tests/riscv_isa/Makefile
# Makefile - L.36 - 37 $(bld_dir)/%.dump: $(bld_dir)/%.elf $(RISCV_OBJDUMP) $^ > $@
ではaddi.dumpを確認していく。先ほど波形で確認したアドレスをaddi.bumpから探すと以下の部分になる。
00000494 <fail>: 494: 0ff0000f fence 498: 85f2 mv a1,t3 49a: 4505 li a0,1 49c: 00000073 ecall 000004a0 <pass>: 4a0: 0ff0000f fence 4a4: 85f2 mv a1,t3 4a6: 4501 li a0,0 4a8: 00000073 ecall 000004ac <ecall>: 4ac: 00000073 ecall
上記のようにaddi試験における試験のPASS/FAIL判定部分のコードになる。更にシミュレーション上で0x4ac
以前の命令読み出しアドレスを確認すると0x4a0 - 0x4a8
を通過しているので、このテスト自体の判定はPASS判定になっていることもわかった。
本来なら、この0x4ac
のecall
命令を経て、命令読み出しアドレスがSCR1_EXIT_ADDR=0xF8
に到達しなければならないのだが、今のVivadoシミュレーション上はそうなっていないためシミュレーションが正常に終了しないことがわかった。
うーーーむ、とりあえず終了しない理由はわかったけど、これ以上はSCR1の中の解析が必要そう。
引き続き調査が必要、、、ということがわかったので今日はここまで。