
Simulateur de jeu d'instructions RISC-V fonctionnel supportant de multiples extensions (RV32/64, V, cryptographie) avec mode de débogage interactif, intégration GDB et modélisation au niveau des instructions pour le co-développement matériel-logiciel et l'exploration d'architecture.
Spike, le simulateur ISA RISC-V, implémente un modèle fonctionnel d'un ou plusieurs cœurs RISC-V. Il doit son nom au « golden spike » (clou d'or) utilisé pour célébrer l'achèvement du chemin de fer transcontinental américain.
Spike prend en charge les fonctionnalités ISA RISC-V suivantes :
Les projets sont versionnés principalement pour indiquer quand l'API a été étendue ou rendue incompatible. Dans cet esprit, Spike vise à suivre le schéma de versionnement SemVer, dans lequel les numéros de version majeure sont incrémentés lors de modifications d'API rétro-incompatibles ; les numéros de version mineure sont incrémentés lors de l'ajout de nouvelles API ; et les numéros de version de correctif sont incrémentés lors de corrections de bogues de manière rétrocompatible.
L'API publique principale de Spike est l'ISA RISC-V. L'interface C++ vers les internes de Spike n'est pas considérée comme une API publique pour le moment, et des modifications rétro-incompatibles de cette interface seront apportées sans incrémenter le numéro de version majeure.
Nous supposons que la variable d'environnement RISCV est définie sur le chemin d'installation des outils 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
Si votre système utilise le gestionnaire de paquets yum, vous pouvez remplacer
yum install dtc pour la première étape.
Installez bash, gmake, dtc, et utilisez 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
Installez spike (voir Étapes de construction), riscv-gnu-toolchain et riscv-pk.
Écrivez un court programme C et nommez-le hello.c. Ensuite, compilez-le en un binaire ELF RISC-V nommé hello :
$ riscv64-unknown-elf-gcc -o hello hello.c
Vous pouvez maintenant simuler le programme au-dessus du noyau proxy :
$ spike pk hello
L'ajout d'une instruction au simulateur nécessite deux étapes :
Décrivez le comportement fonctionnel de l'instruction dans le fichier riscv/insns/<nom_nouvelle_instruction>.h. Examinez d'autres instructions dans ce répertoire comme point de départ.
Ajoutez l'opcode et le masque d'opcode dans riscv/opcodes.h. Alternativement, ajoutez-le au paquet riscv-opcodes, et il le fera pour vous :
$ cd ../riscv-opcodes
$ vi opcodes // ajouter une ligne pour la nouvelle instruction
$ make install
Ajoutez l'instruction à riscv/riscv.mk.in. Sinon, l'instruction ne sera pas incluse dans la construction et sera traitée comme une instruction illégale.
Reconstruisez le simulateur.
Pour invoquer le mode de débogage interactif, lancez spike avec -d :
$ spike -d pk hello
Pour voir le contenu d'un registre entier (0 correspond au cœur 0) :
: reg 0 a0
Pour voir le contenu d'un registre à virgule flottante :
: fregs 0 ft0
ou :
: fregd 0 ft0
selon que vous souhaitiez afficher le registre en simple ou double précision.
Pour voir le contenu d'un emplacement mémoire (adresse physique en hexadécimal) :
: mem 2020
Pour voir le contenu de la mémoire avec une adresse virtuelle (0 pour le cœur 0) :
: mem 0 2020
Vous pouvez avancer d'une instruction en appuyant sur la touche Entrée. Vous pouvez également exécuter jusqu'à ce qu'une égalité souhaitée soit atteinte :
: until pc 0 2020 (s'arrêter quand pc=2020)
: until reg 0 mie a (s'arrêter quand le registre mie=0xa)
: until mem 2020 50a9907311096993 (s'arrêter quand mem[2020]=50a9907311096993)
Alternativement, vous pouvez exécuter tant qu'une égalité est vraie :
: while mem 2020 50a9907311096993
Vous pouvez continuer l'exécution indéfiniment par :
: r
À tout moment pendant l'exécution (même sans -d), vous pouvez entrer dans le
mode de débogage interactif avec <control>-<c>.
Pour terminer la simulation depuis l'invite de débogage, appuyez sur <control>-<c> ou :
: q
Une alternative au mode de débogage interactif est de se connecter en utilisant gdb. Comme spike essaie de ressembler à du matériel réel, vous avez également besoin d'OpenOCD pour cela. Nous utiliserons le programme de test suivant :
$ 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
Pour déboguer ce programme, exécutez d'abord spike en lui demandant d'écouter OpenOCD :
$ spike --rbb-port=9824 -m0x10000:0x20000 rot13
Listening for remote bitbang connection on port 9824.
...
Dans un autre terminal, exécutez OpenOCD avec le fichier de configuration approprié :
$ 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
Dans encore un autre terminal, démarrez votre session de débogage 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)
...
Sur le terminal OpenOCD, vous aurez :
...
decoded text: Instruction sets want to be free!
semihosting: *** application exited with 0 ***
riscv.cpu halted due to breakpoint. Semihosting is active.