久しぶりに自作RISC-Vコアのメンテナンスを行おうと思っているが、個人が使用できるSystemVerilogのシミュレーション環境ってどれも中途半端で困っている。VCSやXceliumは使えないし、VerilatorはC++による独自のドライブが必要、おそらくSystemVerilogを個人がまじめに使うためにはVivado Simulatorが現実的だろうが、今度は波形ビューワが非常にしょぼい。業務でVerdiなどを使っていれば、GTKWaveなどは使い悪すぎて死にそうだし、Vivadoの波形ビューワもしかりだ。
MentorのModelSim Intel Starter Editionも考えられるが、そもそも32ビットバイナリしか配布されていないし、WSLと相性が最悪なので良くない。結局どのRTLシミュレータも決定打が無いわけだ。
と言っても文句ばかり言っていても仕様がないので、独自CPUコアのシミュレーション環境をVerilatorで構築することにする。Verilatorの使い方は私の過去のブログで復習する。
シミュレーション用のTBファイルとしては以下を用意する。
module mrh_tb ( input logic i_clk, input logic i_reset_n ); logic w_ic_req_valid; mrh_pkg::mem_cmd_t w_ic_req_cmd; /* 中略 */ mrh_tile_wrapper u_mrh_tile_wrapper ( .i_clk (i_clk ), .i_reset_n (i_reset_n), // L2 request from ICache .o_ic_req_valid (w_ic_req_valid ), .o_ic_req_cmd (w_ic_req_cmd ), ... .i_ic_resp_data (w_ic_resp_data ), .o_ic_resp_ready (w_ic_resp_ready) ); tb_l2_behavior_ram #( .DATA_W (mrh_pkg::ICACHE_DATA_W), .TAG_W (mrh_pkg::L2_CMD_TAG_W), .ADDR_W (riscv_pkg::PADDR_W), .BASE_ADDR ('h8000_0000), .SIZE (4096), .RD_LAT (10) ) u_tb_l2_behavior_ram ( .i_clk (i_clk ), .i_reset_n (i_reset_n), ...
TBファイルをドライブするためのC++ファイルとしては以下のようなものを作った。FSTファイルを出力するように修正している。
int main(int argc, char** argv) { Verilated::commandArgs(argc, argv); // Instantiate DUT Vmrh_tb *dut = new Vmrh_tb(); // Trace DUMP ON Verilated::traceEverOn(true); VerilatedFstC* tfp = new VerilatedFstC; dut->trace(tfp, 100); // Trace 100 levels of hierarchy tfp->open("simx.fst"); /* 中略 */ int cycle = 0; while (time_counter < 500) { if ((time_counter % 5) == 0) { dut->i_clk = !dut->i_clk; // Toggle clock } if ((time_counter % 10) == 0) { // Cycle Count cycle ++; } // Evaluate DUT dut->eval(); tfp->dump(time_counter); time_counter++; } dut->final(); tfp->close(); }
これでプロジェクト全体をコンパイルするように調整した。
$ make
verilator --top-module mrh_tb -o ../mrh_tb_rv32 --Mdir obj_dir_riscv32 --exe ../cpp/tb_mrh.cpp --cc -I../src --trace-fst --trace-params --trace-structs --trace-underscore ../src/riscv_common_pkg.sv ../src/riscv32_pkg.sv -f filelist.f verilator --top-module mrh_tb -o ../mrh_tb_rv64 --Mdir obj_dir_riscv64 --exe ../cpp/tb_mrh.cpp --cc -I../src --trace-fst --trace-params --trace-structs --trace-underscore ../src/riscv_common_pkg.sv ../src/riscv64_pkg.sv -f filelist.f make -C obj_dir_riscv32 -f Vmrh_tb.mk
これでとりあえず良いだろう。シミュレーションを実行してみる。
$ ./mrh_tlb_rv64
一応上手く行っているようだ。