【一】、
在看 RISC-V 的模拟器 spike 和 riscv-pk(或简称 spike-pk)这一套东西,挺神奇的,以前有个印象,这个东西在 RTL 开发中的应用,主要就是作为参考基准,和 RTL 上的数字电路设计的仿真进行比对,以找到 RTL 可能存在的对 RISCV 指令集设计实现上的错误。这在 picorv32 里似乎找到了,因为它有使用 spike 的仿真结果和其它结果比对,典型的是在 picorv32/scripts/csmith/Makefile 中,发现了大量的使用比较的方法,其中有一个 output_ref.txt 是比较参考基准,而 spike 运行出来的 output_sim.txt 则是被比较的【怀疑对象】,iverilog/verilator 生成的也是 output_sim.txt 的被比较的【怀疑对象】。这就有点奇怪了,为什么 spike 运行出来的是被比较的怀疑对象而不是绝对正确的参考基准呢?它的 output_ref.txt 就是一个 gcc (而不是 riscv64-unknown) 所编译的 test.c 文件。如下所示:


----这个 Makefile 里,`output_ref.txt` 不是 RISC-V 指令集参考,而是 x86 主机 native 编译运行的 Csmith 随机 C 程序的输出;spike、iverilog、verilator (PicoRV32 RTL) 三者,都是被测对象,都要和 x86 主机的程序行为做比对。
----这里的参考基准不是 RISC-V ISA 模拟器 Spike,而是C 语言程序本身的语义:同一个 C 代码,不管跑在 x86 主机、Spike RISC-V 模拟器、PicoRV32 RTL 仿真,程序可观测输出必须一致。
----为什么要拿 x86 native 做参考,而不是拿 Spike 当参考?
----1. Csmith 的目的:验证**编译器 + 目标平台**对 C 标准的实现一致性。
------Csmith 生成随机 C 程序,用来发现编译器 bug、CPU/ISA 实现 bug。
------Csmith 的核心假设:同一个合法 C 源码,在符合 C 标准的不同平台上,可观测程序输出必须相同。
------参考源:x86 Linux + host gcc,成熟稳定,作为 C 语言语义真值。
------待测:riscv-gcc(把 C 编译成 RISC-V 指令)+ 运行载体(Spike 模拟器 / PicoRV32 RTL)。
----2. 和印象里「Spike 作为 ISA 参考模型,比对 RTL」的场景区分开。
----之前理解的经典芯片验证流程是:黄金参考模型(Spike) → 产生指令执行轨迹(trace);RTL 仿真导出 trace;比对两条 trace,检查每一条指令执行、寄存器 / 内存更新是否一致。在这个场景下:Spike = golden reference,RTL = DUT(被测设计)
【二】、
Csmith 是一种 CPU ISA 测试的方法学 (methodology) 吗?Spike 这种 golden reference 也是某种 ISA 测试方法学吗?比如说在更早之前就有这样的方法论论文?
----0. Csmith 本身不是 ISA 测试方法学,它是一个工具;它背后的核心方法学是【差分测试 Differential Testing】,1998 年 McKeeman 就有奠基论文;Csmith 是把这套差分测试落地到 C 编译器、后来被硬件圈拿来做 CPU/ISA 验证的工具arXiv。
----0. Spike 不是方法学,它是一个 Golden Reference Model(GRM,黄金参考模型);而 "用 ISA 功能模拟器(ISS)作为 golden,和 RTL DUT 做状态比对 / 协同仿真",这是一套成熟的处理器功能验证方法学,远早于 RISC-V 和 Spike。
----1、Csmith 工具 和它对应的验证发法学
----Csmith 是什么?Csmith 是**随机、无未定义行为 C 程序生成器**,2011 年 PLDI 论文《Finding and Understanding Bugs in C Compilers》(Yang, Regehr)正式发表,初衷**不是测 CPU,是测 C 编译器**(GCC、LLVM 等的 miscompilation 错误)。
----Csmith核心原理:生成**确定、无 UB(Undefined Behavior)**的 C 程序;同一个源码,交给多个独立编译器 / 平台执行,比对输出;输出不一致,则至少其中一个实现有错。
----Csmith这一套方法叫 **Differential Testing(差分测试)**,**不是 Csmith 发明**。
----差分测试的源头:McKeeman 1998 论文《Differential Testing for Software》,奠定差分测试方法论:**多个独立实现,喂相同输入,比对输出,用来找实现不一致 bug**。
----Csmith 是差分测试的一个**实例化工具**:专门生成合法 C 作为输入。
----2、Spike工具 和它对应的验证方法学
----Spike 是**RISC-V 指令集模拟器 ISS(Instruction Set Simulator)**,属于**Golden Reference Model(GRM)**,是**方法学里的一个组件(oracle 真值源)**,不是方法学本身。
----Spike对应的经典方法学:Golden Model / Reference Model 协同仿真比对。名称常见叫法:
-
Reference Model Verification
-
Co-simulation(协同仿真)
-
ISS vs RTL trace comparison(指令级 trace 比对)
----核心思想几十年前就存在,远远早于 RISC-V:
----建立一个**可信的高层抽象模型(golden model)**,严格按照 ISA 规范建模,只建模架构可见状态(PC、GPR、CSR、内存),不建模微架构流水线、bypass、cache 时序;
----同一个测试激励,同时跑 golden model 和 RTL DUT;**每一条指令提交后,比对架构状态**;一旦寄存器 / 内存不一致,立刻报 bug。
----这个方法在 90 年代商用 CPU 验证就大量使用(ARM、MIPS、PowerPC 都在用),不是 RISC-V 独创。
---- ARM 早年用 C 写的 ISA 参考模型;
----- MIPS 有 mips-sim;
---- RISC-V 社区把 Spike 做成开源 GRM,所以现在 RISC-V 圈子默认 Spike 作为 golden。
----3、更早的相关方法论论文时间线
----3.1. **1998:McKeeman, Differential Testing for Software** ------ 差分测试奠基论文。Csmith 只是这个思想在编译器领域的实例,后来硬件圈拿来复用。这是你 PicoRV32 csmith 脚本的底层理论源头arXiv。
----3.2. 90 年代:工业界大量使用**reference model /golden model 协同仿真**做 CPU 验证,大量 DAC/DATE 论文,没有单一 "发明者",是随 CPU RTL 验证发展出来的工程方法学;早期参考模型很多是 C 写的功能模型。
----3.3. 2011 PLDI:Yang & Regehr 《Finding and Understanding Bugs in C Compilers》 → Csmith 正式发表,目标编译器 fuzzing。
----3.4. 2010 年后 RISC-V 兴起:Spike 作为 RISC-V ISS,被社区选为开源 golden model;然后出现 riscof、riscv-dv 等验证框架,把 Spike 集成进 ISS-RTL trace 比对 flow。
【三】、
同样是在 picorv32 项目里,还有一处也是用到了 spike,但这次用法更为 "惊人",它把 spike test.elf > test.ref 所生成的 test.ref 文件作为 iverilog 的执行器 (vvp) 的一个参数,在 vvp 命令行里使用了 + ref=test.ref,这是什么神奇用法呢?如下是这个 picorv32/scripts/torture/test.sh 的脚本。

