一、前言
这篇文章梳理了xs-env(https://github.com/OpenXiangShan/xs-env)代码工程下,几个和香山开发相关的四个子模块(submodule)工程之间的使用关系:nexus-am、NEMU、XiangShan、Nutshell。
二、子模块工程简介
NEMU:NJU Emulator,来自南京大学的是一个简单但完整的全系统模拟器, 目前支持x86, mips32, riscv32, riscv64指令集。我们只用它来生成 riscv64 相关的两个文件:模拟器和运行库。
Nutshell:果壳项目,是一个入门级别的CPU设计工程。
XiangShan:香山项目,是一个非常复杂的CPU设计工程。
nexus-am:Abstract Machine,抽象层函数库,用于从C应用层代码到指令集的抽象。即向上提供 printf() 这类标准C库函数,向下根据选择的微架构、平台来提供一些标准函数的实现,比如 _halt()、_putc() 。
我准备从Nutshell项目先入手,弄懂微架构设计和开发工作流以后再学习XiangShan项目。
三、子模块工程关系:
步骤说明:
- 编译workload版本 :AM工程里默认至少有三个workload代码(CoreMark、MicroBench、Linux),编译时需要指定生成的目标指令集和平台。指令集我们总是选择 riscv64 ,平台根据需要一般限定为 nemu和noop 。
- 编译NEMU模拟器(riscv64指令集版) :用于验证workload版本的正确性——如果第一步生成的目标指令集为riscv64、目标平台为nemu的workload都不能在riscv64指令集版的NEMU正常跑完,则说明代码有问题,不能用来编译目标平台为Nutshell或XiangShan仿真核的workload版本。
- 编译NEMU动态库(riscv64指令集版) :用于差分测试流程中验证Nutshell或XiangShan仿真核执行workload版本的正确性——NEMU动态库相当于是 没有main()函数 的可执行文件,只能被动输入riscv64指令、输出执行结果(然后被difftest利用来与仿真核的结果做对比)。
- 编译XiangShan仿真核 :文件名为emu,可支持选择编译为标准版,或最小配置版。
- 编译Nutshell仿真核 :文件名为emu(上图中没有对Nutshell仿真核的差分测试进行讲解,但实际与XiangShan使用方法的一样)。
- NEMU运行workload :单独在NEMU模拟器(riscv64指令集版)上跑workload,以验证workload版本的正确性。(此时NEMU模拟器是确定正常的、而workload版本未知。)
- XiangShan运行workload :单独在XiangShan仿真核上跑workload,以验证XiangShan仿真核的正确性。(此时workload版本确定是正常的、而XiangShan核未知)。
- XiangShan核与NEMU同时运行workload :同时在XiangShan核与NEMU模拟器(riscv64指令集版)上跑workload,以验证XiangShan核的执行结果与顺序都是正常的(可能用于测试性能时需要?或调试阶段抓出第一个行为不一致的指令。)
四、疑问与解答:
- 第6步中认为NEMU模拟器是确定正常的,为什么能这么保证呢?
因为NEMU也经过差分测试与调试才拿来用的,而对比的对象为更标准的QEMU模拟器。其实第8步中可以使用QEMU模拟器来与仿真核做差分测试,但在效率方面远比不上NEMU,所以会使用NEMU来代替作为实际使用的指令模拟器。
Nutshell调试指南里有对此进行解释:https://oscpu.gitbook.io/nutshell/qi-ta/debug#cha-fen-ce-shi-kuang-jia - 如果Nutshell或XiangShan核跑AM编译给对方的workload版本,会发生什么?比如Nutshell跑
microbench-riscv64-noop.bin
或XiangShan跑microbench-riscv64-nutshell.bin
。
正常情况下不应该这样做;如果一定要尝试下,结果就是会挂死在某个位置。