从零开始学RISC-V之指令集仿真
背景介绍
一个十分常见的情形是,我们需要确定CPU能正确执行我们的程序,例如对跳转之类的处理,这在应用程序中十分常见。或许可以在程序中增加自测试代码,但这无疑增加代码量并且属于无实际意义的代码量,并且由于不能实现指令级的检查,所以并不具备应用价值。因此需要一种标准的仿真器,这种仿真器独立于处理器微架构,用于模拟处理器在执行目标应用程序时的各种状态,包括执行结果,程序流以及CSR。如果当前设计的处理器在执行指定程序时,这三个指标与标准的仿真程序所呈现的结果不一致,则认为处理器设计存在问题,需要修正。对于RISCV处理器设计来讲,最常见的仿真工具是Spike。在github上有相应资源。关于Spike及其相关的工具链,大家可以自行查阅其他资料。本文的第一部分将着重介绍如何安装Spike仿真工具。
本文的第二部分将介绍一个常见的嵌入式测试应用程序Dhrystone(江湖戏称“干石头”,当然与之对应的还有“湿石头”,大家可以自行了解)。Dhrystone是于1984年由Reinhold P. Weicker设计的一套综合的基准程序,该程序用来测试处理器的整数计算性能。该程序用C语言编写,依赖编译器的编译设置。Dhrystone的计量单位为每秒计算多少次Dhrystone,或者称为Dhrystone MIPS(百万条指令每秒),此处有一个其他处理器跑分结果。本文选用该测试程序作为应用程序演示示例,并不能输出完整的处理器性能数据。不过不排除在后期对处理器完善之后实现该目标。
安装Spike工具链
以下涉及到的安装步骤都源自两个工具链的README文件(所以README是个好东西),经作者实践后所总结。
安装riscv-fesvr
-
下载riscv-fesvr
git clone --recursive https://github.com/riscv/riscv-tools.git
-
设置RISCV环境变量
RISCV=${HOME}/Software/rv_linux_bare_19-10-17-11-10/bin #riscv工具链的路径
-
安装可能会有用的工具
yum install autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev libusb-1.0-0-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev device-tree-compiler pkg-config libexpat-dev #注意:这些工具并不要求都安装成功,视后续需求。此处为保险措施
-
创建build文件夹
在riscv-fesvr文件夹下创建新的build文件夹,用于生成编译
mkdir build cd build
-
配置并生成代码
../configure --prefix=$RISCV
-
安装
make install
此时会看到大片的编译过程,如果没有报错,则安装成功,可以进入下一步,否则就要排错并重新安装。riscv-fesvr
工具是安装spike
所必需的工具。
安装Spike
-
下载riscv-isa-sim
git clone --recursive https://github.com/riscv/riscv-tools.git
-
创建build文件夹
在riscv-isa-sim文件夹下创建新的build文件夹,用于生成编译
mkdir build cd build
-
配置并生成代码
../configure --prefix=$RISCV --with-fesvr=$RISCV
-
安装
make install
-
设置环境变量
将生成的Spike工具添加到环境变量中,后续方便使用
export spike='your_spike_path'
如果没有报错,则安装成功,否则就要排错并重新安装。
编译Dhrystone
Dhrystone
含有部分内建函数,需要与编译器匹配。为保证主线任务,此处直接采用开源蜂鸟版本的Dhrystone
版本。将下载到的工程文件放到xf100/verify/riscv-tools/riscv-tests/benchmarks/
路径下备用。并修改benchmarks/Makefile
脚本文件:
- 修改
RISCV_PREFIX
,使其指向正确的riscv-gcc
工具地址。 - 修改
RISCV_GCC_OPTS
,将-march=rv32imafdc
改为-march=rv32im
,将-mabi=ilp32f
改为-mabi=ilp32
- 改成这样的原因,是目前的xf100处理器,还不支持某些特性,例如原子指令(A),浮点指令(F/D)以及精简指令(C),因此需要告诉编译器,不要产生相关类型的指令。
完成上述修改后,直接在benchmarks/
路径下运行make
指令,即可看到编译后的benchmark代码。
Dhrystone的spike仿真
在任意终端界面下,运行spike
即可看到与之相关的参数介绍。运行以下命令来进行Dhrystone
的软仿真。
spike --isa=RV32IM -l dhrystone.riscv
该命令的含义是:用spike工具,在指定指令集下运行dhrystone程序,并将运行的pc流打印出来。运行结果如下图:
从上图可以看出当一个功能正常的处理器在执行当前的程序时其PC的值,如果某个处理器在同样条件下运行同一套程序,但是有不同的PC值,这表明该处理器无法可信的执行任何一个程序,即当前设计的处理器功能有问题,需要进一步修改。如果将该仿真工具和UVM
等验证平台结合起来,实时监测处理器运行时的各个状态信息,就是处理器验证工作的核心。
总结
从第一篇文章到现在,我们终于介绍完一个极简的处理器的设计过程。虽然它还不完善,没有什么实用性,但是通过此例,我们还是涉及到了以下几个关键部分:
- 极简的处理器,还是包含了取指(IFU),译码(DEC),执行(EXU),访存(LSU)以及写回(WB)五个部分,麻雀虽小,五脏俱全。
- 处理器不涉及流水线的设计,但这并不妨碍它能正常执行若干条指令。实际上,余下的指令都是可以实现的,只是性能和时序会受到诸多限制,但是功能一定是完备的。这也说明一点,流水线在处理器设计中并不是必需的。
- 处理器虽然没有复杂的分支跳转预测与数据反馈机制,但是简单的流水线冲刷机制还是有的,并且依旧满足设计需求。
- 截至目前有一个相对完整的处理器验证环境,这是以后复杂处理器设计的基础工作。
的。这也说明一点,流水线在处理器设计中并不是必需的。
- 处理器虽然没有复杂的分支跳转预测与数据反馈机制,但是简单的流水线冲刷机制还是有的,并且依旧满足设计需求。
- 截至目前有一个相对完整的处理器验证环境,这是以后复杂处理器设计的基础工作。
有了上述的基本框架,要设计一个能完整执行上述Dhrystone
应用程序的处理器只是时间问题。后续文章将重点介绍余下工作中的难点部分,敬请期待。
同系列文章首发于微信公众号:ICLiker,愿逢有缘人