はじめに
- BluespecのAWSteria_Infraを調べる(その1)
- BluespecのAWSteria_Infraを調べる(その2)
- [BluespecのAWSteria_Infraを調べる(その3)](https://vengineer.hatenablog.com/entry/2023/06/25/080000
の続き、
今日は、HW側(Verilator)の中を調べていきます。
HW側(Verilator)
HW側(Verilatorのコードは、ここ にあります。BluespecからVerilog HDLに変換しています。
トップ階層は、Platform_Sim/HW/Include_Common.mk のTOPFILEとして、Platform_Sim/HW/Top_HW_Side.bsv になります。
# ---------------- # Top-level file and module TOPFILE ?= $(AWSTERIA_INFRA_REPO)/Platform_Sim/HW/Top_HW_Side.bsv TOPMODULE ?= mkTop_HW_Side
BluespecからVerilatorへの変換は、Include_Verilator.mk 内で下記のようにcompileターゲットを実行するようになっています。bsc コマンドに -verilog オプションにて、Verilog_RTLディレクトリにVerilog HDLファイルを生成しています。
RTL_GEN_DIRS = -vdir Verilog_RTL -bdir build_dir -info-dir build_dir compile: build_dir Verilog_RTL @echo "INFO: Verilog RTL generation ..." bsc -u -elab -verilog $(RTL_GEN_DIRS) $(BSC_COMPILATION_FLAGS) -p $(BSC_PATH) $(TOPFILE) @echo "INFO: Verilog RTL generation finished"
Verilog_RTLディレクトリを見てみます。Verilog HDLコードだけでなく、C言語のソースファイルやヘッダーファイルも生成されています。C言語のファイルには、vpi_wrapperというファイル名が付いています。この vpi_wrapper は、Verilog HDLのPLI(Programming Language Interface)のWrapperになっているようです。
$ cd TestApp/HW/build_Verilator $ ls Makefile Verilator_Make Verilator_RTL Verilog_RTL build_dir exe_HW_sim $ ls Verilog_RTL mkAWSteria_HW.v vpi_wrapper_c_host_send.h mkAWSteria_System.v vpi_wrapper_c_host_send2.c mkAXI4L_S_to_AXI4_M_Adapter_synth.v vpi_wrapper_c_host_send2.h mkAXI4_16_64_512_0_Fabric_2_N.v vpi_wrapper_c_host_send_put_byte_j.c mkBytevec.v vpi_wrapper_c_host_send_put_byte_j.h mkDDR_A_Model.v vpi_wrapper_c_host_try_accept.c mkDDR_B_Model.v vpi_wrapper_c_host_try_accept.h mkDDR_C_Model.v vpi_wrapper_c_putchar.c mkDDR_D_Model.v vpi_wrapper_c_putchar.h mkTop_HW_Side.v vpi_wrapper_c_start_timing.c vpi_wrapper_c_end_timing.c vpi_wrapper_c_start_timing.h vpi_wrapper_c_end_timing.h vpi_wrapper_c_trace_file_close.c vpi_wrapper_c_host_disconnect.c vpi_wrapper_c_trace_file_close.h vpi_wrapper_c_host_disconnect.h vpi_wrapper_c_trace_file_load_byte_in_buffer.c vpi_wrapper_c_host_listen.c vpi_wrapper_c_trace_file_load_byte_in_buffer.h vpi_wrapper_c_host_listen.h vpi_wrapper_c_trace_file_load_word64_in_buffer.c vpi_wrapper_c_host_recv.c vpi_wrapper_c_trace_file_load_word64_in_buffer.h vpi_wrapper_c_host_recv.h vpi_wrapper_c_trace_file_open.c vpi_wrapper_c_host_recv2.c vpi_wrapper_c_trace_file_open.h vpi_wrapper_c_host_recv2.h vpi_wrapper_c_trace_file_write_buffer.c vpi_wrapper_c_host_recv_get_byte_j.c vpi_wrapper_c_trace_file_write_buffer.h vpi_wrapper_c_host_recv_get_byte_j.h vpi_wrapper_c_trygetchar.c vpi_wrapper_c_host_send.c vpi_wrapper_c_trygetchar.h
simulatorターゲットを実行することで生成したVerilog HDLコードとPLI Wrapperファイルをverilatorでビルドします。Verilog_RTLディレクトリ内のVerilog HDLコードをVerilator_RTLディレクトリにコピーし、ちょっと加工しています。Verilog_RTLディレクトリに生成されたPLI Wrapperファイルは使わずに、Platform_Sim/HW/C_Imported_Functions.cを使っています。そして、Platform_Sim/HW/Verilator_resources/sim_main.cpp も呼んでいます。
simulator: @echo "----------------" @echo "INFO: Preparing RTL files for verilator" @echo "Copying all Verilog files from Verilog_RTL/ to Verilator_RTL" mkdir -p Verilator_RTL cp -p Verilog_RTL/*.v Verilator_RTL/ @echo "Copying boilerplate Verilog files to Verilator_RTL" cp -p $(VERILATOR_RESOURCES)/ClockDiv.v Verilator_RTL/ @echo "----------------" @echo "INFO: Editing Verilog_RTL/$(TOPMODULE).v -> Verilator_RTL/$(TOPMODULE).v for DPI-C" sed -f $(VERILATOR_RESOURCES)/sed_script.txt Verilog_RTL/$(TOPMODULE).v > tmp1.v cat $(VERILATOR_RESOURCES)/verilator_config.vlt \ $(VERILATOR_RESOURCES)/import_DPI_C_decls.v \ tmp1.v > Verilator_RTL/$(TOPMODULE).v rm -f tmp1.v @echo "----------------" @echo "INFO: Editing Verilog_RTL/$(EDIT_MODULE2).v -> Verilator_RTL/$(EDIT_MODULE2).v for DPI-C" sed -f $(VERILATOR_RESOURCES)/sed_script.txt Verilog_RTL/$(EDIT_MODULE2).v > Verilator_RTL/$(EDIT_MODULE2).v @echo "----------------" @echo "INFO: Verilating Verilog files (in $(VERILATOR_MAKE_DIR))" verilator \ -IVerilator_RTL \ $(VERILATOR_FLAGS) \ --cc --exe --build -j 4 -o $(SIM_EXE_FILE) $(TOPMODULE).v \ --top-module $(TOPMODULE) \ $(VERILATOR_RESOURCES)/sim_main.cpp \ $(AWSTERIA_INFRA_REPO)/Platform_Sim/HW/C_Imported_Functions.c mv $(VERILATOR_MAKE_DIR)/$(SIM_EXE_FILE) . @echo "----------------" @echo "INFO: Created verilator executable: $(SIM_EXE_FILE)"
sim_main.cpp は、下記のようになっています。下記のように、Verilatorのmain関数を定義しています。
// Copyright (c) 2018-2022 Bluespec, Inc. All Rights Reserved // Top-level driver for "verilated" objects (Verilog compiled with verilator) #include <verilated.h> #include <sys/stat.h> // for 'mkdir' #include "VmkTop_HW_Side.h" // If "verilator --trace" is used, include the tracing class #if VM_TRACE # include <verilated_vcd_c.h> #endif vluint64_t main_time = 0; // Current simulation time double sc_time_stamp () { // Called by $time in Verilog return main_time; } int main (int argc, char **argv, char **env) { Verilated::commandArgs (argc, argv); // remember args VmkTop_HW_Side* mkTop_HW_Side = new VmkTop_HW_Side; // create instance of model #if VM_TRACE // If verilator was invoked with --trace argument, // and if at run time passed the +trace argument, turn on tracing VerilatedVcdC* tfp = NULL; const char* flag = Verilated::commandArgsPlusMatch("trace"); if (flag && 0==strcmp(flag, "+trace")) { Verilated::traceEverOn(true); // Verilator must compute traced signals VL_PRINTF("Enabling waves into vcd/vlt_dump.vcd...\n"); tfp = new VerilatedVcdC; mkTop_HW_Side->trace(tfp, 99); // Trace 99 levels of hierarchy mkdir("vcd", 0777); tfp->open("vcd/vlt_dump.vcd"); // Open the dump file } #endif // initial conditions in order to generate appropriate edges on // reset mkTop_HW_Side->RST_N = 1; mkTop_HW_Side->CLK = 0; while (! Verilated::gotFinish ()) { if (main_time == 2) { mkTop_HW_Side->RST_N = 0; // assert reset } else if (main_time == 7) { mkTop_HW_Side->RST_N = 1; // Deassert reset } // Toggle clock if ((main_time % 10) == 5) { mkTop_HW_Side->CLK = 1; } else if ((main_time % 10) == 0) { mkTop_HW_Side->CLK = 0; } #if VM_TRACE if (tfp) tfp->dump(main_time); #endif mkTop_HW_Side->eval (); main_time++; } mkTop_HW_Side->final (); // Done simulating // Close trace if opened #if VM_TRACE if (tfp) { tfp->close(); } #endif delete mkTop_HW_Side; mkTop_HW_Side = NULL; exit (0); }
おわりに
BluespecからVerilog HDLに変換し、Verilator(v5)でシミュレーションできるのいいですね。ここまではオープンソースのみで動くんですよね。