-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
【分享】接入difftest的几个主要步骤 #8
Comments
👍👍👍期待继续更新! |
补充一个编译
解决: sudo apt-get install libsdl2-dev 建议此时安装以下包: sudo apt-get install build-essential libreadline-dev libsdl2-dev libc6-dev-i386 qemu-system 如果运行
那么多半是没有编译好 make -C $NEMU_HOME ISA=riscv64 SHARE=1 ENGINE=interpreter 另外小声 bb 一下,我的 difftest 没有放在根目录下,并且也不是用的 |
@YouTheFreedom1999 看上去像是系统无法 mmap 8GB 的地址空间。你的电脑是 64 位的吗,理论上地址空间应该足够才对。 至于解决的话,可以试试看把申请的空间改小一点。对于这次项目来讲应该 256MB 也足够了。 |
@YouTheFreedom1999 我也遇到了这个问题,我的解决方案是给Linux的swap分配更多的空间,原先是2G,给到了10G,就可以了 |
感谢,我根据这个链接https://www.cnblogs.com/tocy/p/linux-swap-cmd-summary.html增加了swap之后,difftest可以跑起来了 |
你好,请问你知道如果用sbt作为构建工具的话,应该怎么修改build.sbt吗 |
我昨天改完swap大小之后,今天发现虚拟机打不开了。。。ubuntu的logo过后,就一直卡在黑屏界面,左上角一个光标在闪烁,这可怎么办。。。 |
指令提交连线正确但是无法提交这两天有空就在弄 Difftest,跟着两位的步骤走,自认为连线正确但是就是无法出现 参考 Difftest 的源码: |
你好!我用了上面的方法,但是报了一个分配物理内存的错误,这个是改成256M出现的吗?
|
NEMU的内存也要改成256MB |
确实是这样,我把NEMU/include/memory/paddr.h中的
8 * 1024 改成了256,重新编译NEMU和emu就可以运行了。 |
我来分享一下使用sbt接入difftest的方法。
主要修改的部分为为root添加源码依赖路径~ |
请问使用difftest框架之后,可以查看仿真波形吗?怎么查看呢? |
NEMU 编译的时候需要但不限于以下几个库,如果是wsl Ubuntu20.04。按以下命令安排即可: sudo apt install bison libncursesw5-dev libreadline-dev |
我把PC地址从0改回800000000之后,报错:
请问老哥知道这个怎么解决吗,谢谢 |
这个看样子是地址超出了边界。你得看看你 pc 输入到 ramhelper 的地址有没有按照 demo 那样减去 pc start 再处理。 |
|
请问用什么命令编译所有的cpu_test的程序? |
应该只能一个一个编译吧。可以用下面的命令编译($FILENAME是cpu_test的文件名,例如add)。
|
多谢多谢,已经找到了。直接运行make ARCH=riscv64-mycpu 就是编译所有的! |
写在前面
我个人使用
chisel
编写项目,并且使用mill
作为构建工具。使用
verilog
编写或者使用sbt
构建工具大同小异。如果在操作过程有出现本文章未提及的问题,欢迎在讨论区提出。你提出的问题很可能能帮助到别人。
下载
difftest
项目和所需依赖主要为
difftest
项目 和NEMU
模拟器。其中,
difftest
项目必须在chisel
项目根目录下,NEMU
项目不限制位置,但是必须设置NEMU_HOME
环境变量为NEMU
所在目录。此外,还需要设置
NOOP_HOME
为项目根目录(参考verilog.mk
,虽然不会使用这个功能,但是这个变量必须要有)。我个人的项目树大致如下,不要求完全一致,符合上述要求即可。
因此
NEMU_HOME
环境变量应该设置为/home/xxx/NEMU
,NOOP_HOME
环境变量应该设置为/home/xxx/chisel-template
。(正式开始前建议执行
git commit -am --allow-empty "before difftest"
保证接入失败后可以随时回退回原来的状态)构建
SimTop.v
由于
difftest
框架本身由verilog
写成,仅使用chisel
编写的项目需要此步骤。使用verilog
编写的项目可以直接跳过此步骤,但是必须保证build/SimTop.v
是 CPU 的顶级文件且具有 规定的端口。我的
SimTop.v
实现如下:由于需要使用
difftest
模块下的文件,需要指示mill
difftest
模块的位置。修改build.sc
如下(sbt
需修改build.sbt
,两个文件不通用)此时,
mill
可以执行以下命令生成build/SimTop.v
其中,
top.TopMain
是本chisel
项目的顶层文件,形如而
SimTop
是编写的CPU
模块。运行上述命令后,期望能找到
build/SimTop.v
。构建
difftest
程序build/emu
在项目根目录中执行以下命令即可构建
build/emu
在准备好上述文件后,理论上就算不做任何修改,在没有接入
difftest
的情况下期望能生成build/emu
文件(可能会有大量输出,成功与否以build/emu
文件是否存在为准)。如果无法生成,请检查是否做好上述准备,如是否已配置正确的NEMU_HOME
环境变量、build/SimTop.v
是否是 CPU 模块的顶层文件等。此时,运行
build/emu --help
应该能够看到帮助文档。准备镜像文件
任意镜像文件均可,可以使用
AbstractMachine
编译cpu-test
作为镜像(需要实现几乎全部rv64i
指令才能正常运行),也可以自己编写并生成stripped
的纯二进制文件。该文件会作为difftest
过程中执行的程序。也可以使用框架里的 inst.bin 替代。
以下使用
$IMG
代指该镜像文件。此时执行
build/emu -i $IMG
,期望看到以下输出。在前几行输出可以看出,由于我们还没有接入
difftest
,框架无法获取我们 CPU 的执行状态。因此接下来需要修改CPU
模块来接入difftest
框架。接入RAM
我们的 CPU 需要获取执行的指令以及运行
load/store
指令。原先这些数据由verilator
中的测试框架给出,现在需要将其转接到difftest
框架中。difftest
框架通过RAMHelper
向 CPU 提供读写信息。其定义在ram.v
中。我们需要做的就是在 CPU 中实例化这个RAMHelper
模块并且按照其定义连接对应信号。需要注意的是,
RAMHelper
读写都仅以 8字节 为一个单位,也即,当rIdx
为1
时,实际读取了0x80000008
开始的八个字节。写入同理。正确接入后,期望在 CPU 运行过程中可以正确读取对应地址的信息。正确性可以通过在代码中打印日志人工判断。
我个人在
SimTop.v
中的实现如下:接入“指令提交”
我们需要通过一个方式告诉
difftest
框架已经完成了某条指令的执行。该功能通过 DifftestInstrCommit 实现。verilog
中对应的模块是difftest.v
。具体而言,需要在写回阶段,实例化
DifftestInstrCommit
并且连接对应的信号。我个人的实现大概如下:
其中,我没有使用 RegNext 的信号是暂时不需要管的,和我一致即可。其余使用了 RegNext 的信号需要替换成你们对应的实现。(端口含义通过命名可以猜出来很多了)
此时,执行
mill -i __.test.runMain top.TopMain -td ./build
、make -C difftest emu
和build/emu -i $IMG
,期望difftest
能够正确识别出第一条指令的执行。但是由于其余数据我们还未提供给difftest
框架,所以极可能第一条指令就会被判错,这是正常现象。该阶段正确性的判定可以通过是否输出了
The first instruction of core 0 has commited. Difftest enabled.
判断。我个人在该阶段的输出如下:
从错误信息中,可以看到期望的
Difftest enabled
,说明InstrCommit
正确接入了。并且可以看到在==Commit Instr Trace==
中我的CPU正确提交了第一条指令,但是由于ra
寄存器的错误终止了difftest
。这个问题在下个阶段会修复。接入寄存器组
difftest
框架主要比对我们 CPU 的寄存器值和 NEMU 模拟器的寄存器值来判定实现的正确性。该功能通过DifftestArchIntRegState
实现。verilog
也有对应的模块。具体而言,需要在 寄存器组 模块中,实例化
DifftestArchIntRegState
并连接对应的信号。我个人的实现大概如下:
此外,
difftest
在运行时还会对比CSR
寄存器的值。由于我们此时并未实现,直接硬编码即可。(但是不能留空,否则会出现非合法值导致NEMU
异常)此时,再次执行
mill -i __.test.runMain top.TopMain -td ./build
、make -C difftest emu
和build/emu -i $IMG
,此时期望能够正确执行difftest
了。(此时的表现为difftest
没有任何输出)但是由于我们还未实现
Trap
通知difftest
框架我们的程序已经终止,difftest
将会一直执行下去。(因为在AM
中halt
的实现暂时是一个死循环)关于 Trap
在
NJU-ProjectN
中告知框架 “程序已运行结束” 的方式是发送一个Trap
事件。在difftest
框架中也是如此。在没有修改的情况下,如果使用NEMU
运行AM
编译的程序,会出现程序运行结束之后仍然无法退出的情况。该行为在trap.c
中定义。$NEMU_HOME/build/riscv64-nemu-interpreter -b am-kernels/tests/cpu-tests/build/add-riscv64-mycpu.bin
可以看到,无论等待多久,
NEMU
的运行都不会停止。要修改这个行为,让程序能够自动退出,只需要在
trap.c
的halt
前加入一条特殊的指令即可。asm
语句在halt
函数中添加了一条特殊指令0x0000006b
。该指令在NEMU
中的行为是终止执行,并将a0
寄存器的值作为程序是否正常退出的标志。a0
为 0 时表示时正常终止,否则代表异常终止。该行为定义在exec/special.c
中。此时重新编译
cpu-test
(可以使用make clean
再make ARCH=riscv64-mycpu
),并且再次使用NEMU
运行该测试,可以发现NEMU
可以正常终止,并输出HIT GOOD TRAP
。接入 Trap
接入
difftest
的Trap
的流程与之前类似,只需要实例化对应的接口并连接信号即可。对应本次是DifftestTrapEvent
模块。暂时不需要区分
GoodTrap
和BadTrap
,因此大部分内容都可以硬编码完成。此外,只需要保证你的CPU
在识别到0x0000006b
这个非标准的指令的时候不会出现异常行为即可。我的实现如下:
此时再次执行
difftest
相关流程,可以看到difftest
也最终输出了Hit Good Trap
指示程序正确结束了。最后,附带一个能够一件测试
cpu-test
中所有指令的命令:如果一次性输出太多,可以考虑重定向到某个文件中然后查找
ABORT
关键词查看错误的样例。The text was updated successfully, but these errors were encountered: