riscv-software-src/riscv-isa-sim
GitHub: riscv-software-src/riscv-isa-sim
Spike 是 RISC-V 官方指令集参考模拟器,为软件开发、硬件验证和架构研究提供功能精确的多 hart 仿真环境。
Stars: 3051 | Forks: 1045
# Spike RISC-V ISA 模拟器
## 关于
Spike,即 RISC-V ISA 模拟器,实现了一个或多个 RISC-V hart 的功能模型。它的名字来源于用来庆祝美国横贯大陆铁路完工的金道钉(golden spike)。
Spike 支持以下 RISC-V ISA 特性:
- RV32I 和 RV64I 基础 ISA,v2.1
- RV32E 和 RV64E 基础 ISA,v1.9
- Zifencei 扩展,v2.0
- Zicsr 扩展,v2.0
- Zicntr 扩展,v2.0
- M 扩展,v2.0
- A 扩展,v2.1
- B 扩展,v1.0
- F 扩展,v2.2
- D 扩展,v2.2
- Q 扩展,v2.2
- C 扩展,v2.0
- Zbkb、Zbkc、Zbkx、Zknd、Zkne、Zknh、Zksed、Zksh 标量密码学扩展(Zk、Zkn 和 Zks 组),v1.0
- Zkr 虚拟熵源模拟,v1.0
- V 扩展,v1.0(_需要 64 位主机_)
- P 扩展,v0.9.2
- Zba 扩展,v1.0
- Zbb 扩展,v1.0
- Zbc 扩展,v1.0
- Zbs 扩展,v1.0
- Zfh 和 Zfhmin 半精度浮点扩展,v1.0
- Zfa 扩展,v1.0
- Zfinx 扩展,v1.0
- Zmmul 整数乘法扩展,v1.0
- Zicbom、Zicbop、Zicboz 缓存块维护扩展,v1.0
- 同时符合 RVWMO 和 RVTSO 规范(Spike 是顺序一致的)
- 机器(Machine)、监督者(Supervisor)和用户(User)模式,v1.11
- Hypervisor 扩展,v1.0
- Svnapot 扩展,v1.0
- Svpbmt 扩展,v1.0
- Svinval 扩展,v1.0
- Svadu 扩展,v1.0
- Svade 扩展,v1.0
- Sdext 扩展,v1.0-STABLE
- Sdtrig 扩展,v1.0-STABLE
- Smepmp 扩展 v1.0
- Smstateen 扩展,v1.0
- Smdbltrp 扩展,v1.0
- Sscofpmf v0.5.2
- Ssdbltrp 扩展,v1.0
- Ssqosid 扩展,v1.0
- Zaamo 扩展,v1.0
- Zalrsc 扩展,v1.0
- Zabha 扩展,v1.0
- Zacas 扩展,v1.0
- Zawrs 扩展,v1.0
- Zicfiss 扩展,v1.0
- Zicfilp 扩展,v1.0
- Zca 扩展,v1.0
- Zcb 扩展,v1.0
- Zcf 扩展,v1.0
- Zcd 扩展,v1.0
- Zcmp 扩展,v1.0
- Zcmt 扩展,v1.0
- Zfbfmin 扩展,v0.6
- Zvfbfmin 扩展,v0.6
- Zvfbfwma 扩展,v0.6
- Zvabd 扩展,v0.7
- Zvbb 扩展,v1.0
- Zvbc 扩展,v1.0
- Zvkg 扩展,v1.0
- Zvkned 扩展,v1.0
- Zvknha、Zvknhb 扩展,v1.0
- Zvksed 扩展,v1.0
- Zvksh 扩展,v1.0
- Zvkt 扩展,v1.0
- Zvkn、Zvknc、Zvkng 扩展,v1.0
- Zvks、Zvksc、Zvksg 扩展,v1.0
- Zvzip 扩展,v0.1
- Zicond 扩展,v1.0
- Zilsd 扩展,v1.0
- Zclsd 扩展,v1.0
- Zimop 扩展,v1.0
## 版本控制与 API
项目版本控制主要用于指示 API 何时被扩展或变得不兼容。本着这种精神,Spike 旨在遵循 [SemVer](https://semver.org/spec/v2.0.0.html) 版本控制方案,即:当发生向后不兼容的 API 更改时,递增主版本号;当添加新的 API 时,递增次版本号;当以向后兼容的方式修复错误时,递增修订版本号。
Spike 的主要公共 API 是 RISC-V ISA。_Spike 内部的 C++ 接口目前**不**被视为公共 API_,并且对这一接口进行向后不兼容的更改时,_将_不会递增主版本号。
## 构建步骤
我们假设已将 RISCV 环境变量设置为 RISC-V 工具的安装路径。
```
$ apt-get install device-tree-compiler libboost-regex-dev libboost-system-dev
$ mkdir build
$ cd build
$ ../configure --prefix=$RISCV
$ make
$ [sudo] make install
```
如果你的系统使用 `yum` 包管理器,可以将第一步替换为 `yum install dtc`。
## 在 OpenBSD 上构建
安装 bash、gmake、dtc,并使用 clang。
```
$ pkg_add bash gmake dtc
$ exec bash
$ export CC=cc; export CXX=c++
$ mkdir build
$ cd build
$ ../configure --prefix=$RISCV
$ gmake
$ [doas] make install
```
## 编译并运行一个简单的 C 程序
安装 spike(见构建步骤)、riscv-gnu-toolchain 和 riscv-pk。
编写一个简短的 C 程序并将其命名为 hello.c。然后,将其编译为名为 hello 的 RISC-V ELF 二进制文件:
```
$ riscv64-unknown-elf-gcc -o hello hello.c
```
现在,你可以在代理内核上模拟该程序:
```
$ spike pk hello
```
## 模拟新指令
向模拟器添加一条指令需要两个步骤:
1. 在 riscv/insns/.h 文件中描述指令的功能行为。可以查看该目录下的其他指令作为起点。
2. 将操作码和操作码掩码添加到 riscv/opcodes.h 中。或者,将其添加到 riscv-opcodes 包中,它会自动为你完成此操作:
$ cd ../riscv-opcodes
$ vi opcodes // 为新指令添加一行
$ make install
3. 将指令添加到 riscv/riscv.mk.in 中。否则,该指令将不会包含在构建中,并被视为非法指令。
4. 重新构建模拟器。
## 交互式调试模式
要调用交互式调试模式,请使用 -d 参数启动 spike:
```
$ spike -d pk hello
```
要查看整数寄存器的内容(0 代表核心 0):
```
: reg 0 a0
```
要查看浮点寄存器的内容:
```
: fregs 0 ft0
```
或者:
```
: fregd 0 ft0
```
具体取决于你希望将寄存器打印为单精度还是双精度。
要查看某个内存位置的内容(十六进制的物理地址):
```
: mem 2020
```
要查看虚拟地址的内存内容(0 代表核心 0):
```
: mem 0 2020
```
你可以通过按回车键来单步执行一条指令。你也可以一直执行,直到达到预期的相等条件:
```
: until pc 0 2020 (stop when pc=2020)
: until reg 0 mie a (stop when register mie=0xa)
: until mem 2020 50a9907311096993 (stop when mem[2020]=50a9907311096993)
```
或者,你可以只要相等条件成立就继续执行:
```
: while mem 2020 50a9907311096993
```
你可以通过以下方式无限期地继续执行:
```
: r
```
在执行期间的任何时候(即使没有使用 -d),你都可以通过 `-` 进入交互式调试模式。
要在调试提示符下结束模拟,请按 `-` 或输入:
```
: q
```
## 使用 Gdb 进行调试
除了交互式调试模式,另一种方法是使用 gdb 进行附加。因为 Spike 力求表现得像真实的硬件,所以你还需要 OpenOCD 来完成此操作。
我们将使用以下测试程序:
```
$ cat rot13.c
#include
char text[] = "Vafgehpgvba frgf jnag gb or serr!";
// Don't use the stack, because sp isn't set up.
volatile int wait = 1;
int main()
{
int i = 0;
while (text[i]) {
char lower = text[i] | 32;
if (lower >= 'a' && lower <= 'm')
text[i] += 13;
else if (lower > 'm' && lower <= 'z')
text[i] -= 13;
i++;
}
done:
printf("decoded text: %s\n", text);
}
$ riscv64-unknown-elf-gcc -g -Og --specs=semihost.specs -o rot13 rot13.c
```
要调试此程序,首先运行 spike 并告诉它监听 OpenOCD:
```
$ spike --rbb-port=9824 -m0x10000:0x20000 rot13
Listening for remote bitbang connection on port 9824.
...
```
在另一个终端窗口中,使用相应的配置文件运行 OpenOCD:
```
$ cat spike.cfg
adapter driver remote_bitbang
remote_bitbang host localhost
remote_bitbang port 9824
set _CHIPNAME riscv
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0xdeadbeef
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME riscv -chain-position $_TARGETNAME
gdb report_data_abort enable
init
arm semihosting enable
halt
$ openocd -f spike.cfg
Open On-Chip Debugger 0.12.0
...
Info : starting gdb server for riscv.cpu on 3333
Info : Listening on port 3333 for gdb connections
riscv.cpu halted due to debug-request. Semihosting is active.
...
riscv.cpu: target state: halted
```
在又一个终端窗口中,启动你的 gdb 调试会话:
```
$ riscv64-unknown-elf-gdb rot13
...
Reading symbols from rot13...
(gdb) target extended-remote localhost:3333
...
(gdb) load
...
(gdb) set $sp=0x2fff0
(gdb) b main
Breakpoint 1 at 0x10202: file rot13.c, line 5.
(gdb) c
Continuing.
Disabling abstract command writes to CSRs.
Breakpoint 1, main () at rot13.c:5
5 {
(gdb) print text
$1 = "Vafgehpgvba frgf jnag gb or serr!"
(gdb) until done
[riscv.cpu] Found 4 triggers
main () at rot13.c:16
16 printf("decoded text: %s\n", text);
(gdb) c
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
0x00019ff8 in _exit ()
(gdb)
...
```
在 OpenOCD 终端上,你将看到:
```
...
decoded text: Instruction sets want to be free!
semihosting: *** application exited with 0 ***
riscv.cpu halted due to breakpoint. Semihosting is active.
```
标签:CPU仿真, Hypervisor虚拟化, ISA模拟器, ISS, RISC-V, RV32I, RV64I, Spike, 功能模拟器, 向量扩展, 处理器模型, 安全头部检测, 客户端加密, 嵌入式系统, 开源硬件, 微架构验证, 指令集架构, 指令集模拟器, 标量密码学扩展, 浮点运算扩展, 硬件仿真, 硬件辅助工具, 系统软件开发, 芯片开发, 计算机体系结构