QuickSave F6/F9 в roomtest; bank_load_file/bank_save_file/gfx_w0_page_prepare; sprinter-cc: авто n_banks

roomtest:
- QuickSave/QuickLoad (F6/F9): снапшот 'POPQ' v3 в POP.SAV/POP.BAK на HDD,
  транзакционная запись (POP.NEW -> rename, откат при ошибке), XOR-контрольная
  сумма payload'а; сериализация всех игровых переменных через W0-примитивы
  pop_qs_*; pop_qsave_process() на границе кадра вне Char-окон
- pop_qsave_restore_room(): полная перезагрузка комнаты после загрузки
  (карта/края/швы, сброс bake-кэша, перерисовка обеих страниц, инвалидация
  кэшей спрайтов и HP)
- сериализаторы в pop_map/pop_loose_mob/pop_trob/pop_guard_ai
  (+ восстановление инвариантов: mobs_live, trob_drawn, redraw)
- immortal-чит 2 уровня: уровень 2 поглощает только малый урон Kid'а

libc/libbgi:
- bank_load_file()/bank_save_file() — резидентное файловое I/O в банк,
  без правила W3 (путь читается до переключения страницы)
- gfx_w0_page_prepare(page) — подготовка W0-окна (IRQ/NMI-стабы) одной
  функцией; atlas_load.c и roomtest переведены на новые примитивы;
  ручные ISR-стабы удалены

sprinter-cc / сборка:
- --bank N=FILE.c: автогенерация n_banks (_n_banks_auto.c), ручные
  const n_banks удалены из тестов
- roomtest/app.mk: ресурсы через stamp-файлы (.resource-stamps/) — один
  запуск упаковщика на группу вместо N под -B; HDD_PACK_ARGS
This commit is contained in:
2026-08-22 11:53:10 +03:00
parent b6699b3aef
commit f4b4852d51
57 changed files with 1610 additions and 301 deletions
+18 -20
View File
@@ -5,6 +5,17 @@
## Ближайшее
- [ ] **Перевести новые EMM/W0-функции libc/libbgi на Z80 asm:**
`bank_load_file()`, `bank_save_file()` и `gfx_w0_page_prepare()`.
Сейчас универсальная C-обвязка (четыре аргумента, IX-frame, проверки
диапазона и сохранение временных значений) съедает часть выигрыша от
унификации загрузчиков PoP. Сделать компактные `__naked`-реализации
по образцу остальных низкоуровневых функций библиотек, строго сохранив
`__sdcccall(1)`, IX, W3 до возврата и семантику `-1 + errno`; fast-
вариант может вырезать проверки диапазона, safe обязан их оставить.
После правки: `make -C libc`, `make -C libbgi`, `make size-check` и
MAME-проверка Atlas/Kid/Level/Sound + QuickSave/QuickLoad.
- [ ] **Модульные тесты libc и libbgi под ucsim_z80** — план:
`docs/host-tests-plan.md`. Обвязка уже готова и обкатана
(`testkit/`, первый потребитель — PoP/roomtest). Не срочно, но
@@ -61,12 +72,10 @@
## Auto-banking (memory/banking_roadmap.md)
- [ ] **Сверять `n_banks` с реальным числом банков — ошибкой сборки.**
Сейчас число банков задаётся ДВАЖДЫ и вручную: флагами `--bank N=…`
у `sprinter-cc` и константой `const uint8_t n_banks = N;` в
приложении (её читает `crt0_banked` при старте, чтобы выделить
EMM-страницы и загрузить в них образы банков). Рассогласование не
даёт ни ошибки компиляции, ни ошибки линковки — только зависание в
- [x] **Генерировать `n_banks` из реальной раскладки банков.**
`sprinter-cc` вычисляет максимальный N из `--bank N=…`, проверяет диапазон
1..15 и отсутствие дыр, затем линкует сгенерированный `_n_banks`.
Раньше число задавалось ещё и вручную в приложении; рассогласование давало зависание в
рантайме: `_bank_pages[N]` остаётся нулём, трамплин отображает в
окно страницу 0 и прыгает по 0xC000 в мусор (предупреждение об этом
уже есть в шапке `runtime/bank.s`).
@@ -75,20 +84,9 @@
загрузки ресурсов и вставала намертво в дисковом коде DSS. Диагноз
занял заметно больше, чем сама правка: симптом (зависание в чужом
коде) никак не указывает на причину.
Сверять надо не количество, а **максимальный индекс** банка: `--bank`
нумеруются с 1 и в принципе могут идти с дырами, а `crt0_banked`
заполняет `_bank_pages[1..n_banks]` подряд.
Варианты, от простого к правильному:
1. **Проверка после линковки** — вытащить значение `_n_banks` из
`.ihx`/`.map` (это `const` в `_CODE`, адрес известен из карты) и
сравнить с `max(N)` по флагам; не совпало — `sprinter-cc` падает
с внятным сообщением. Ничего не ломает в существующих
приложениях, ставится сразу.
2. **Генерировать самим `sprinter-cc`** — он уже так делает, когда
банков нет (`const unsigned char n_banks = 0;`). Правильнее по
сути (единственный источник истины), но требует убрать константу
из всех банковых приложений, иначе дубль символа: `tests/banked`,
`banktest`, `banklocl`, `bankedbg`, `applications/PoP/roomtest`.
Берётся не число опций (в одном банке может быть несколько модулей), а
**максимальный индекс**. Дыры запрещены, поскольку `crt0_banked` и `mkexe`
обрабатывают `_bank_pages[1..n_banks]` подряд.
Phase 1 — file-level bin-packing (`toolchain/auto_bank.py`) — когда
проект перерастёт ~30 KB кода: парсинг размеров из .rel/.map,