
Funktionaler RISC-V-ISA-Simulator, der mehrere Erweiterungen (RV32/64, V, Kryptografie) mit interaktivem Debug-Modus, GDB-Integration und instruktionsgenauer Modellierung für die Hardware-Software-Koentwicklung und Architekturforschung unterstützt.
Spike, der RISC-V ISA Simulator, implementiert ein funktionales Modell eines oder mehrerer RISC-V-Kerne. Er ist nach dem goldenen Nagel benannt, der zur Feier der Fertigstellung der transkontinentalen Eisenbahn in den USA verwendet wurde.
Spike unterstützt die folgenden RISC-V-ISA-Funktionen:
Projekte werden in erster Linie versioniert, um anzuzeigen, wann die API erweitert oder inkompatibel gemacht wurde. In diesem Sinne zielt Spike darauf ab, dem SemVer-Versionierungsschema zu folgen, bei dem Hauptversionsnummern erhöht werden, wenn rückwärtsinkompatible API-Änderungen vorgenommen werden; Nebenversionsnummern werden erhöht, wenn neue APIs hinzugefügt werden; und Patchversionsnummern werden erhöht, wenn Fehler in einer rückwärtskompatiblen Weise behoben werden.
Die wichtigste öffentliche API von Spike ist die RISC-V-ISA. Die C++-Schnittstelle zu Spikes Interna gilt derzeit nicht als öffentliche API, und rückwärtsinkompatible Änderungen an dieser Schnittstelle werden vorgenommen, ohne die Hauptversionsnummer zu erhöhen.
Wir gehen davon aus, dass die Umgebungsvariable RISCV auf den Installationspfad der RISC-V-Tools gesetzt ist.
$ apt-get install device-tree-compiler libboost-regex-dev libboost-system-dev
$ mkdir build
$ cd build
$ ../configure --prefix=$RISCV
$ make
$ [sudo] make install
Falls Ihr System den yum-Paketmanager verwendet, können Sie den ersten Schritt durch
yum install dtc ersetzen.
Installieren Sie bash, gmake, dtc und verwenden Sie 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
Installieren Sie spike (siehe Build-Schritte), riscv-gnu-toolchain und riscv-pk.
Schreiben Sie ein kurzes C-Programm und nennen Sie es hello.c. Kompilieren Sie es dann in ein RISC-V- ELF-Binary namens hello:
$ riscv64-unknown-elf-gcc -o hello hello.c
Jetzt können Sie das Programm über den Proxy-Kernel simulieren:
$ spike pk hello
Das Hinzufügen einer Instruktion zum Simulator erfordert zwei Schritte:
Beschreiben Sie das funktionale Verhalten der Instruktion in der Datei riscv/insns/<new_instruction_name>.h. Untersuchen Sie andere Instruktionen in diesem Verzeichnis als Ausgangspunkt.
Fügen Sie den Opcode und die Opcode-Maske zu riscv/opcodes.h hinzu. Alternativ fügen Sie es zum riscv-opcodes-Paket hinzu, und es wird dies für Sie erledigen:
$ cd ../riscv-opcodes
$ vi opcodes // fügen Sie eine Zeile für die neue Instruktion hinzu
$ make install
Fügen Sie die Instruktion zu riscv/riscv.mk.in hinzu. Andernfalls wird die Instruktion nicht in den Build einbezogen und als illegale Instruktion behandelt.
Bauen Sie den Simulator neu.
Um den interaktiven Debug-Modus aufzurufen, starten Sie spike mit -d:
$ spike -d pk hello
Um den Inhalt eines Integer-Registers anzuzeigen (0 steht für Kern 0):
: reg 0 a0
Um den Inhalt eines Gleitkommaregisters anzuzeigen:
: fregs 0 ft0
oder:
: fregd 0 ft0
je nachdem, ob Sie das Register als einfache oder doppelte Genauigkeit ausgeben möchten.
Um den Inhalt einer Speicherstelle anzuzeigen (physische Adresse in hex):
: mem 2020
Um den Inhalt des Speichers mit einer virtuellen Adresse anzuzeigen (0 für Kern 0):
: mem 0 2020
Sie können mit der Eingabetaste einen Schritt vorrücken. Sie können auch ausführen, bis eine gewünschte Gleichheit erreicht ist:
: until pc 0 2020 (stoppen, wenn pc=2020)
: until reg 0 mie a (stoppen, wenn Register mie=0xa)
: until mem 2020 50a9907311096993 (stoppen, wenn mem[2020]=50a9907311096993)
Alternativ können Sie so lange ausführen, wie eine Gleichheit wahr ist:
: while mem 2020 50a9907311096993
Sie können die Ausführung unbegrenzt fortsetzen mit:
: r
Während der Ausführung (auch ohne -d) können Sie jederzeit in den
interaktiven Debug-Modus mit <Strg>-<c> wechseln.
Um die Simulation von der Debug-Eingabeaufforderung zu beenden, drücken Sie <Strg>-<c> oder:
: q
Eine Alternative zum interaktiven Debug-Modus ist das Anhängen mit gdb. Da spike versucht, wie echte Hardware zu sein, benötigen Sie dazu auch OpenOCD. Wir verwenden das folgende Testprogramm:
$ cat rot13.c
#include <stdio.h>
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
Um dieses Programm zu debuggen, starten Sie zuerst spike und weisen es an, auf OpenOCD zu hören:
$ spike --rbb-port=9824 -m0x10000:0x20000 rot13
Listening for remote bitbang connection on port 9824.
...
Führen Sie in einer separaten Shell OpenOCD mit der entsprechenden Konfigurationsdatei aus:
$ 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
Starten Sie in einer weiteren Shell Ihre gdb-Debug-Sitzung:
$ 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)
...
Auf dem OpenOCD-Terminal sehen Sie:
...
decoded text: Instruction sets want to be free!
semihosting: *** application exited with 0 ***
riscv.cpu halted due to breakpoint. Semihosting is active.