前回、Diplomacyを使ったデザインを作成し、Verilogの生成まで完了した。次に、RTLシミュレーションを行うための環境を整えていく。
RTLシミュレーションにはVerilatorを使用する。VerilatorはRocket-Chipの環境を使用する。 Rocket-ChipにはVerilatorを自動的にダウンロードしてコンパイルして実行するまでのフローが整っている。これを活用しよう。
Verilogの生成までのフロー
Verilogを生成するまでのフローは、前回までのフローをそのまま活用する。
chisel-hw/Makefile
PROJECT ?= freechips.rocketchip.unittest CONFIG ?= TLOriginalUnitTestConfig CONFIG_FIR ?= $(PROJECT).$(CONFIG).fir TestHarness.sv: $(CONFIG_FIR) ../../firrtl_origin/utils/bin/firrtl -td . -i $(PROJECT).$(CONFIG).fir -X sverilog $(CONFIG_FIR): sbt 'runMain $(PROJECT).Generator . $(PROJECT) TestHarness $(PROJECT) $(CONFIG)'
RTLシミュレーションを実行するフロー
RTLシミュレーションを実行するフローは以下のようにした。これはRocket-Chipのフローをそのまま使用している。
chisel-hw/Makefile
tilelink: TestHarness.sv verilator_bin mkdir -p $(generated_dir_debug)/$(long_name) $(VERILATOR) $(VERILATOR_FLAGS) -Mdir $(generated_dir_debug)/$(long_name) --trace \ -o $(abspath $(sim_dir))/$@ $(verilog) $(cppfiles) -LDFLAGS "$(LDFLAGS)" \ -CFLAGS "-I$(generated_dir_debug) -include $(model_header_debug)" $(MAKE) VM_PARALLEL_BUILDS=1 -C $(generated_dir_debug)/$(long_name) -f V$(MODEL).mk ./$@
変数の定義などは分離してMakefrag-verilator
で管理している。
long_name = $(PROJECT).$(CONFIG) long_name_fir = $(long_name).fir VERILATOR := rocketchip/emulator/verilator/install/bin/verilator --cc --exe VERILATOR_THREADS ?= 2 CXX ?= g++ # CXXSRCS := emulator SimDTM SimJTAG remote_bitbang CXXSRCS := main CXXFLAGS := $(CXXFLAGS) -std=c++11 -I$(RISCV)/include LDFLAGS := $(LDFLAGS) -L$(RISCV)/lib -Wl,-rpath,$(RISCV)/lib -L$(abspath $(sim_dir)) -lfesvr -lpthread JVM_MEMORY ?= 2G base_dir = $(abspath rocketchip) resources := $(base_dir)/src/main/resources csrc := $(abspath verilator_csrc) vsrc := $(resources)/vsrc sim_dir = . model_header_debug = $(generated_dir_debug)/$(long_name)/V$(MODEL).h verilog = $(abspath TestHarness.sv) MODEL ?= TestHarness generated_dir_debug = $(abspath ./generated-src-debug) VERILATOR_FLAGS := --top-module $(MODEL) \ +define+PRINTF_COND=\$$c\(\"verbose\",\"\&\&\"\,\"done_reset\"\) \ +define+RANDOMIZE_GARBAGE_ASSIGN \ +define+STOP_COND=\$$c\(\"done_reset\"\) --assert \ --output-split 20000 \ --output-split-cfuncs 20000 \ --threads $(VERILATOR_THREADS) -Wno-UNOPTTHREADS \ -Wno-STMTDLY --x-assign unique \ -I$(vsrc) \ -O3 -CFLAGS "$(CXXFLAGS) -DVERILATOR -DTEST_HARNESS=V$(MODEL) -include $(csrc)/verilator.h -include $(generated_dir_debug)/../$(PROJECT).$(CONFIG).plusArgs" cppfiles = $(addprefix $(csrc)/, $(addsuffix .cpp, $(CXXSRCS))) headers = $(wildcard $(csrc)/*.h) verilator_bin: make -C rocketchip/emulator/ verilator
Verilatorシミュレーション用main.cc
の作成
Verilatorにはシミュレーション用のC++ファイルが必要だ。制御用のC++ファイルを作成する。
chisel-hw/verilator_csrc/main.cpp
#include "VTestHarness.h" #include "verilated.h" #include "verilated_vcd_c.h" static uint64_t trace_count = 0; bool done_reset; bool verbose; double sc_time_stamp() { return trace_count; } int main(int argc, char **argv, char **env) { Verilated::commandArgs(argc, argv); VTestHarness* top = new VTestHarness; ... while (sc_time_stamp() < sim_time && !top->io_success) { if (trace_count >= 100) { top->reset = 0; } if ((trace_count % 1000) == 0) { printf ("Count = %u\n", trace_count); } if (done_reset) { break; } } tfp->close(); delete top; exit(0); }
ここまで出来たら、シミュレーションを実行してみよう。
make tilelink
... make[1]: Entering directory '/home/msyksphinz/work/riscv/chisel-development/chisel-hw/generated-src-debug/freechips.rocketchip.unittest.TLOriginalUnitTestConfig' make[1]: Nothing to be done for 'default'. make[1]: Leaving directory '/home/msyksphinz/work/riscv/chisel-development/chisel-hw/generated-src-debug/freechips.rocketchip.unittest.TLOriginalUnitTestConfig' ./tilelink Count = 1000 Count = 2000 Count = 3000 Count = 4000 Count = 5000
一応シミュレーションができたようだ。波形を確認してみよう。