Difftest踩坑笔记(二)
如何搭建自己的Difftest框架呢?一生一芯仓库的wiki给了优秀的回答,但要全搭起来还是不容易,同样是两个原因:不够保姆、版本。
1. 初始化仓库
首先clone一生一芯官网的初始化仓库。
git clone -b ysyx2204 git@github.com:OSCPU/ysyx-workbench.git
cd ysyx-workbench
# 初始化chisel环境
bash init.sh npc-chisel
2. Difftest文件夹
NutShell@3a8832e下的difftest拷贝到npc目录下,和playground同级。同时需要修改npc/build.sc文件,才能调用difftest中的clas,但需要修改difftest的版本至3.5.0-RC1,不然会报错。 参考以下三个Issue:issue8,issue9,issue10
// import Mill dependency
import mill._
import mill.scalalib._
import mill.scalalib.scalafmt.ScalafmtModule
import mill.scalalib.TestModule.Utest
// support BSP
import mill.bsp._
object playground extends ScalaModule with ScalafmtModule { m =>
override def scalaVersion = "2.12.13"
override def scalacOptions = Seq(
"-Xsource:2.11",
"-language:reflectiveCalls",
"-deprecation",
"-feature",
"-Xcheckinit",
// Enables autoclonetype2 in 3.4.x (on by default in 3.5)
"-P:chiselplugin:useBundlePlugin"
)
override def ivyDeps = Agg(
ivy"edu.berkeley.cs::chisel3:3.5.0-RC1",
)
override def scalacPluginIvyDeps = Agg(
ivy"edu.berkeley.cs:::chisel3-plugin:3.4.3",
ivy"org.scalamacros:::paradise:2.1.1"
)
object test extends Tests with Utest {
override def ivyDeps = m.ivyDeps() ++ Agg(
ivy"com.lihaoyi::utest:0.7.10",
ivy"edu.berkeley.cs::chiseltest:0.3.3",
)
}
override def moduleDeps = super.moduleDeps ++ Seq(difftest)
}
object difftest extends ScalaModule {
override def scalaVersion = "2.12.13"
override def millSourcePath = os.pwd / "difftest"
override def ivyDeps = Agg(
ivy"edu.berkeley.cs::chisel3:3.5.0-RC1"
)
}
3.单周期CPU
CPU的chisel模板参考oscpu-chisel-framework,需要做两方面改动:
- 添加二读一写端口的ram1w2r.v:difftest/src/test/vsrc/common/ram1w2r.v。因为单周期一般区分imem和dmem。
- 修改difftest的接入时序,这点比较繁琐,也花了很长时间debug。
时序主要修改了两个文件:InstFetch.scala
和 Core.scala
-
InstFetch.scala
添加pc_valid信号,告诉difftest这是一个有效提交指令,然后Nemu运行一条指令,再对比各自的寄存器。如果没这样做,第一条提交的指令会出错。 -
Core.scala
添加RegNext做延时,这是调节时序的。寄存器的更新在指令的下一拍,传给difftest的pc需要和寄存器的更新同步。这样difftest接受指令提交后,Nemu运行一条指令,然后比对各自的寄存器。
4. 测试BIN文件
测试BIN文件在这个仓库可以找到,感觉是之前一生一芯的开源仓库,不知为什么原官方仓库不见了。
BIN文件生成的时候需要加编译选项-march=rv64g -mabi=lp64d
,否则默认会编译出压缩指令,运行时会报错(暂时没有实现压缩指令解码器)。
最后 npc目录下的Makefile 生成emu时,需要加上EMU_CXX_EXTRA_FLAGS="-DFIRST_INST_ADDRESS=0x80000000"
,告诉nemu在0x80000000的位置开始取值。
5. 小结
本想专心写硬件,没想到花了那么多时间大环境,print大法排查了很久,附上调试好的仓库,希望jyy老师不会打我。系统环境是Ubuntu20.04的虚拟机。如果用wsl,有可能需要改动一些地方。
git clone https://gitee.com/he_zhifan/ysyx-workbench.git
cd ysyx-workbench
git submodule update --init --recursive
bash install_tools.sh
git checkout v0.5
cd nemu
make riscv64-xs-ref_defconfig
make
cd ../npc
make sim
默认仿真addi-riscv-tests.bin文件
,会停在0x8000050的位置,因为lui
指令还没实现。li
,mov
是addi
的伪指令,bne
虽然没实现,但默认下条指令是pc+4,也能通过。
附
附上difftest的函数跳转图
入口函数:difftest/src/test/csrc/verilator/main.cpp
main.cpp
|-构造emu
|-调用构造函数:reset 10 cycles,init_ram,init_flash
|-调用emu->execute
|-init_difftest
*****while*****
single_cycle运行dut
difftest_step()运行nemu emu.cpp :426(difftest.cpp:88)
|-do_first_instr_commit() difftest.cpp :103(354)
do_instr_commit() difftest.cpp :148(222)
*compare regs difftest.cpp :178
|-打印对比信息 difftest.cpp :180
state->dispaly:打印Commit Group difftest.cpp:614
Difftes display: Instr Trace, REF Regs difftest.cpp:608
display_trapinfo打印trap位置,和指令统计结果
|-打印错误的寄存器
****end while***
display_trapinfo() emu.cpp:495(569)
打印verilog里面的日志信息
写的很好,感谢分享