/* * _irq_state — данные IM2-модуля. Только данные. * * Кадровый обработчик теперь ЦЕПОЧКА (_irq_chain[]) вместо одного слота * (см. docs/im2_isr_design.md «Цепочка кадровых обработчиков»). * * Всё, к чему трамплин обращается ВО ВРЕМЯ прерывания, обязано жить в * W2 (0x8000-0xBFFF) — единственное окно, которое DSS не перемапливает * (там стек). В tiny/big/huge вся BSS садится в W2 (code-loc W2 либо * data-loc 0x8000); в small для маленьких программ BSS может оказаться * в W1 — тогда _irq_table_ref вернёт EINVAL (safe). Полное снятие * этого ограничения (резерв area _IM2) — отдельный follow-up. */ #include "_irq.h" uint8_t _irq_vec_buf[_IRQ_VEC_BUF_SIZE]; /* Цепочка кадровых обработчиков. Пустой слот = NULL. Порядок вызова = * порядок индексов; после remove/add взаимный порядок НЕ гарантирован * (переиспользуется первая дыра) — хендлеры обязаны быть независимы. */ isr_t _irq_chain[IRQ_CHAIN_MAX]; uint8_t _irq_chain_n; /* число занятых слотов (быстрый выход) */ isr_t _irq_ctc_user; /* CTC-handler; NULL = нет */ isr_t _irq_cbl_hook; /* хук CBL-насоса; NULL = нет */ uint8_t _irq_old_i; /* I до захвата таблицы */ uint8_t _irq_refs; /* счётчик пользователей таблицы */ /* --- W1-remap для all-modes (см. трамплин) --------------------------- * В small/huge базовый код приложения в W1 (статическая страница). * Трамплин (в W2) вокруг вызова хендлеров восстанавливает эту страницу * в W1, чтобы хендлер, лежащий где угодно в плоском 0x4000-0xBFFF, был * адресуем; на выходе возвращает прочитанное на входе (что было — * возможно DSS-страница, если прервали сисколл). */ uint8_t _irq_app_w1_page; /* базовая W1-страница (IN 0xA2 при install) */ uint8_t _irq_saved_w1; /* W1 на входе в прерывание (для restore) */ /* W2-копия трамплина: в small/huge сам _irq_tramp лежит в W1-коде и в * момент прерывания может быть перемаплен — _irq_table_ref копирует его * байты сюда (BSS=W2) и направляет вектор на копию. В tiny/big копия не * нужна (трамплин уже в W2), буфер не используется. */ uint8_t _irq_tramp_w2buf[_IRQ_TRAMP_BUF_SIZE];