- irq_ctc_install(handler, div2, div3) / irq_ctc_remove: канал 2 CTC
делит видеотакт 875 кГц (1 тик = 1 знакоместо), канал 3 считает от
него и прерывает; f = 875000/(div2*div3), div 0 = 256. Пресет
IRQ_CTC_VSYNC_DIV2/3 = 112*160 — точное начало кадра ~48.8 Гц БЕЗ
примеси клавиатуры (вектор 0x06 отделён от общего 0xFF)
- CTC-трамплин: полный сейв -> handler -> EI/RETI; RETI обязателен
(daisy chain Z84C015 снимает IUS только по опкоду RETI); к DSS не
чейнится — личное прерывание
- общая IM2-таблица под счётчиком ссылок (_irq_table.c): кадровый и
CTC-хендлеры независимы, последний unref возвращает I/IM 1;
atexit-уборка глушит CTC обязательно (иначе кГц-прерывания душат
шелл после выхода)
- порты/слова по docs/samples: CH0=0x10/CH2=0x12/CH3=0x13,
0x57/0xD7/вектор в CH0, стоп 0x03
- irqtest: CTC-vsync параллельно с кадровым + произвольная частота;
MAME: frame 48 Гц, ctc(vsync) 49 Гц (parallel frame жив),
ctc(50x50) 350 Гц точно по формуле, remove/выход чистые
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Проще исходного плана (docs/im2_isr_design.md обновлён): отдельный
--memory im2 не понадобился.
- <irq.h>: irq_install(handler) — вызов ~50 Гц только на КАДРОВЫХ
прерываниях (клавиатура bit0:0x19 и CBL bit7:0xFE отфильтровываются);
штатный обработчик DSS чейнится ВСЕГДА (SMC-jp, адрес из старой
IM2-таблицы по регистру I) — клавиатура/SYSTIME/мышь живут
- вектор-таблица: 513 Б BSS + runtime-выравнивание; Sprinter шлёт
только вектор 0xFF, поэтому jp-заглушка лежит внутри самой таблицы
по смещению H — без linker-областей и правок crt0
- трамплин: полный сейв обоих наборов+IX/IY вокруг user-handler'а
(ex af,af' как .db 0x08 — апостроф ломает препроцессор SDCC)
- tiny/big: работает (код в W2); small/huge: EINVAL по проверке
адресов; irq_remove идемпотентен и висит на atexit (выход без
снятия = I в памяти умершего процесса = крах шелла); old_I==0 → IM1
- tests/irqtest: тики за 3 с против time() (~50 Гц), живая клавиатура
под handler'ом, остановка после remove, чистый выход
- docs: im2_isr_design (статус+дельты), libc-reference (<irq.h>), TODO
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Регрессия от 961cfb7 (gsinit зануляет _DATA, 2026-07-04): crt0_banked
заполняет таблицу физических страниц _bank_pages ДО gsinit, а тот её
стирал — трамплины banked-вызовов читали нули и прыгали в незамапленную
страницу. Висли ВСЕ banked-программы (banked/bankedbg/banklocl/
banktest); найдено MAME-смоуком. Тот коммит перенёс crt0-приватные
_estex_* в _CODE, но _bank_pages в runtime/bank.s пропустил.
- runtime/bank.s: _bank_pages → .area _CODE (RAM, всегда замаплен —
это же условие нужно и трамплину); +16 Б _CODE у программ с bank.s
- app.mk: exe теперь зависит от runtime/*.s — правка crt0/bank.s
перелинковывает тесты без make clean (фикс иначе не подхватывался)
- эталон размеров обновлён (+16 Б у banked/bankedbg/banklocl/
banktest/openenv — size-check поймал ровно их)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- lib/Makefile: stale .rel удаляются сверкой списка модулей перед
упаковкой; штамп build/.modules триггерит перелинковку при любом
изменении состава исходников (при смене списка архив сносится —
на exFAT гранулярность mtime грубая, сравнение времён ненадёжно)
- top-level TESTS: все каталоги tests/ теперь собираются make all
(43 программы; banktest переименован из banked.exe — конфликт имён
с tests/banked); mdview2 добавлен в APPS
- размерный регресс: toolchain/size_check.py сверяет _CODE всех
программ с docs/size_baseline.tsv; make size-check / size-baseline
- заголовки: контракт затенения SDCC задокументирован в
docs/libc-headers.md; новый string.h (include_next + strlwr/strupr);
из sprinter_compat.h убраны макросы min/max — конфликтовали с
функциями из stdlib.h, и в Solid-C min/max тоже функции
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>