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:
@@ -193,3 +193,97 @@ _intWaitVsyncSys
|
||||
Если будем добавлять поддержку — делать это отдельным opt-in механизмом
|
||||
(по аналогии с banked-режимами), с обязательной обёрткой off/restore вокруг всех
|
||||
точек входа в систему.
|
||||
|
||||
---
|
||||
|
||||
## 8. Разбор двух предложений по спрайтовому движку (обсуждение 2026-07-14)
|
||||
|
||||
Итог двух обсуждений (эмуляция FastRAM в dev-MAME подтверждена
|
||||
разработчиками MAME как полная).
|
||||
|
||||
### 8.1. Предложение «W0/FastRAM как код-банк `__banked`»
|
||||
|
||||
Идея: выделить 1-2 FastRAM-страницы в crt0, научиться размещать в них
|
||||
`__banked`-код с целью W0 и контрактом «такой код не зовёт DSS/BIOS»;
|
||||
критичным функциям указывать размещение в W0/FastRAM.
|
||||
|
||||
**Framing правильный** (переиспользовать трамплин `__banked` +
|
||||
контракт), но W0-банк — НЕ «ещё один bank id», а тяжелее по трём осям:
|
||||
|
||||
1. **Своп W0 сносит всё окно 0 с RST-векторами** (ESTEX RST10, BIOS
|
||||
RST8, IM1 RST38, RST0). Пока FastRAM в W0: сисколлы невозможны (это
|
||||
и есть контракт — ок), но прерывание фатально (`#0038` → мусор
|
||||
FastRAM) → обязателен `DI` на весь интервал. `DI` бьёт ISR-счётчик
|
||||
кадров (см. FPS-делитель, [[sprite-engine-perf]]).
|
||||
2. **Загрузку нельзя сделать как в `crt0_banked`** (там `ESTEX READ`
|
||||
прямо в окно, строки 165-173): сам READ вектрится через W0. Нужен
|
||||
2-шаг — READ в DRAM-буфер, затем `DI` + FastRAM в W0 + **`LD`-копия**
|
||||
(акселератор с FastRAM не работает!) + выкл. Плюс FastRAM затирается
|
||||
запуском дочернего DSS-процесса — нужна перезагрузка.
|
||||
3. **16 КБ окно против 64 КБ**: кросс-страничные вызовы внутри FastRAM
|
||||
тянут вложенный W0-своп. Вызовы в W1/W2/W3 — свободны (те окна
|
||||
замаплены).
|
||||
|
||||
Плюс **пер-вызовная такса трамплина** (~40-60Т: DI/toggle/EI/restore)
|
||||
съедает выигрыш именно на горячих inner-листьях, которые от FastRAM
|
||||
выигрывают больше всего. Per-function `__banked` — неправильная
|
||||
гранулярность.
|
||||
|
||||
**Выгода** мала: FastRAM ускоряет только выборку инструкций. Из бюджета
|
||||
спрайта 19.5К (blit 9.7 + heal 6.4 + тик 3.0) blit и heal —
|
||||
акселератор/видео-ОЗУ, не выигрывают; выигрывает только тик+сорт по
|
||||
fetch: ~15-20К/кадр ≈ +1 спрайт (3-4% бюджета в самом узком месте).
|
||||
|
||||
**Рекомендация:** если вообще трогать — модель «горячий остров», а не
|
||||
«функция-в-банке»: одна 16-КБ FastRAM-страница с самодостаточным
|
||||
кластером (тик + сортировщик + их листья), вход один раз за кадр через
|
||||
единственную обёртку `DI / своп-в / вызов / своп-обратно / EI`, внутри
|
||||
острова обычные `call`, никаких RST. Убирает таксу, сводит связку с
|
||||
прерываниями к одному DI-интервалу на кадр (мы и так HALT-ждём между
|
||||
кадрами; ISR-счётчик кадров тикает во время HALT-ожидания ПОСЛЕ EI, а
|
||||
не во время острова → совместимо с FPS-делителем, пока остров < 1
|
||||
кадра).
|
||||
|
||||
### 8.2. Данные в FastRAM вместо кода?
|
||||
|
||||
Вывод неожиданный: **для нашей нагрузки данные — более СЛАБЫЙ рычаг,
|
||||
чем код.** Wait-state вставляется на КАЖДЫЙ доступ к DRAM, а на Z80
|
||||
большинство обращений к памяти — выборка инструкций, не операндов. Тик
|
||||
= IX-индексный код (`ld a,(ix+d)` — DD-префикс: 3 байта fetch + 1 байт
|
||||
данных) → ¾ штрафа на fetch, ¼ на операнде. Значит `sprite_t` в FastRAM
|
||||
убирает лишь ¼, а код тика — ¾.
|
||||
|
||||
По данным движка:
|
||||
- **Пиксели/атласы — жёсткое НЕТ** (их читает акселератор; с FastRAM не
|
||||
работает → блит откатился бы на LD-циклы).
|
||||
- **Массив `sprite_t` — не стоит:** тик его трогает, но выигрыш мал (см.
|
||||
выше), а хуже того — его читают и heal/blit под акселератор, которым
|
||||
нужна нормальная карта памяти. `sprite_t` в W0-FastRAM → весь
|
||||
`sprite_update` под `DI` + непроверенный вопрос «работает ли
|
||||
акселератор при W0=FastRAM». Не кандидат, пока это не подтверждено
|
||||
артефактом в MAME.
|
||||
- **Таблица Y-сорта + чисто-CPU скретч — да, но не отдельное решение:**
|
||||
живут в той же 16-КБ странице «горячего острова» с кодом сортировщика
|
||||
(сорт не трогает ни акселератор, ни сисколлы). Отдельного рычага
|
||||
«данные» тут нет.
|
||||
|
||||
**Единственный сильный независимый кейс для данных-в-FastRAM:**
|
||||
CPU-bound алгоритм с большим LUT случайного доступа (fetch внутреннего
|
||||
цикла крошечный, чтений таблицы — тьма). У движка такого нет (тяжёлая
|
||||
графика = акселератор). Но если добавим CPU-side эффект (программный
|
||||
per-pixel шейдинг, палитровый remap, софт-скейлер) — его LUT станет
|
||||
главным кандидатом на FastRAM-данные. На будущее.
|
||||
|
||||
**Ограничения именно для FastRAM-данных:** лежат в окне 0
|
||||
(#0000-#3FFF) → буфер под BIOS/ESTEX туда нельзя (нужно #4000-#BFFF);
|
||||
стек остаётся в W2; не переживают дочерний DSS-процесс; заполняются
|
||||
только `LD`-копией (акселератор мимо).
|
||||
|
||||
### 8.3. Общий вердикт
|
||||
|
||||
Оба варианта реализуемы, но бьют по 3-4% бюджета в самом узком месте
|
||||
(тик+сорт fetch), мимо доминирующих blit/heal. Остаётся **последним
|
||||
резервом** ([[fast_ram]] в памяти). Перед любой реализацией — дешёвый
|
||||
бенч в dev-MAME: один и тот же CPU-loop в DRAM vs FastRAM по
|
||||
`totalcycles`, чтобы измерить реальный коэффициент wait-state, который
|
||||
эмулятор моделирует, и подтвердить, что овчинка стоит выделки.
|
||||
|
||||
Reference in New Issue
Block a user