/*
 * _irq_tramp — вход IM2-прерывания (вектор 0xFF: кадр/клавиатура/CBL).
 *
 * До выяснения источника трогаем только AF:
 *  - клавиатура (бит 0 порта 0x19 = SIO-A RR0 «Rx Character
 *    Available») уходит напрямую в DSS;
 *  - CBL (бит 7 порта 0xFE) проверяется ТОЛЬКО при зарегистрированном
 *    хуке _irq_cbl_hook: при выключенном CBL бит подтянут к 1 (MAME
 *    kbd_fe_r: data |= 0xE0) и проверка ложно срабатывала бы на
 *    каждом кадре.  CBL-путь: полный сейв → насос → restore →
 *    EI/RETI, к DSS НЕ чейнится (личное прерывание);
 *  - кадровое: полный сейв → user-handler → restore → чейн.
 *
 * Чейн — ВСЕГДА jp на обработчик DSS 0x0038 (DSS работает в IM 1;
 * jp с interrupted-PC на стеке имитирует RST 38) — он делает свой
 * save/restore и завершает EI/RETI: клавиатурный FIFO, SYSTIME и
 * курсор мыши живут.
 *
 * Операнд финального jp (_irq_dss_target) — SMC, патчится из
 * _irq_table_ref; модуль в _CODE (RAM на Sprinter, W2 в tiny/big).
 */

#include "_irq.h"

void _irq_tramp(void) __naked
{
    __asm
        push  af
        in    a, (#0x19)
        rrca                        ; бит 0 — клавиатурный байт принят?
        jr    C, _irq_chain

        ;; --- CBL? --- старший байт хука ненулевой у любого
        ;; W2-адреса — для проверки «хук есть» хватает одного байта.
        ld    a, (__irq_cbl_hook + 1)
        or    a, a
        jr    Z, _irq_frame
        in    a, (#0xFE)
        rlca                        ; бит 7 — запрос блока CBL?
        jr    NC, _irq_frame

        ;; --- CBL: сейв, насос, restore, EI/RETI (без DSS) ---
        push  bc
        push  de
        push  hl
        .db   0x08                  ; ex af,af (теневой AF)
        push  af
        exx
        push  bc
        push  de
        push  hl
        push  ix
        push  iy
        ld    hl, (__irq_cbl_hook)
        call  _irq_call_hl
        pop   iy
        pop   ix
        pop   hl
        pop   de
        pop   bc
        exx
        pop   af
        .db   0x08                  ; ex af,af (теневой AF)
        pop   hl
        pop   de
        pop   bc
        pop   af
        ei
        reti

    _irq_frame:
        ;; --- кадровое прерывание ---
        push  bc
        push  de
        push  hl
        ld    hl, (__irq_user)
        ld    a, h
        or    a, l
        jr    Z, _irq_pop3          ; handler не установлен

        ;; Сохранить теневой набор и индексные — user-код клобберит всё.
        .db   0x08                  ; ex af,af (теневой AF)
        push  af
        exx
        push  bc
        push  de
        push  hl
        push  ix
        push  iy

        ld    hl, (__irq_user)
        call  _irq_call_hl

        pop   iy
        pop   ix
        pop   hl
        pop   de
        pop   bc
        exx
        pop   af
        .db   0x08                  ; ex af,af (теневой AF)
    _irq_pop3:
        pop   hl
        pop   de
        pop   bc
    _irq_chain:
        pop   af
        ;; Всегда к DSS (IM 1, обработчик 0x0038) — EI/RETI за ним.
        .db   0xC3                  ; jp nn
    __irq_dss_target::
        .dw   0x0038                ; SMC: подтверждается в _irq_table_ref

    _irq_call_hl:
        jp    (hl)
    __endasm;
}
