/*
 * irq_ctc_install — периодический user-таймер на CTC Z84C015
 * (каналы 2+3 в связке, вектор 0x06 — ОТДЕЛЬНЫЙ от кадрового 0xFF).
 *
 * Канал 2 тактируется видеотактом 875 кГц (1 тик = 1 знакоместо) и
 * работает делителем; канал 3 считает от канала 2 и генерирует
 * прерывание.  Частота = 875000 / (div2 * div3), div 0 = 256.
 * Пресет кадра: 112 * 160 (2 пиксельные линии * 160 = 320 линий) —
 * точное начало кадра ~48.8 Гц без примеси клавиатуры.
 *
 * Программирование (docs/samples/sprinterIntLib.asm, SIO_CTC_KEY.asm;
 * значения control-слов «надо читать доку по z84c15»):
 *   0x57 -> CH2, div2   — счётчик, без прерывания
 *   0xD7 -> CH3, div3   — счётчик, прерывание разрешено
 *   0x00 -> CH0         — базовый вектор блока CTC = 0 (ch3 -> 0x06)
 */

#include <errno.h>
#include "_irq.h"

static uint8_t ctc_div2;
static uint8_t ctc_div3;

static void ctc_program(void) __naked
{
    __asm
        ld    a, #0x57              ; CH2: counter, int off, TC следом
        out   (#_IRQ_CTC_CH2), a
        ld    a, (_ctc_div2)
        out   (#_IRQ_CTC_CH2), a
        ld    a, #0xD7              ; CH3: counter, int on, TC следом
        out   (#_IRQ_CTC_CH3), a
        ld    a, (_ctc_div3)
        out   (#_IRQ_CTC_CH3), a
        xor   a, a                  ; базовый вектор CTC = 0
        out   (#_IRQ_CTC_CH0), a
        ret
    __endasm;
}

int irq_ctc_install(isr_t handler, uint8_t div2, uint8_t div3)
{
    if (!handler) { errno = EINVAL; return -1; }
    if (_irq_ctc_user) { errno = EBUSY; return -1; }
    /* CTC-трамплин вектрится напрямую (table[0x06] = &_irq_ctc_tramp) в
     * обход W2-копии кадрового пути — поэтому CTC пока требует код в W2
     * (tiny/big).  All-modes для CTC (копия _irq_ctc_tramp) — follow-up. */
    if ((uint16_t)&_irq_ctc_tramp < 0x8000) { errno = EINVAL; return -1; }
    if (_irq_table_ref() != 0) return -1;

    uint16_t tramp = (uint16_t)&_irq_ctc_tramp;
    uint8_t *table = _irq_table();

    IRQ_DISABLE();
    _irq_ctc_user = handler;
    /* Вектор 0x06 — обычная (не same-byte) запись в таблицу. */
    table[0x06] = (uint8_t)(tramp & 0xFF);
    table[0x07] = (uint8_t)(tramp >> 8);
    ctc_div2 = div2;
    ctc_div3 = div3;
    ctc_program();
    IRQ_ENABLE();
    return 0;
}
