Files
Sprinter-SDCC/libc/irq/_irq.h
T
snark13 0280b05933 libc/kbd: held-карта клавиш в биты (512 -> 64 Б); эталон размеров принят
Разгрузка W1/W2 под будущий ИИ стражей: _kbdraw_down был БАЙТОМ на
скан-код (512 Б в _DATA при 32-килобайтной раскладке).  Теперь бит на
код: код>>3 = байт, код&7 = бит, расширенные (префикс 0xE0) — смещение
+32 байта вместо +256.

Трамплин прерывания строит маску СДВИГОМ, а не таблицей: таблица
потребовала бы `ld hl,#метка` внутри трамплина, а он копируется в W2
побайтно и обязан быть без абсолютных само-ссылок (см. его шапку).
Маска строится в BC, поэтому в клавиатурной ветке добавлен push/pop bc.
Трамплин вырос 244 -> 267 Б, буфер копии поднят 320 -> 336 (запас 69 Б).

Проверено в MAME на roomtest, все три класса клавиш:
  - обычные: '=' (обход комнат) и 'K' (чит-убийство стража — читал
    guardhp_curr/delta: 3/0 -> 0/-3);
  - расширенные (E0): стрелка вправо — Kid добежал до края комнаты;
  - модификаторы: удержание Shift ставит бит 2 байта 2 карты
    (скан-код 0x12), отпускание снимает.

Скорость: кадр 334 716 -> 338 508 тактов (+1.1 %) на битовой арифметике
в kbd_raw_down (~15 вызовов за кадр); при бюджете 430 000 это 0.79
периода вместо 0.78 — регрессии нет.

Итог по roomtest: данные 4422 -> 4022 Б, куча W2 996 -> 1294 Б.

Эталон размеров принят заново (make size-baseline): _CODE десяти
программ вырос на 14-23 Б — это код битовой арифметики в трамплине и
kbd_raw_down, обмен на -448 Б данных, которые size_check не считает.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 00:50:37 +03:00

96 lines
5.5 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* _irq.h — внутренности IM2-модуля (НЕ публичный заголовок).
*
* Механика (docs/im2_isr_design.md):
* - таблица векторов: 257 байт с выравниванием 256 внутри статического
* буфера 513 байт (_irq_state.c), заполняется байтом H = старший
* байт её же адреса; CPU по внешнему вектору 0xFF читает адрес
* (H<<8|H) — трёхбайтовый `jp _irq_tramp` лежит ВНУТРИ таблицы по
* смещению H (H < 0xC0 — с [0xFF]/[0x100] не пересекается; заливка
* H перехватывает и вектора SIO 0x10..0x1E, если их кто-то включит);
* - таблица общая для кадрового и CTC-хендлеров — жизнью управляет
* счётчик ссылок (_irq_table_ref/_irq_table_unref в _irq_table.c);
* unref последнего возвращает I и IM 1 (штатный режим DSS);
* - кадровый трамплин (_irq_tramp.c): AF-пробник порта 0x19 (SIO-A
* RR0, бит 0 = клавиатурный байт); кадр → полный save → user
* handler → restore; затем ВСЕГДА jp на обработчик DSS 0x0038
* (DSS работает в IM 1) — EI/RETI делает DSS;
* - CTC-трамплин (_irq_ctc_tramp.c): вектор 0x06 (Z84C015, каналы
* 2+3 в связке, база 875 кГц); полный save → handler → restore →
* EI/RETI — RETI ОБЯЗАТЕЛЕН (daisy chain: без него CTC не пошлёт
* следующее прерывание); к DSS НЕ чейнится (наше личное прерывание).
*/
#ifndef _IRQ_INTERNAL_H
#define _IRQ_INTERNAL_H
#include <stdint.h>
#include <irq.h>
/* Буфер под таблицу: 256 (выравнивание) + 257 (таблица). */
#define _IRQ_VEC_BUF_SIZE (256 + 257)
/* Буфер под W2-копию кадрового трамплина (small/huge — _irq_tramp в
* W1). С запасом над реальным размером трамплина (267 Б после
* упаковки held-карты клавиатуры в биты, 2026-07-30 — проверять
* __irq_tramp_end при правках, запас держать >= 60 Б). */
#define _IRQ_TRAMP_BUF_SIZE 336
extern uint8_t _irq_vec_buf[_IRQ_VEC_BUF_SIZE];
/* Цепочка кадровых обработчиков (см. _irq_state.c, docs/im2_isr_design). */
extern isr_t _irq_chain[IRQ_CHAIN_MAX];
extern uint8_t _irq_chain_n; /* число занятых слотов */
extern isr_t _irq_ctc_user; /* CTC-handler; NULL = нет */
extern uint8_t _irq_old_i; /* I до захвата таблицы */
extern uint8_t _irq_refs; /* счётчик пользователей таблицы */
/* W1-remap (all-modes): базовая W1-страница приложения + сохранённая
* страница на входе в прерывание; W2-копия трамплина. */
extern uint8_t _irq_app_w1_page;
extern uint8_t _irq_saved_w1;
extern uint8_t _irq_tramp_w2buf[_IRQ_TRAMP_BUF_SIZE];
/* Порт-регистр окна W1 (страница). */
#define _IRQ_W1_PORT 0xA2
/* Хук CBL-насоса (libc/cbl регистрирует _cbl_pump). Косвенность
* сознательная: прямая ссылка трамплина на cbl-модуль притянула бы
* его (и 2 КБ кольца) в каждую irq-программу. NULL = CBL выключен,
* трамплин НЕ проверяет бит 7 порта 0xFE (он подтянут к 1). */
extern isr_t _irq_cbl_hook;
/* Порты встроенной периферии Z84C015 (docs/samples/SIO_CTC_KEY.asm). */
#define _IRQ_CTC_CH0 0x10
#define _IRQ_CTC_CH2 0x12
#define _IRQ_CTC_CH3 0x13
#define _IRQ_SIO_A 0x19 /* SIO-A RR0: бит 0 = Rx available */
#define _IRQ_SIO_DATA 0x18 /* SIO-A data — деструктивное чтение
* (дренирует байт); читает либо DSS
* (штатно), либо raw-канал клавиатуры
* (libc/kbd/_kbdraw.h), но не оба сразу */
/* Захватить/отпустить IM2-таблицу (счётчик ссылок). ref: при первом
* захвате строит таблицу, ставит I/IM2, взводит atexit-уборку;
* 0 или -1+errno (EINVAL — код/буфер не в W2). unref: при последнем
* отпускании возвращает I и IM 1. */
int _irq_table_ref(void);
void _irq_table_unref(void);
/* Адрес выровненной таблицы (валиден при _irq_refs > 0). */
uint8_t *_irq_table(void);
/* Входы трамплинов (asm). */
void _irq_tramp(void);
void _irq_ctc_tramp(void);
/* Метка конца кадрового трамплина — для вычисления его размера при
* копировании в W2 (_irq_table_ref). Объявлена как массив, чтобы
* можно было взять адрес без вызова. */
extern uint8_t _irq_tramp_end[];
/* SMC-операнд `jp` на обработчик DSS (метка в _irq_tramp.c). */
extern uint16_t _irq_dss_target;
#endif