Extremis
Assembly

Extremis

RPG-avontuur geschreven in RISC-V Assembly

( god, die .iris programmeerde om niet opgenomen te kunnen worden? )

Een tekstgebaseerd rollenspel geschreven in RISC-V 32-bit assembly, gesimuleerd via QEMU.

"Het universum besloot dat het niet wilde dat ik iets beters deed, zoals misschien een leven krijgen."

Afhankelijkheden

  • riscv32-elf-as — RISC-V assembler
  • riscv32-elf-ld — RISC-V linker
  • qemu-riscv32 — RISC-V user-mode emulator

Op Arch Linux:

sudo pacman -S riscv64-elf-binutils qemu-user

Bouwen & Uitvoeren

make build   # assembleren en linken naar main.bin
make run     # bouwen + uitvoeren via qemu-riscv32
make debug   # uitvoeren met -strace om syscalls te inspecteren

Projectstructuur

Extremis/
├── main.s                      # Entry point (_start), roept run_chapter_1 aan
├── src/
│   ├── include/
│   │   └── function.s          # startF / endF stack frame macros
│   ├── engine/
│   │   ├── print.s             # print  — print een enkele null-terminated string (a0)
│   │   └── utils.s             # printl — print een lijst strings (a0=addr tabel, a1=aantal)
│   ├── chapters/
│   │   └── chapter_1.s         # Hoofdstuk 1 logica; laadt intro strings en roept printl aan
│   └── dialogue/
│       └── intro.s             # String data voor de introductie
└── build/                      # Gecompileerde .o bestanden (spiegelt src/ structuur)

Architectuur

De engine is pure RISC-V 32-bit assembly gericht op de Linux ABI via QEMU user-mode emulatie.

Stack Frame Conventie

Elke functie gebruikt de startF / endF macros uit src/include/function.s om ra, s0, s1, s2 op de stack op te slaan en te herstellen:

startF    # push: wijs 16 bytes toe, sla ra/s0/s1/s2 op
...
endF      # pop:  herstel ra/s0/s1/s2, dewijs 16 bytes vrij
ret

Syscalls

Waarschuwing: RARS/MARS omgevingscallnummers werken niet onder qemu-riscv32. Dit project gebruikt Linux RISC-V ABI syscallnummers.

Syscallnummer gaat in a7, aanroepen met ecall. Retourwaarde komt terug in a0.

Uitvoer

Doel RARS a7 Linux a7 a0 a1 a2 Opmerkingen
Print string 4 64 1 (stdout fd) buf addr lengte Linux stopt NIET bij null — geef byte lengte
Print char 11 64 1 char buf 1 sla char op in geheugen, geef adres door
Print integer 1 integer geen Linux equivalent; eerst naar string
Print hex integer 34 integer geen Linux equivalent; handmatig converteren
Print unsigned int 36 integer geen Linux equivalent; handmatig converteren

Invoer

Doel RARS a7 Linux a7 a0 a1 a2 Opmerkingen
Lees string 8 63 0 (stdin fd) buf addr max bytes Linux retourneert ruwe bytes incl. newline
Lees char 12 63 0 buf addr 1 retourneert a0 = gelezen bytes; char in buf
Lees integer 5 geen Linux equivalent; lees string, parseer

Proces

Doel RARS a7 Linux a7 a0 Opmerkingen
Afsluiten 10 93 RARS negeert a0; Linux leest als exitstatus
Afsluiten(code) 17 93 exitcode Linux exit_group

Geheugen

Doel RARS a7 Linux a7 a0 Retourneert Opmerkingen
Toewijzen (sbrk) 9 214 bytes (RARS) / nieuw brk adres (Linux) a0 = begin toegewezen blok Linux brk werkt anders — je stelt nieuwe top in, geen grootte

Bestands-I/O

Doel RARS a7 Linux a7 a0 a1 a2 a3 Opmerkingen
Bestand openen 13 56 dirfd (-100=CWD) bestandsnaam addr vlaggen modus Linux gebruikt openat
Bestand lezen 14 63 fd buf addr max bytes retourneert gelezen bytes
Bestand schrijven 15 64 fd buf addr byte aantal retourneert geschreven bytes
Bestand sluiten 16 57 fd retourneert 0 bij succes

Tijd

Doel RARS a7 Linux a7 a0 a1 Opmerkingen
Tijd 30 113 clock id (1=REALTIME) timespec* buf RARS retourneert lo/hi in a0/a1; Linux schrijft struct naar buf
Slaap 32 115 clock id timespec* RARS neemt milliseconden in a0; Linux gebruikt clock_nanosleep met struct

Inhoud Toevoegen

  • Nieuwe dialoogstrings gaan in src/dialogue/.
  • Nieuwe hoofdstukken gaan in src/chapters/ en worden .include'd in het hoofdstukbestand dat ze nodig heeft.
  • Het Makefile ontdekt automatisch alle .s bestanden onder src/ (exclusief src/include/).