2. verilator仿真环境说明
运行环境包括run_prog和run_random。
run_prog用于运行以下测试程序:
func:共81个功能测试点,验证处理器核设计是否与指令手册一致。
coremark/dhrystone:性能测试程序。
my_program:用户自定义裸机C程序。
linux:内核,仿真环境下可通过终端与用户交互。
run_random用于运行随机指令序列。序列中存在数量庞大,随机排列的指令,能够覆盖部分边角情况。初始化完成后,序列中的指令可连续执行,由生成器保证序列可连续执行不会中断以及提供页表项完成虚实地址映射。
仿真环境下运行程序都可通过difftest框架,实现处理器运行结果同nemu模拟器运行结果的实时比对,nemu作为金标准。能够帮助用户发现出错的第一现场,便于调试。
2.1. SoC参数配置
chip目录在未来会赋予SoC顶层代码自动生成的能力,体现敏捷开发的思想。但目前仍处于初始的状态,仅提供少数宏定义,对SoC中的部分参数进行简单调整,以适配处理器核的配置。
chip/config-generator.makAXI64: 设置为y表示SoC中AXI协议数据位宽为64btisAXI128: 设置为y表示SoC中AXI协议数据位宽为128btis,AXI64和AXI128至多配置一个y,都置为n表示AXI32,AXI协议数据位宽为32bitsCPU_2CMT: 设置为y,表示处理器核每周期可至多提交2条指令,设置为n,表示处理器核每周期提交1条指令。其他参数 : 用于指示所使用的IP模块,以及IP所处的位置。在当前SoC固定无法修改的情况下,这部分参数不需要调整。
2.2. Quick Start
以下为一个简单的仿真例程,方便用户快速上手仿真过程。在进行仿真之前,用户需安装好verilator、gtkware以及nemu。
cd $CHIPLAB_HOME/sims/verilator/run_prog #进入验证程序仿真目录中
./configure.sh --run func/func_lab19 #以仿真运行的程序func_lab19为例子生成对应的Makefile
make #开始编译。若没有编译出错,会自动进行仿真。
当需要输出波形时,需要修改Makefile_run中以下参数
DUMP_WAVEFORM=1
重新运行以下命令
make run
cd $CHIPLAB_HOME/sims/verilator/run_prog/log/func/func_lab19_log
gtkwave simu_trace.fst #查看仿真波形
上述简单仿真过程完成之后,用户可根据自己的需要,配置相应的仿真参数。对于仿真参数的说明,请参考以下章节。
2.3. LA32R-NEMU
为帮助用户在仿真环境下调试内核,我们提供了difftest环境,
使用方法请参考DIFFTEST说明。
2.4. prog环境
2.4.1. 编译参数配置
./configure.sh --help
选择运行的software以及对各项功能进行配置,--run必选,其他可选。func测试用例所测试的内容记录在software/func/*对应文件夹下的README中,该文件也对func中的一些选项进行了说明。
编译参数配置更改后需要重新执行整个编译运行流程才能生效。
--run software: 选择仿真运行的程序。目前只支持单次仿真选择一个测试程序。测试程序清单可通过./configure.sh –help查看--disable-trace-comp: 关闭使用NEMU进行的trace比对功能,默认开启--disable-simu-trace: 关闭trace log记录,适用于内核的长时间仿真,simu_trace.txt可能会占用较大的存储空间,默认开启--enable-mem-trace: 打开访存信息记录,在mem_trace.txt保存取指、数据访问load/store的地址、数据信息。--disable-read-miss: 关闭read miss警告,C++模拟的ram在核访问未初始化的内容时,会报该地址的read miss,默认关闭--disable-clk-time: 在simu_trace.txt中关闭仿真时间的打印,适用于将simu_trace.txt进行diff的场景,默认开启--output-pc-info: 在当前终端输出每条指令提交的信息,开启这一选项会拉低仿真速度,默认关闭--output-uart-info: 在当前终端输出假串口以及真串口的输出,默认关闭--output-nothing: 在当前终端不输出任何信息,默认关闭--threads: 开启多个线程进行仿真。对于规模较小的设计,开启多线程仿真并不会有仿真速度提升(甚至导致速度下降),对于规模较大的设计,开启多线程仿真会有明显的仿真速度提升,请根据实际情况选择是否使用多线程仿真--reset-val:reset信号置起时,rtl未初始化的寄存器,verilator不会呈现出x,而是会自行初始化。赋值0初始化为0;赋值1初始化为1;赋值2初始化为随机值。早期设计阶段,可以固定为某个值,而当设计比较稳定,可以设置为随机值,进行比较完备的验证--reset-random-seed: 当reset-val设为2时,该选项选择对应的随机种子--dump-vcd: 生成vcd格式的波形文件,该格式未进行任何的压缩,会占用较大的存储空间,且gtkwave打开较慢,默认关闭。不过如果因为程序卡死而不得不杀死仿真进程时,使用该选项可以保存波形,fst格式则不能保存波形。--dump-fst: 生成fst格式的波形文件,该格式会进行一定的压缩,gtkwave打开较快,但会导致仿真速度下降,默认开启--slice-waveform: 对波形文件进行切分,存储在多个文件中,用于解决波形堆积在一个文件,导致打开极慢的问题--waveform-slice-size: 波形文件切分的单位,以仿真时间衡量--slice-simu-trace: 对simu_trace.txt进行切分,同样解决trace堆积在一个文件,vim打开及文本处理都极慢的问题--trace-slice-size:simu_trace.txt切分的单位--tail-waveform: 仅保留末尾部分的波形文件,适用于运行内核时,希望保留出错位置的信息--waveform-tail-size: 波形所保留的末尾部分的大小,以仿真时间衡量--tail-simu-trace: 仅保留末尾部分的trace--trace-tail-size:trace所保留的末尾部分的大小--fork-interval: 每多长时间(ms)fork一个子进程--slot-size: 同时最多支持多少个子进程存在,多余的会被kill掉--wait-interval: 子进程每隔多长时间(seconds)检查父进程的信号
2.4.2. 运行参数配置
Makefile_run
运行参数在该文件中进行配置,参数更改后仅需重新开始仿真即可生效,即make中的最后一个流程。
DUMP_DELAY: 波形起始时间DUMP_WAVEFORM: 是否生成波形FORK_CHILD:是否允许子进程 (lightSSS)TIME_LIMIT: 仿真时间限制 (设零无限制)BUS_DELAY: 总线是否引入随机延迟BUS_DELAY_RANDOM_SEED: 总线延迟随机种子SAVE_BP_TIME: 断点保存仿真时间,断点产生后仿真仍继续进行(设零不进行断点保存)RAM_SAVE_BP_FILE: 断点保存内存信息文件TOP_SAVE_BP_FIEL: 断点保存RTL状态文件RESTORE_BP_TIME: 断点恢复仿真时间(设零不进行断点恢复)RAM_RESTORE_BP_FILE: 断点恢复内存信息文件TOP_RESTORE_BP_FIEL: 断点恢复RTL状态文件
2.4.3. 编译运行
make
即可开始仿真的整个流程,包括:
make verilator: verilator编译verilog代码make testbench: 编译testbench(C++)make soft_compile: 编译software(func)make simulation_run_prog: 开始func仿真
如若出现混乱,可以运行
make clean
清理make生成的内容,还可运行
make clean_all
清理make及configure.sh生成的内容。
目前Makefile比较简陋,对于software无法进行是否修改过的判断,仅通过是否构建出对应obj/*文件进行判断,如果仅希望重新编译software,可以运行
make clean_soft
删除对应的obj/*文件夹,然后make。注意不是删除obj目录。
2.4.4. func验证
实验过程中可以根据当前的进度,选择性的执行相应的流程。流程间存在依赖。一般来说对myCPU的rtl内容进行改动后,可以仅运行
make verilator testbench simulation_run_prog
仿真过程会生成两个比较关键的文件夹,分别是obj和log,内容包括:
objmain.elf: software elf文件test.s: 反汇编文件
logsimu_trace.txt: 仿真过程输出信息的备份mem_trace.txt: 仿真过程访存信息的备份simu_trace.fst: 仿真波形文件uart_output.txt: 假串口输出loguart_output.txt.real: 真串口输出log
以上文件都可用于调试自己的处理器核设计,波形文件可以通过gtkwave打开。
gtkwave simu_trace.fst
如果仿真过程中被ctrl-c强制结束,仅simu_trace.txt会保存在tmp目录下,波形文件、串口输出的log会丢失。为避免该情况,可估算运行时间,并配置Makefile_run中的TIME_LIMIT选项。
2.5. random环境
2.5.1. 连接DIFFTEST相关信号
为帮助用户在仿真环境下调试处理器,我们提供了’difftest’环境.
使用方法请参考DIFFTEST使用说明,完成DIFFTEST相关信号的适配。
若不进行适配,请关闭DIFFTEST比对功能后,再进行随机指令序列测试。修改$(CHIPLAB_HOME)/sims/verilator/run_random/config-random.mak
TRACE_COMP=n
2.5.2. 准备测试用例
下载相关随机res文件压缩包,下载地址 提取码:sHJS 。
random_res_*.tar.bz2其中的数字表示拥有几组随机指令序列,一组随机指令序列拥有30万条指令
压缩包中的随机指令序列包括RES_cluster_*和RES_jump_*表示不同的生成倾向。jump类倾向于同一类指令重复,而cluster类为多类型指令混合。
解压后将random_res_*内的文件夹RES_cluster_*或者RES_jump_*拷贝至$(CHIPLAB_HOME)/software/random_res/下。
该文件夹由用户自行创建,对于random_res下的所有文件,run_random都会对其进行处理,因此建议放入适量的随机指令序列,同时该目录下不可放置其他无关内容。
2.5.3. 编译参数配置
config-random.mak
部分选项与run_prog环境下./configure.sh中的选项具有相同的含义,不同的内容有
CACHE_SEED: 为对cache进行完备的测试,随机环境下,tlb的存储访问类型(MAT)也进行随机的配置,该选项配置随机种子。LA32:y配置为32位架构,n配置为64位架构。
2.5.4. 运行参数配置
Makefile_run
DUMP_DELAY: 波形起始时间DUMP_WAVEFORM: 是否生成波形TIME_LIMIT: 仿真时间限制 (设零无限制)
2.5.5. 编译运行
make
即可开始随机验证,运行software/random_res目录下所存的所有随机指令序列。
所有随机序列测试成功或失败的信息存放在sims/verilator/run_random/log/*-result.txt中
每个随机序列具体的测试信息存放在$(CHIPLAB_HOME)/sims/verilator/run_random/log/$(TESTCASE)下.
run.log: 当前case执行随机的输出结果.simu_trace.fst: 当前case所生成波形 以上文件都可用于调试自己的处理器核设计,波形文件可以通过gtkwave打开。
gtkwave simu_trace.fst
2.5.5.1. 单个随机指令序列运行方法
若需要跑具体某个随机测试用例,进入$(CHIPLAB_HOME)/sims/verilator/run_random/run_random/,执行:
make simulation_run_random -C $(TESTCASE) -f ../../Makefile_run CASENAME=$(TESTCASE)
或执行:
make ../../../../software/random_res/$(TESTCASE)
若此前没有执行过make random,请在$(CHIPLAB_HOME)/sims/verilator/run_random/run_random/$(TESTCASE)/下先执行:
make prepare
所有随机指令序列的测试结果记录在log/result.txt中。
debug时请参考$(TESTCASE)/comments.res以及$(TESTCASE)/logs/run.log。
2.5.6. 随机验证调试帮助
随机启动代码位于software/random_boot的rand_boot.S中。对处理器状态进行初始化,eret指令之后开始执行随机指令序列,并且开始比对。
随机指令序列仅允许触发tlb refill例外,tlb refill例外的处理程序位于rand_boot.S中。当触发tlb refill例外时,由testbench获取出错虚地址,并查询随机指令序列中提供的页表项,填写到固定地址,再由例外处理程序填充到处理器核的tlb中。
随机指令序列使用大小页。
随机测试用例文件夹中存有*.res文件,用于构成随机验证环境。同时,随机指令序列也给出了正确的执行路径以及执行结果。当运行出错时,一方面可以同作为金标准的nemu进行对比分析,另一方面也可以从*.res文件获取正确的运行结果并进行分析。以下对较为关键的*.res文件进行介绍。
comment.res: 随机指令序列中的汇编指令。instruction.res/address.res/pc.res/result_type.res/value1.res五个文件每行与该文件每行的指令对应。instruction.res: 随机指令的二进制。address.res: 随机指令修改的通用寄存器号。value1.res: 随机指令修改的通用寄存器的值。pc.res: 随机指令的虚地址。result_type.res: 为1表示随机指令修改通用寄存器,为0则表示不修改。page.res: 页表项的虚地址。pfn.res: 页表项的物理地址。cca.res: 页表项的存储访问类型。page_size.res: 页表项的页大小。page.res/pfn.res/cca.res/page_size.res四个文件每行描述一个页表项,当处理器核在处理tlb出错时,可查询四个文件观察页表填充是否正确。init.res.res: 通用寄存器初始值。
查看波形时,可观察顶层simu_top.v的几个ram*信号,判断AXI总线发出的请求及传输的数据是否正确。
2.6. 对于提高仿真速度的Tips
推荐使用较新的
verilator版本,建议v4.224及以上。关注
verilator编译时给出的WARNING中是否有UNOPT,UNOPTFLAT等字样,如有,应当尽量解决之。如果你的设计复杂度明显比
chiplab仓库中自带的DEMO CPU更高,请尝试使用多线程仿真。建议关闭
output-pc-info这一编译选项。不必要记录波形的时候建议不要开启
DUMP_WAVEFORM,记录波形会带来明显的仿真速度下降。verilator仿真非常依赖主机处理器前端的性能,因此,考虑压缩设计代码大小或使用前端性能更强的处理器来运行仿真会有帮助。