Extremis
Assembly

Extremis

Jeu d'aventure RPG écrit en langage assembleur RISC-V

( 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-V
  • riscv32-elf-ld — Éditeur de liens RISC-V
  • qemu-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 .include dans le fichier de chapitre qui en a besoin.
  • Le Makefile détecte automatiquement tous les fichiers .s sous src/ (à l'exception de src/include/).