libc/irq: цепочка кадровых обработчиков + all-modes W1-remap

_irq_user → _irq_chain[4]+_irq_chain_n (W2-BSS); трамплин tr_frame
проходит слоты (один тяжёлый сейв на всю цепь, пустой слот пропуск).
API irq_chain_add (0/-1+ENOMEM) / irq_chain_remove(h); irq_install →
обёртка chain_add (EBUSY исчез), irq_remove() рвёт всю цепь; refcount
таблицы на первом/последнем слоте, мутации под IRQ_DISABLE. Лимит
4 кадровых + 1 CTC.

All-modes: трамплин copy-safe (только jr/djnz + литерал jp 0x0038),
_irq_table_ref копирует его в _irq_tramp_w2buf (W2) когда оригинал в W1
(small/huge), вектор → на копию; вокруг вызова хендлеров восстанавливает
базовую W1-страницу (_irq_app_w1_page = IN 0xA2). Хендлер может лежать
где угодно в плоском 0x4000-0xBFFF.

Проверено в MAME (tests/irqtest, 2 хендлера): tiny/big/huge — chain
h1=h2 → remove h2 → h1 жив/h2=0; huge = код в W1, remap работает.
Follow-up: CTC в small/huge = EINVAL (нужна W2-копия _irq_ctc_tramp);
small для мелких программ (BSS в W1) = irq_install EINVAL, safe.

Доки: im2_isr_design (цепочка), sprite-api §9е (делитель поверх цепи),
fast_ram §8. rpgprof: gfx_sprite_ysort в профиль (+230 Б baseline).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-15 10:23:39 +03:00
parent 6b6986d9b6
commit 2c6f4e33c3
17 changed files with 700 additions and 128 deletions
+26 -18
View File
@@ -5,26 +5,34 @@
## Ближайшее
- [ ] **FPS-делитель (frame pacing)** — gfx_set_fps_div(n): логический
Порядок реализации связки: **сначала цепочка irq, потом FPS-делитель
поверх неё** (делитель — просто один слот цепи; так снимается EBUSY
на сосуществование со своим тиком приложения).
- [x] **(1) irq: цепочка кадровых обработчиков** — СДЕЛАНО 2026-07-15.
Массив `isr_t _irq_chain[4]` + `_irq_chain_n` в W2-data (заменили
`_irq_user`); трамплин `tr_frame` проходит слоты (один тяжёлый сейв
на всю цепь, пустой слот пропускается); API `irq_chain_add`
(0/-1+ENOMEM), `irq_chain_remove(h)`; `irq_install` → обёртка
chain_add (EBUSY исчез), `irq_remove()` рвёт всю цепь; refcount
таблицы на первом/последнем слоте; мутации под IRQ_DISABLE.
All-modes W1-remap: трамплин копируется в W2 (`_irq_tramp_w2buf`,
copy-safe — только jr/djnz + литерал jp 0x0038), вокруг вызова
восстанавливает базовую W1-страницу (`_irq_app_w1_page` = IN 0xA2
при install). ПРОВЕРЕНО в MAME (tests/irqtest, 2 хендлера):
tiny/big/huge — chain 97=97 → remove h2 → 48/0; **huge = код в W1,
remap работает** (цепочка тикает синхронно). Дизайн:
docs/im2_isr_design.md.
FOLLOW-UP: (а) CTC-трамплин пока требует код в W2 → в small/huge
`irq_ctc_install` = EINVAL (нужна такая же W2-копия _irq_ctc_tramp);
(б) small для мелких программ (BSS в W1) → irq_install EINVAL
(safe; снять резервом area _IM2 в верхней W2).
- [ ] **(2) FPS-делитель (frame pacing)** — gfx_set_fps_div(n): логический
кадр = ровно n кадровых интервалов (50/25/16.7 fps), при
переполнении слота — выравнивание на ближайший фронт; счётчик
кадров через irq_install (только tiny/big в первой версии).
ПОЛНЫЙ ПЛАН: docs/sprite-api-design.md §9е (обсуждён 2026-07-14).
- [ ] **irq: цепочка обработчиков** (дизайн 2026-07-14, реализация по
потребности — понадобится, когда в программе сойдутся fps-делитель
+ свой тик/звук). Вместо одного слота (EBUSY) — фиксированный
массив `isr_t _irq_chain[IRQ_CHAIN_MAX /* 4 */]` в W2-data:
- трамплин вместо SMC-вызова одного handler'а обходит слоты
(load/or a/skip-NULL/call — пустой слот ~40Т, копейки на кадре);
- API: `irq_chain_add(h)` (0 / -1+ENOMEM когда слоты кончились),
`irq_chain_remove(h)` (по указателю; слот → NULL);
- совместимость: `irq_install(h)` становится обёрткой chain_add
(EBUSY исчезает), `irq_remove()` БЕЗ аргумента снимает ВСЮ цепь
и возвращает IM 1 — семантика exit/atexit сохранена;
- порядок вызова = порядок слотов; взаимный порядок хендлеров НЕ
гарантируется после remove/add (первая дыра) — хендлеры обязаны
быть независимы; дисциплина ISR прежняя (irq.h);
- CTC-цепочка (irq_ctc_*) — тем же паттерном, если понадобится.
кадров через irq_chain_add(_gfx_frame_isr) (только tiny/big в
первой версии). ПОЛНЫЙ ПЛАН: docs/sprite-api-design.md §9е
(обсуждён 2026-07-14; ограничение EBUSY снято цепочкой).
- [ ] **П6/железо**: MAME-смоук всех тестов после libc-сплита (conio,
ptime, stattest, mouse, gfx_demo/gfx_d16/gfx_text/gfx_mous —
трогался asm акселератора); затем прогон на реальном Sprinter