前回、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
一応シミュレーションができたようだ。波形を確認してみよう。
