/* * irq.h — пользовательский обработчик кадрового прерывания (IM 2). * * Sprinter шлёт вектор 0xFF от трёх источников: кадр (50 Гц), * клавиатура (бит 0 порта 0x19), CBL/COVOX. Штатно DSS работает в * IM 1 (обработчик 0x0038). irq_install() переключает CPU в IM 2 со * своей таблицей и зовёт handler ТОЛЬКО на кадровых прерываниях; * после него (и на всех прочих источниках) управление всегда * передаётся штатному обработчику DSS на 0x0038 — клавиатура, * SYSTIME и курсор мыши продолжают работать. irq_remove() * возвращает IM 1/I как было (и вызывается автоматически из exit). * * ТРЕБОВАНИЕ ПАМЯТИ: код и данные программы должны быть в W2 * (0x8000-0xBFFF) — режимы tiny и big. В small/huge (CODE в W1) * irq_install вернёт -1/EINVAL: во время прерывания W1 может быть * перемаплен. Дизайн: docs/im2_isr_design.md. * * Правила для handler'а (вызывается ~50 раз/с, все регистры * сохраняются снаружи): * МОЖНО: volatile-глобалы, арифметика, короткая работа (<1 мс); * НЕЛЬЗЯ: ESTEX/BIOS-вызовы (printf/malloc/файлы), gfx_* и любой * своп W1/W3, акселератор, banked-функции, longjmp наружу. */ #ifndef IRQ_H #define IRQ_H #include typedef void (*isr_t)(void); /* Установить обработчик кадрового прерывания. * 0 — OK; -1 + errno: EBUSY (уже установлен), EINVAL (код/данные * не в W2 — неподходящий memory mode). */ int irq_install(isr_t handler); /* Снять обработчик и вернуть IM2-таблицу DSS. Безопасно звать * повторно; вызывается автоматически при exit(). */ void irq_remove(void); /* ---- CTC-таймер (Z84C015, вектор 0x06 — отдельный от кадрового) --- * * Канал 2 тактируется 875 кГц (1 тик = 1 знакоместо видеотракта) и * делит; канал 3 считает от канала 2 и прерывает. Частота handler'а: * f = 875000 / (div2 * div3), div 0 = 256 * (диапазон ~13 Гц .. десятки кГц; на частотах выше пары кГц handler * должен быть ОЧЕНЬ коротким). Ставится независимо от irq_install — * можно иметь оба. Ограничения для handler'а те же, что выше. * Обработчик завершается RETI (в трамплине) — daisy chain Z84C015. */ int irq_ctc_install(isr_t handler, uint8_t div2, uint8_t div3); void irq_ctc_remove(void); /* глушит CTC; тоже вызывается из exit() */ /* Пресет точного кадра: 112 тактов (2 пикс. линии) * 160 = 320 линий, * ~48.8 Гц, начало кадра — «vsync без примеси клавиатуры». */ #define IRQ_CTC_VSYNC_DIV2 112 #define IRQ_CTC_VSYNC_DIV3 160 /* Скобки для доступа main-кода к данным, разделяемым с ISR. */ #define IRQ_DISABLE() __asm__("di") #define IRQ_ENABLE() __asm__("ei") #endif