----一句话核心:`+ref=test.ref` **不是 vvp/iverilog 内置功能**,这是**testbench.v 里面自己写的 Verilog 测试代码**,用`valueplusargs`读出`ref=test.ref`这个字符串,**在 RTL 仿真运行期间,实时读取 Spike 提前生成好的 trace 文件,逐指令比对 PicoRV32 的架构状态**。
----这就是前面说的经典 ISA 验证 flow:**Spike 作为 Golden Reference,输出 trace;RTL DUT 在仿真时,每提交一条指令,就和 golden trace 做在线比对,一旦寄存器 / PC / 内存不一致,仿真立刻终止报错**。
----这和前面 `scripts/csmith` 的测试是**两套完全不同的验证范式**,刚好形成对照:
----1. **csmith**:**后处理比对**,跑完整套程序,比对最终 stdout 输出;参考源是 x86 主机 gcc;粗粒度,程序级。
----2. **riscv-torture +ref**:**仿真内在线逐指令 trace 比对**;参考源是 Spike;细粒度,ISA 架构状态级。

----这个 torture 脚本用的就是经典 **Golden Reference Model 协同仿真 / Tandem Simulation(串联仿真)**:
----同一个激励,先跑 golden 模型(Spike),预先生成 trace;再跑 RTL DUT,DUT 运行时逐条对照 golden trace。
----属于**参考模型验证方法学**,90 年代工业处理器验证就已经广泛使用。
----变种还有:**实时协同仿真(co-sim)**:Spike 和 RTL 同步跑,DUT 每提交一条指令,就调用 Spike DPI 接口当场计算参考状态,而不是预先生成离线 trace 文件。PicoRV32 这里选了离线预生成 trace 的简化版本,更轻量,不需要 DPI。

----同样是这个目录下的Makefile,采用Verilator进行验证,依靠同样的testbench.v里面的readmemh()读取hex和ref两个变量所代表的实际文件,该变量由Makefile中的参数传入,即如上的$(TESTBENCH_EXE) +hex=test_xxx.hex +ref=test_xxx.ref所传入,而test_xxx.ref正是由spike所生成的Trace。Testbench.v代码中会比较test_xxx.hex和test_xxx.ref的结果。
----两次看到了Spike作为Golden Reference Mode、用来验证RTL的test_xxx.hex是否和该GRM一致。
<<<<<<<完>>>>>>>>
关键字:Spike, Riscv-pk, Spike-pk, Golden Reference Mode, Golden Trace,Differential Testing,差分测试。Reference Model Verification,参考模型验证。Co-simulation(协同仿真),ISS vs RTL trace comparison(指令级 trace 比对)。
摘要:本文记录了PicoRV32中两个层次的差分测试案例,一个是使用Spike作为黄金基准、对RISCV RTL的运行结果进行比对测试。另一个则是以x86-gcc作为基准,对riscv-gcc compiled program running on Spike/RISCV-RTL进行测试,其中riscv-gcc compiled program on RISCV-RTL的测试又分别使用了iverilog和verilator等不同的仿真工具进行测试。充分展现了差分测试(Diff Test)和参考模型验证(Reference Model Verification)等方法。