( боже, хто запрограмував .iris так, що його не можна комітити? )
Текстова RPG, написана на асемблері RISC-V 32-біт, симульована через QEMU.
"Всесвіт вирішив, що я не повинен займатися чимось кращим, наприклад, мати життя."
Залежності
riscv32-elf-as— асемблер RISC-Vriscv32-elf-ld— лінкер RISC-Vqemu-riscv32— емулятор RISC-V у режимі користувача
На Arch Linux:
sudo pacman -S riscv64-elf-binutils qemu-user
Збірка та запуск
make build # асемблювати та лінкувати в main.bin
make run # збірка + запуск через qemu-riscv32
make debug # запуск з -strace для перевірки системних викликів
Структура проєкту
Extremis/
├── main.s # Точка входу (_start), викликає run_chapter_1
├── src/
│ ├── include/
│ │ └── function.s # макроси кадрів стеку startF / endF
│ ├── engine/
│ │ ├── print.s # print — вивести один рядок, що закінчується нулем (a0)
│ │ └── utils.s # printl — вивести список рядків (a0=адреса таблиці, a1=кількість)
│ ├── chapters/
│ │ └── chapter_1.s # Логіка глави 1; завантажує вступні рядки та викликає printl
│ └── dialogue/
│ └── intro.s # Дані рядків для вступної послідовності
└── build/ # Скомпільовані файли .o (віддзеркалює структуру src/)
Архітектура
Рушій написаний повністю на асемблері RISC-V 32-біт, орієнтований на Linux ABI через емуляцію QEMU в режимі користувача.
Конвенція кадру стеку
Кожна функція використовує макроси startF / endF з src/include/function.s для збереження та відновлення ra, s0, s1, s2 у стеку:
startF # push: виділити 16 байт, зберегти ra/s0/s1/s2
...
endF # pop: відновити ra/s0/s1/s2, звільнити 16 байт
ret
Системні виклики
Увага: Номери викликів середовища RARS/MARS не працюють під
qemu-riscv32. Цей проєкт використовує номери системних викликів Linux ABI для RISC-V.
Номер системного виклику поміщається в a7, викликається за допомогою ecall. Значення повернення надходить у a0.
Виведення
| Призначення | RARS a7 |
Linux a7 |
a0 |
a1 |
a2 |
Примітки |
|---|---|---|---|---|---|---|
| Вивести рядок | 4 |
64 |
1 (stdout fd) |
адреса буфера | довжина | Linux НЕ зупиняється на нулі — передавайте довжину в байтах |
| Вивести символ | 11 |
64 |
1 |
буфер символу | 1 |
зберегти символ у пам'яті, передати його адресу |
| Вивести ціле число | 1 |
— | ціле число | — | — | немає еквівалента в Linux; спочатку конвертуйте в рядок |
| Вивести шістнадцяткове ціле число | 34 |
— | ціле число | — | — | немає еквівалента в Linux; конвертуйте вручну |
| Вивести беззнакове ціле число | 36 |
— | ціле число | — | — | немає еквівалента в Linux; конвертуйте вручну |
Введення
| Призначення | RARS a7 |
Linux a7 |
a0 |
a1 |
a2 |
Примітки |
|---|---|---|---|---|---|---|
| Зчитати рядок | 8 |
63 |
0 (stdin fd) |
адреса буфера | макс. байт | Linux повертає сирі байти, включаючи новий рядок |
| Зчитати символ | 12 |
63 |
0 |
адреса буфера | 1 |
повертає a0 = прочитані байти; символ у буфері |
| Зчитати ціле число | 5 |
— | — | — | — | немає еквівалента в Linux; зчитати рядок, розпарсити його |
Процес
| Призначення | RARS a7 |
Linux a7 |
a0 |
Примітки |
|---|---|---|---|---|
| Вихід | 10 |
93 |
— | RARS ігнорує a0; Linux читає його як статус виходу |
| Вихід(код) | 17 |
93 |
код виходу | Linux exit_group |
Пам'ять
| Призначення | RARS a7 |
Linux a7 |
a0 |
Повертає | Примітки |
|---|---|---|---|---|---|
| Виділити (sbrk) | 9 |
214 |
байти (RARS) / нова адреса brk (Linux) | a0 = початок виділеного блоку |
Linux brk працює інакше — ви встановлюєте новий верх, а не розмір |
Файловий ввід/вивід
| Призначення | RARS a7 |
Linux a7 |
a0 |
a1 |
a2 |
a3 |
Примітки |
|---|---|---|---|---|---|---|---|
| Відкрити файл | 13 |
56 |
dirfd (-100=CWD) |
адреса імені файлу | прапори | режим | Linux використовує openat |
| Читати файл | 14 |
63 |
fd | адреса буфера | макс. байт | — | повертає прочитані байти |
| Писати у файл | 15 |
64 |
fd | адреса буфера | кількість байт | — | повертає записані байти |
| Закрити файл | 16 |
57 |
fd | — | — | — | повертає 0 при успіху |
Час
| Призначення | RARS a7 |
Linux a7 |
a0 |
a1 |
Примітки |
|---|---|---|---|---|---|
| Час | 30 |
113 |
ідентифікатор годинника (1=REALTIME) |
буфер timespec* |
RARS повертає розділені lo/hi в a0/a1; Linux записує структуру в буфер |
| Сон | 32 |
115 |
ідентифікатор годинника | timespec* |
RARS приймає мілісекунди в a0; Linux використовує clock_nanosleep зі структурою |
Додавання контенту
- Нові рядки діалогів додавайте в
src/dialogue/. - Нові глави додавайте в
src/chapters/та включайте їх (.include) у файл глави, який їх потребує. - Makefile автоматично виявляє всі файли
.sуsrc/(крімsrc/include/).
