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:
+21
-13
@@ -900,19 +900,27 @@ Call-sites НЕ меняются: gfx_wait_vsync() один; n<=1 — СТАРЫ
|
||||
(данные; div=0/1 → старый путь; НЕ инициализировать).
|
||||
- common/_gfx_frame_isr.c — ISR: `_gfx_frame_tick++` (правила irq.h:
|
||||
без ESTEX/gfx/банков — здесь чистый инкремент).
|
||||
- common/gfx_set_fps_div.c — сеттер: n>=2 → irq_install(_gfx_frame_isr)
|
||||
(однократно; повторные вызовы только меняют div), n<=1 →
|
||||
irq_remove (если ставили) + div=1. Возврат 0 / -1+errno
|
||||
(EINVAL/EBUSY от irq_install). ТОЛЬКО этот модуль ссылается на
|
||||
irq-механику и ISR — DCE: программа без сеттера не тянет ничего
|
||||
(wait ссылается лишь на data-модуль).
|
||||
- common/gfx_set_fps_div.c — сеттер: n>=2 → irq_chain_add(_gfx_frame_isr)
|
||||
(ТАРГЕТНО свой слот; однократно, повторные вызовы только меняют div),
|
||||
n<=1 → irq_chain_remove(_gfx_frame_isr) (если ставили) + div=1.
|
||||
ВАЖНО: chain_remove, НЕ irq_remove — выключение делителя не должно
|
||||
снести собственный хендлер приложения (см. цепочку в
|
||||
docs/im2_isr_design.md). Возврат 0 / -1+errno (EINVAL — не tiny/big;
|
||||
ENOMEM — 4 слота заняты). ТОЛЬКО этот модуль ссылается на irq-механику
|
||||
и ISR — DCE: программа без сеттера не тянет ничего (wait ссылается
|
||||
лишь на data-модуль).
|
||||
- gfx_wait_vsync.c — ветка `if (_gfx_fps_div >= 2)` перед текущим
|
||||
поллингом.
|
||||
|
||||
### Ограничения (задокументировать в gfx.h)
|
||||
|
||||
1. irq_install работает ТОЛЬКО в tiny/big; в small/huge вернёт EINVAL
|
||||
→ gfx_set_fps_div(2+) там недоступен (rpgprof — small!). ПРИЧИНА
|
||||
→ gfx_set_fps_div(2+) там недоступен (rpgprof — small!). СНИМАЕТСЯ
|
||||
вариантом «все режимы» (docs/im2_isr_design.md «Вариант работает во
|
||||
всех режимах памяти», 2026-07-14): трамплин → W2-резидентный, хендлер
|
||||
остаётся в W1, трамплин восстанавливает статическую базовую W1-страницу
|
||||
приложения вокруг вызова (паттерн __banked). Тогда rpgprof (small)
|
||||
тоже получит делитель. ПРИЧИНА исходного ограничения
|
||||
(см. docs/im2_isr_design.md): IM2-таблица/трамплин/handler обязаны
|
||||
лежать по адресам, валидным в ЛЮБОЙ момент прихода прерывания —
|
||||
стабильно только W2 (стек обязан быть там по требованию DSS, окно
|
||||
@@ -929,12 +937,12 @@ Call-sites НЕ меняются: gfx_wait_vsync() один; n<=1 — СТАРЫ
|
||||
период кадра 896×320, дрейфа нет; фаза не привязана к лучу — разовая
|
||||
синхронизация поллингом фронта при установке). Делать по
|
||||
потребности.
|
||||
2. Один слот user-ISR: приложение со СВОИМ irq_install получит EBUSY
|
||||
от сеттера. Обход v1: приложение инкрементирует _gfx_frame_tick из
|
||||
своего обработчика и выставляет _gfx_fps_div напрямую (внутренние
|
||||
символы задокументировать); правильное решение — ЦЕПОЧКА
|
||||
обработчиков в libc/irq (дизайн записан в docs/TODO.md 2026-07-14,
|
||||
реализация по потребности).
|
||||
2. ~~Один слот user-ISR (EBUSY)~~ — СНЯТО цепочкой обработчиков: сеттер
|
||||
зовёт irq_chain_add, приложение со своим хендлером — тоже слот,
|
||||
оба тикают. Дизайн цепочки: docs/im2_isr_design.md «Цепочка
|
||||
кадровых обработчиков». Порядок реализации: цепочка → потом
|
||||
делитель поверх неё. (Осталось лишь: при 4 занятых слотах сеттер
|
||||
вернёт ENOMEM.)
|
||||
3. W0-атласы + IM2: прерывание при замапленном атласе идёт через
|
||||
IM2-таблицу приложения (W2) → чейн на 0x0038 = ISR-стаб страницы
|
||||
атласа → DSS. Путь совместим по построению, но ПРОВЕРИТЬ в MAME
|
||||
|
||||
Reference in New Issue
Block a user