一、引言:
玩过单片机的同学应该都知道,在使用cpu/mcu跑程序时,我们通常是SDK软件(例如keil)+下载器(其协议往往是jtag或者swd)+cpu芯片的组合,以此来对cpu进行下载程序、打断点、以及读写某些寄存器的操作。对应的在我们设计一个CPU时也需带有相应的模块供其调试,在SOC的设计中,其CPU调试模块的设计难度往往是大于核的,若想在设计过程中监测调试模块与cpu的信号交互,一个方案是把SOC部分或全部套个壳子在FPGA上跑,再接个下载器,用ila即可抓取相应的波形信息(详情可参考蜂鸟处理器那本书)。但在FPGA跑抓波的效率确实很低,一个好的在线仿真RTL代码的调试平台能达到事半功倍的效果,抓波还得用verdi才带劲,那么解决方案即为:VCS+OpenOCD+RISC-V,选取tinyriscv项目来即可学习这套环境。
二、SDK:
OpenOCD其开源特性强工具成熟,且兼顾windows、linux,此乃绝佳选择。需要搭配debug adapter(比如JLink,ST-Link,DAP-Link)和GDB(或Telnet)一起使用。
三、下载器(JTAG adpter):
套路一般是GDB/telne+OpenOCD+DPI组合,两两之间使用TCP协议通信。OpenTitan里有现成的JTAG DPI,将其在顶层TB verilog里接上,file list里加入JTAG DPI的verilog和C文件,也包括TCP server的C code。
在tb中把他们连起来:
wire sim_jtag_tck;
wire sim_jtag_tms;
wire sim_jtag_tdi;
wire sim_jtag_trstn;
wire sim_jtag_tdo;
wire [31:0] sim_jtag_exit;
tinyriscv_soc_top #(
.TRACE_ENABLE(1'b1)
) u_tinyriscv_soc_top (
.clk_50m_i (clk_i),
.rst_ext_ni (rst_ni),
.dump_wave_en_o(dump_wave_en_o),
.halted_ind_pin(halted),
.jtag_TCK_pin (sim_jtag_tck),
.jtag_TMS_pin (sim_jtag_tms),
.jtag_TDI_pin (sim_jtag_tdi),
.jtag_TDO_pin (sim_jtag_tdo)
);
`ifdef sim_jtag
sim_jtag #(
.TICK_DELAY(10),
.PORT(9999)
) u_sim_jtag (
.clock ( clk_i ),
.reset ( ~rst_ni ),
.enable ( 1'b1 ),
.init_done ( rst_ni ),
.jtag_TCK ( sim_jtag_tck ),
.jtag_TMS ( sim_jtag_tms ),
.jtag_TDI ( sim_jtag_tdi ),
.jtag_TRSTn ( sim_jtag_trstn ),
.jtag_TDO_data ( sim_jtag_tdo ),
.jtag_TDO_driven ( 1'b1 ),
.exit ( sim_jtag_exit )
);
`endif
四、Makefile
在tinyriscv的基础上改吧改吧就变成vcs+verdi
PROG := ../sdk/examples/simple/simple.mem
PROG_DIR := $(shell dirname $(PROG))
MAKE := make
VCS := vcs
VERI_FLAGS += +vcd
VERI_CFLAGS += -DVL_DEBUG
VERI_VFLAGS += -DTRACE_ENABLED
RTL_FILES = filelist.f
VERI_OBJ_DIR := cobj_dir
ifeq ($(findstring +vcd,$(VERI_FLAGS)),+vcd)
VERI_TRACE = "--trace"
VERI_CFLAGS += "-DVCD_TRACE"
else
VERI_TRACE =
endif
SIM_TOP_MODULE := tb_top_verilator
DEFAULT_GOAL := sim
all: sim
.PHONY: recompile
recompile:
rm -rf $(VERI_OBJ_DIR) testbench_verilator
$(MAKE) -C ./remote_bitbang clean
$(MAKE) -C $(PROG_DIR) clean
$(MAKE) compile
.PHONY: compile
compile: remote_bitbang/librbs.so $(PROG) testbench_verilator
vlogan :
vlogan -f filelist.f \
-timescale=1ns/1ps -fsdb \
-sverilog +lint=all -full64 +define+TRACE_ENABLED -l vlog.log
verdi : lib
verdi -lib my_work -top tb_top_verilator -ssf tb.fsdb &
lib :
vericom -lib my_work -sv -f filelist.f
testbench_verilator:vlogan
$(VCS) -full64 -sverilog +lint=all \
-debug_all -lca \
-timescale=1ns/1ps -fsdb \
-top $(SIM_TOP_MODULE) \
-LDFLAGS "-L../remote_bitbang \
-Wl,--enable-new-dtags -Wl,-rpath,remote_bitbang -lrbs" \
-CFLAGS "-std=gnu++11 $(VERI_CFLAGS)"
./simv
remote_bitbang/librbs.so:
$(MAKE) -C ./remote_bitbang all
$(PROG):
$(MAKE) -C $(PROG_DIR)
.PHONY: clean
clean:
rm -rf $(VERI_OBJ_DIR) testbench_verilator *.log \
*.vcd simv simv.* csrc *.fsdb *.vpd *.h *.key stack.* verdiLog
$(MAKE) -C ./remote_bitbang clean
$(MAKE) -C $(PROG_DIR) clean
.PHONY: help
help:
@echo 'rebuild all:'
@echo 'make PROG=/path/file.mem recompile'
@echo 'run directly:'
@echo 'make PROG=/path/file.mem run'
@echo 'rebuild & run:'
@echo 'make PROG=/path/file.mem sim'
@echo 'clean obj files:'
@echo 'make PROG=/path/file.mem clean'
五、是骡子是马溜溜才知道:
make compile一下:
再打开一个终端;
成功了,可以看到openocd已经连上了,可以使用telnet或者gdb进行调试了。
再开一个终端,输入以下命令连接telnet(没集成到SDK确实有点麻烦):
随便调试玩一下:
可以看到我们成功通过jtag改变了这个0x10地址的值。
结束仿真并make verdi看看对应的波形:
大功告成!这样就极大方便了我们学习、设计CPU调试的过程