Files
Sprinter-SDCC/libc/irq/_irq.h
T
snark13 2c6f4e33c3 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>
2026-07-15 10:23:39 +03:00

90 lines
5.0 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). С запасом над реальным размером трамплина (~150 Б). */
#define _IRQ_TRAMP_BUF_SIZE 224
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 */
/* Захватить/отпустить 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