irq: фикс Phase 1 после отладки — DSS работает в IM 1, чейн всегда на 0x0038
Первая версия висла на первом прерывании. Две причины (verified по docs/samples/sprinterIntLib.asm, SIO_CTC_KEY.asm и исходникам MAME): - DSS работает в IM 1 (обработчик 0x0038); I=0x3F — наследие Spectrum ROM, НЕ таблица: чтение [I<<8|0xFF] давало мусор (0x00BF) и прыжок в никуда. Чейн из трамплина теперь ВСЕГДА jp 0x0038 (interrupted-PC на стеке = имитация RST 38); irq_remove безусловно восстанавливает IM 1 - CBL-фильтр по биту 7 порта 0xFE убран: при выключенном CBL бит подтянут к 1 (MAME kbd_fe_r: data |= 0xE0) — каждый кадр ложно уходил в чейн, user-handler не вызывался бы. Вернуть в Phase 2 вместе с поддержкой CBL Попутно подтверждено: порт 0x19 = SIO-A RR0 (Z84C015), бит 0 = Rx Available; вектора встроенной периферии SIO 0x10..0x1E / CTC 0x06 (заливка 257×H ловит любые); внешний вектор 0xFF. irqtest: диагностика I до установки + фаза без ESTEX; прогон в MAME: ~49 Гц, клавиатура жива, remove останавливает тики, чистый выход. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+43
-13
@@ -1,27 +1,57 @@
|
||||
# IM2 Interrupt Handlers — Design Document
|
||||
|
||||
**Status: Phase 1 РЕАЛИЗОВАН 2026-07-06** (libc/irq: irq_install/
|
||||
irq_remove + трамплин; тест tests/irqtest). Отличия реализации от
|
||||
плана ниже:
|
||||
**Status: Phase 1 РЕАЛИЗОВАН 2026-07-06, ИСПРАВЛЕН после отладки**
|
||||
(libc/irq: irq_install/irq_remove + трамплин; тест tests/irqtest).
|
||||
|
||||
## Результаты verification (2026-07-06, по docs/samples и исходникам MAME)
|
||||
|
||||
Первая версия зависала на первом же прерывании после irq_install.
|
||||
Причины и проверенные факты:
|
||||
|
||||
- **DSS работает в IM 1** (обработчик на 0x0038). I=0x3F — наследие
|
||||
Spectrum ROM, НЕ признак IM 2-таблицы. Доказательства:
|
||||
`docs/samples/sprinterIntLib.asm` (intRestoreDefaultInterrupt: `ld i,a`
|
||||
+ `im 1` безусловно, «обязательно перед функциями дос и биос») и
|
||||
`docs/samples/SIO_CTC_KEY.asm` (выход: `LD I,A` + `IM 1`). Чтение
|
||||
«таблицы DSS» по [I<<8+0xFF] давало мусор (0x00BF) и было причиной
|
||||
зависания. Фикс: чейн из трамплина ВСЕГДА на 0x0038 (jp с
|
||||
interrupted-PC на стеке = имитация RST 38); irq_remove всегда
|
||||
восстанавливает IM 1 (I — только регистр).
|
||||
- **CBL-фильтр по биту 7 порта 0xFE убран из трамплина**: в MAME при
|
||||
выключенном CBL бит 7 всегда = 1 (sprinter.cpp kbd_fe_r:
|
||||
`data |= 0xE0`), и каждое кадровое прерывание ложно классифицировалось
|
||||
как CBL — user-handler не вызывался бы никогда. Признак «#fe.bit7=1»
|
||||
(sprinterIntLib.asm) имеет смысл только при активном CBL — вернуть в
|
||||
Phase 2 вместе с поддержкой CBL.
|
||||
- **Порт 0x19 = SIO-A RR0 (Z84C015), бит 0 = «Rx Character Available»** —
|
||||
семантика клавиатурного пробника верна (подтверждено
|
||||
sprinterIntLib.asm: `in a,(COM_A); bit 0,a; Z → кадровое`).
|
||||
- **Вектора встроенной периферии Z84C015**: SIO — 0x10..0x1E, CTC — 0x06
|
||||
(базовые вектора задаются записью в WR2 SIO-B / CTC ch0). Штатно их
|
||||
прерывания выключены (сэмплы включают/выключают их сами); наша
|
||||
заливка 257×H перехватывает любой вектор на трамплин, а чейн на
|
||||
0x0038 безопасен для любого источника.
|
||||
- Внешний вектор действительно 0xFF (MAME sprinter.cpp:
|
||||
`set_irq_acknowledge_callback` → 0xff).
|
||||
|
||||
Отличия реализации от плана ниже:
|
||||
|
||||
- **отдельный `--memory im2` НЕ понадобился**: таблица — статический
|
||||
буфер 513 Б в BSS с выравниванием в рантайме; т.к. Sprinter шлёт
|
||||
только вектор 0xFF, значимы лишь байты [0xFF]/[0x100], и 3-байтовый
|
||||
буфер 513 Б в BSS с выравниванием в рантайме; т.к. внешний вектор —
|
||||
только 0xFF, значимы лишь байты [0xFF]/[0x100], и 3-байтовый
|
||||
`jp _irq_tramp` лежит ВНУТРИ таблицы по смещению H (H = старший
|
||||
байт её адреса, < 0xC0 — не пересекается). Никаких linker-областей
|
||||
и правок crt0;
|
||||
- работает в tiny/big (код и данные в W2); в small/huge irq_install
|
||||
возвращает EINVAL (проверка адресов трамплина/буфера);
|
||||
- **чейн к DSS — ВСЕГДА** (и клавиатура, и кадр, и CBL): не нужно
|
||||
знать, что DSS делает в своём ISR — SYSTIME/клавиатура/мышь живут.
|
||||
User-handler зовётся только на кадровых (фильтр: бит 0 порта 0x19,
|
||||
бит 7 порта 0xFE → мимо); финальный jp — SMC-операнд;
|
||||
- **чейн к DSS — ВСЕГДА и всегда на 0x0038** (и клавиатура, и кадр):
|
||||
не нужно знать, что DSS делает в своём ISR — SYSTIME/клавиатура/мышь
|
||||
живут. User-handler зовётся только на кадровых (фильтр: бит 0
|
||||
порта 0x19 → мимо); финальный jp — SMC-операнд;
|
||||
- W3-порт в трамплине НЕ сохраняется: gfx держит DI на время свопов,
|
||||
а user-handler'у banking запрещён; DSS свои окна сохраняет сам;
|
||||
- irq_remove вешается на atexit (выход без снятия = I указывает в
|
||||
память умершего процесса = крах шелла); old_I==0 → восстановление IM 1;
|
||||
- открытые вопросы 1 (что делает DSS ISR) и 2 (ld a,i) сняты
|
||||
дизайном «всегда чейн» и безусловным EI.
|
||||
- irq_remove вешается на atexit (выход без снятия = IM 2/I указывают в
|
||||
память умершего процесса = крах шелла); восстановление — всегда IM 1.
|
||||
|
||||
Phase 2 (CBL/COVOX handler, ISA, цепочка нескольких хендлеров) — ниже
|
||||
по плану, не реализовано.
|
||||
|
||||
Reference in New Issue
Block a user