( Mais bon sang, qui a programmé .iris pour qu'on ne puisse pas le valider ? )
Un RPG textuel écrit en assembleur RISC-V 32 bits, simulé via QEMU.
« L'univers a décidé qu'il ne voulait pas que je fasse quelque chose de mieux, comme peut-être me trouver une vie. »
Dépendances
riscv32-elf-as— Assembleur RISC-Vriscv32-elf-ld— Éditeur de liens RISC-Vqemu-riscv32— Émulateur RISC-V en mode utilisateur
Sous Arch Linux :
sudo pacman -S riscv64-elf-binutils qemu-user
Compilation et exécution
make build # assemble et lie dans main.bin
make run # compile + exécute via qemu-riscv32
make debug # exécute avec -strace pour inspecter les appels système
Structure du projet
Extremis/
├── main.s # Point d'entrée (_start), appelle run_chapter_1
├── src/
│ ├── include/
│ │ └── function.s # macros de trame de pile startF / endF
│ ├── engine/
│ │ ├── print.s # print — affiche une chaîne de caractères terminée par un caractère nul (a0)
│ │ └── utils.s # printl — affiche une liste de chaînes (a0=table d'adresses, a1=nombre)
│ ├── chapters/
│ │ └── chapter_1.s # Logique du chapitre 1 ; charge les chaînes d'introduction et appelle printl
│ └── dialogue/
│ └── intro.s # Données de chaînes pour la séquence d'introduction
└── build/ # Fichiers .o compilés (reflète la structure de src/)
Architecture
Le moteur est un assemblage RISC-V 32 bits pur ciblant l'ABI Linux via l'émulation en mode utilisateur de QEMU.
Convention de cadre de pile
Chaque fonction utilise les macros startF / endF de src/include/function.s pour sauvegarder et restaurer ra, s0, s1, s2 sur la pile :
startF # push : allouer 16 octets, sauvegarder ra/s0/s1/s2
...
endF # pop : restaurer ra/s0/s1/s2, désallouer 16 octets
ret
Appels système
Avertissement : les numéros d'appel d'environnement RARS/MARS ne fonctionnent pas sous
qemu-riscv32. Ce projet utilise les numéros d'appel système de l'ABI Linux RISC-V.
Le numéro d'appel système est placé dans a7, invoqué avec ecall. La valeur de retour est renvoyée dans a0.
Sortie
| Intention | RARS a7 |
Linux a7 |
a0 |
a1 |
a2 |
Remarques |
|---|---|---|---|---|---|---|
| Afficher une chaîne | 4 |
64 |
1 (descripteur stdout) |
adresse du tampon | longueur | Linux ne s'arrête PAS à la fin de la chaîne — passer la longueur en octets |
| Afficher un caractère | 11 |
64 |
1 |
tampon de caractères | 1 |
stocker le caractère en mémoire, passer son adresse |
| Imprimer un entier | 1 |
— | entier | — | — | pas d'équivalent sous Linux ; convertir d'abord en chaîne |
| Imprimer un entier hexadécimal | 34 |
— | entier | — | — | pas d'équivalent sous Linux ; convertir manuellement |
| Afficher un entier non signé | 36 |
— | entier | — | — | pas d'équivalent sous Linux ; convertir manuellement |
Entrée
| Intention | RARS a7 |
Linux a7 |
a0 |
a1 |
a2 |
Remarques |
|---|---|---|---|---|---|---|
| Lecture de chaîne | 8 |
63 |
0 (descripteur stdin) |
adresse du tampon | nombre max. d'octets | Linux renvoie les octets bruts, y compris le retour à la ligne |
| Lecture de caractère | 12 |
63 |
0 |
adresse du tampon | 1 |
renvoie a0 = octets lus ; le caractère est dans le tampon |
| Lecture d'un entier | 5 |
— | — | — | — | pas d'équivalent sous Linux ; lire la chaîne, l'analyser |
Processus
| Intention | RARS a7 |
Linux a7 |
a0 |
Remarques |
|---|---|---|---|---|
| Sortie | 10 |
93 |
— | RARS ignore a0 ; Linux le lit comme statut de sortie |
| Sortie(code) | 17 |
93 |
code de sortie | Linux exit_group |
Mémoire
| Intention | RARS a7 |
Linux a7 |
a0 |
Retourne | Remarques |
|---|---|---|---|---|---|
| Allouer (sbrk) | 9 |
214 |
octets (RARS) / nouvelle adresse brk (Linux) | a0 = début du bloc alloué |
Linux brk fonctionne différemment — vous définissez le nouveau début, pas la taille |
E/S de fichiers
| Intention | RARS a7 |
Linux a7 |
a0 |
a1 |
a2 |
a3 |
Remarques |
|---|---|---|---|---|---|---|---|
| Ouvrir un fichier | 13 |
56 |
dirfd (-100=CWD) |
adresse du nom de fichier | indicateurs | mode | Linux utilise openat |
| Lire un fichier | 14 |
63 |
fd | adresse du tampon | nombre maximal d'octets | — | renvoie le nombre d'octets lus |
| Écriture dans le fichier | 15 |
64 |
fd | adresse du tampon | nombre d'octets | — | renvoie le nombre d'octets écrits |
| Fermeture du fichier | 16 |
57 |
fd | — | — | — | renvoie 0 en cas de succès |
Temps
| Intention | RARS a7 |
Linux a7 |
a0 |
a1 |
Remarques |
|---|---|---|---|---|---|
| Temps | 30 |
113 |
identifiant d'horloge (1=REALTIME) |
tampon timespec* |
RARS renvoie les parties basse et haute dans a0/a1 ; Linux écrit la structure dans le tampon |
| Sommeil | 32 |
115 |
ID de l'horloge | timespec* |
RARS prend les millisecondes dans a0 ; Linux utilise clock_nanosleep avec une structure |
Ajout de contenu
- Les nouvelles chaînes de dialogue vont dans
src/dialogue/. - Les nouveaux chapitres vont dans
src/chapters/et sont inclus via.includedans le fichier de chapitre qui en a besoin. - Le Makefile détecte automatiquement tous les fichiers
.ssoussrc/(à l'exception desrc/include/).
