Spike, the RISC-V ISA Simulator, implements a functional model of one or more RISC-V harts. It is named after the golden spike used to celebrate the completion of the US transcontinental railway.
This fork extends Spike to support custom PULP instructions. Together with the repos riscv-opcodes and riscv-tests, it forms a framework that aids in developing extensions, testing implementations and running applications.
Spike supports the following RISC-V ISA features:
- RV32I and RV64I base ISAs, v2.1
- Zifencei extension, v2.0
- Zicsr extension, v2.0
- M extension, v2.0
- A extension, v2.1
- F extension, v2.2
- D extension, v2.2
- Q extension, v2.2
- C extension, v2.0
- V extension, v0.9, w/ Zvlsseg/Zvamo/Zvqmac, w/o Zvediv, (requires a 64-bit host)
- Conformance to both RVWMO and RVTSO (Spike is sequentially consistent)
- Machine, Supervisor, and User modes, v1.11
- Debug v0.14
- All xpulpv3 extension subsets except xpulpelw
Projects are versioned primarily to indicate when the API has been extended or rendered incompatible. In that spirit, Spike aims to follow the SemVer versioning scheme, in which major version numbers are incremented when backwards-incompatible API changes are made; minor version numbers are incremented when new APIs are added; and patch version numbers are incremented when bugs are fixed in a backwards-compatible manner.
Spike's principal public API is the RISC-V ISA. The C++ interface to Spike's internals is not considered a public API at this time, and backwards-incompatible changes to this interface will be made without incrementing the major version number.
We assume that the RISCV environment variable is set to the RISC-V tools install path.
$ apt-get install device-tree-compiler
$ mkdir build
$ cd build
$ ../configure --prefix=$RISCV
$ make
$ [sudo] make install
Install bash, gmake, dtc, and use 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
Install spike (see Build Steps), riscv-gnu-toolchain, and riscv-pk.
Write a short C program and name it hello.c. Then, compile it into a RISC-V ELF binary named hello:
$ riscv32-unknown-elf-gcc -o hello hello.c
Now you can simulate the program atop the proxy kernel:
$ spike pk hello
Or on bare metal:
$ spike hello
jonesinator/riscv-spike-minimal-assembly provides a well documented minimal bare metal program and also one which uses syscall to communicate with the host.
For xpulp-specific examples take a look at the riscv-tests repo, in riscv-tests/isa it contains functional tests for all supported xpulp instructions.
Adding an instruction to the simulator requires these steps:
-
Clone riscv-opcodes, add the opcode to it and generate encoding_out.h
-
Create a soft-link for riscv/encoding.h to the generated encoding_out.h
$ ln -sfr riscv-opcodes/encoding_out.h riscv-isa-sim/riscv/encoding.h
-
Describe the instruction's functional behavior in the file riscv/insns/<new_instruction_name>.h. Examine other instructions in that directory as a starting point. Use macros from riscv/decode.h.
-
Add the mnemonic format (disassembly format) of the instruction to diasm/diasm.cc
-
In riscv/riscv.mk.in add the instruction to riscv_insn_list. You can get all instructions from your current encoding.h (encoding_out.h) using:
$ grep ^DECLARE_INSN encoding.h | sed 's/DECLARE_INSN(\(.*\),.*,.*)/\1/'
-
Rebuild the simulator.
To invoke interactive debug mode, launch spike with -d:
$ spike -d pk hello
To see the contents of an integer register (0 is for core 0):
: reg 0 a0
To see the contents of a floating point register:
: fregs 0 ft0
or:
: fregd 0 ft0
depending upon whether you wish to print the register as single- or double-precision.
To see the contents of a memory location (physical address in hex):
: mem 2020
To see the contents of memory with a virtual address (0 for core 0):
: mem 0 2020
You can advance by one instruction by pressing the enter key. You can also execute until a desired equality is reached:
: until pc 0 2020 (stop when pc=2020)
: until mem 2020 50a9907311096993 (stop when mem[2020]=50a9907311096993)
Alternatively, you can execute as long as an equality is true:
: while mem 2020 50a9907311096993
You can continue execution indefinitely by:
: r
At any point during execution (even without -d), you can enter the
interactive debug mode with <control>-<c>
.
To end the simulation from the debug prompt, press <control>-<c>
or:
: q
An alternative to interactive debug mode is to attach using gdb. Because spike
tries to be like real hardware, you also need OpenOCD to do that. OpenOCD
doesn't currently know about address translation, so it's not possible to
easily debug programs that are run under pk
. We'll use the following test
program:
$ cat rot13.c
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()
{
while (wait)
;
// Doesn't actually go on the stack, because there are lots of GPRs.
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:
while (!wait)
;
}
$ cat spike.lds
OUTPUT_ARCH( "riscv" )
SECTIONS
{
. = 0x10010000;
.text : { *(.text) }
.data : { *(.data) }
}
$ riscv64-unknown-elf-gcc -g -Og -o rot13-64.o -c rot13.c
$ riscv64-unknown-elf-gcc -g -Og -T spike.lds -nostartfiles -o rot13-64 rot13-64.o
To debug this program, first run spike telling it to listen for OpenOCD:
$ spike --rbb-port=9824 -m0x10000000:0x20000 rot13-64
Listening for remote bitbang connection on port 9824.
In a separate shell run OpenOCD with the appropriate configuration file:
$ cat spike.cfg
interface remote_bitbang
remote_bitbang_host localhost
remote_bitbang_port 9824
set _CHIPNAME riscv
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10e31913
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME riscv -chain-position $_TARGETNAME
gdb_report_data_abort enable
init
halt
$ openocd -f spike.cfg
Open On-Chip Debugger 0.10.0-dev-00002-gc3b344d (2017-06-08-12:14)
...
riscv.cpu: target state: halted
In yet another shell, start your gdb debug session:
tnewsome@compy-vm:~/SiFive/spike-test$ riscv64-unknown-elf-gdb rot13-64
GNU gdb (GDB) 8.0.50.20170724-git
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-pc-linux-gnu --target=riscv64-unknown-elf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from rot13-64...done.
(gdb) target remote localhost:3333
Remote debugging using localhost:3333
0x0000000010010004 in main () at rot13.c:8
8 while (wait)
(gdb) print wait
$1 = 1
(gdb) print wait=0
$2 = 0
(gdb) print text
$3 = "Vafgehpgvba frgf jnag gb or serr!"
(gdb) b done
Breakpoint 1 at 0x10010064: file rot13.c, line 22.
(gdb) c
Continuing.
Disabling abstract command writes to CSRs.
Breakpoint 1, main () at rot13.c:23
23 while (!wait)
(gdb) print wait
$4 = 0
(gdb) print text
...