/* * irqtest — smoke-тест IM2-модуля (Phase 1+2, docs/im2_isr_design.md). * * Проверяет: * 1. кадровый handler тикает ~50 Гц (сверка с time() за 3 секунды); * 1b. цепочка: второй обработчик (irq_chain_add) тикает синхронно с * первым; irq_chain_remove снимает только его, первый жив; * 2. клавиатура/SYSTIME живы при установленном handler'е (чейн к DSS); * 3. CTC-таймер (вектор 0x06): пресет vsync ~49 Гц ОДНОВРЕМЕННО с * кадровым; затем быстрый режим 875 кГц/(50*50) = 350 Гц; * 4. irq_remove/irq_ctc_remove останавливают тики; * 5. чистый выход в шелл (I/IM восстановлены, CTC заглушен). */ #include #include #include #include #include static volatile uint16_t ticks; static volatile uint16_t ticks2; static volatile uint16_t ctc_ticks; static void on_tick(void) { ticks++; } static void on_tick2(void) { ticks2++; } static void on_ctc(void) { ctc_ticks++; } /* Диагностика: регистр I до установки (что за режим у DSS?). */ static uint8_t get_i(void) __naked { __asm ld a, i ret __endasm; } /* Busy-пауза без единого ESTEX-вызова (~симв. полсекунды). */ static void busy_wait(void) { for (volatile uint16_t i = 0; i < 30000u; i++) ; } /* Атомарное чтение 16-битного счётчика, разделяемого с ISR. */ static uint16_t read_ticks(void) { uint16_t v; IRQ_DISABLE(); v = ticks; IRQ_ENABLE(); return v; } int main(void) { /* --- диагностика ДО установки --- */ uint8_t old_i = get_i(); const uint8_t *vec = (const uint8_t *)(((uint16_t)old_i << 8) + 0xFF); printf("I=%02x, [I:FF]=%02x%02x (DSS isr cand: %04x)\n", old_i, vec[1], vec[0], (unsigned)(vec[0] | ((uint16_t)vec[1] << 8))); if (irq_install(on_tick) != 0) { printf("irq_install failed: errno=%d\n", errno); return 1; } puts("irq installed"); /* Фаза 1: busy-пауза БЕЗ ESTEX — жив ли трамплин/чейн вообще. */ busy_wait(); printf("phase1: ticks=%u (expect >0)\n", read_ticks()); puts("phase2: measuring 3 s vs time()..."); /* Выровняться на границу секунды (time() зовёт ESTEX SYSTIME в * цикле — заодно стресс чейна к DSS). */ time_t t0 = time(0); while (time(0) == t0) ; uint16_t start = read_ticks(); time_t t1 = time(0); while (time(0) < t1 + 3) ; uint16_t got = read_ticks() - start; printf("ticks: %u in 3 s (~%u Hz, expect ~50)\n", got, got / 3); /* --- Phase 1b: цепочка — второй кадровый обработчик --- */ if (irq_chain_add(on_tick2) != 0) { printf("chain_add failed: errno=%d\n", errno); return 1; } puts("chain: 2nd handler added"); { IRQ_DISABLE(); uint16_t a0 = ticks, b0 = ticks2; IRQ_ENABLE(); time_t tc = time(0); while (time(0) < tc + 2) ; IRQ_DISABLE(); uint16_t da = ticks - a0, db = ticks2 - b0; IRQ_ENABLE(); printf("chain both: h1=%u h2=%u in 2 s (both ~100, must match)\n", da, db); } /* Снять ТОЛЬКО второй — первый обязан продолжать тикать. */ irq_chain_remove(on_tick2); { IRQ_DISABLE(); uint16_t a0 = ticks, b0 = ticks2; IRQ_ENABLE(); time_t tc = time(0); while (time(0) < tc + 1) ; IRQ_DISABLE(); uint16_t da = ticks - a0, db = ticks2 - b0; IRQ_ENABLE(); printf("chain after remove h2: h1=%u (>0) h2=%u (must be 0)\n", da, db); } /* --- Phase 2: CTC-таймер одновременно с кадровым --- */ if (irq_ctc_install(on_ctc, IRQ_CTC_VSYNC_DIV2, IRQ_CTC_VSYNC_DIV3)) { printf("irq_ctc_install failed: errno=%d\n", errno); return 1; } { time_t t3 = time(0); while (time(0) == t3) ; IRQ_DISABLE(); uint16_t c0 = ctc_ticks, f0 = ticks; IRQ_ENABLE(); time_t t4 = time(0); while (time(0) < t4 + 2) ; IRQ_DISABLE(); uint16_t dc = ctc_ticks - c0, df = ticks - f0; IRQ_ENABLE(); printf("ctc(vsync): %u in 2 s (~%u Hz), frame in parallel: %u\n", dc, dc / 2, df); } irq_ctc_remove(); /* CTC на произвольной частоте: 875000/(50*50) = 350 Гц. */ if (irq_ctc_install(on_ctc, 50, 50)) { printf("ctc fast install failed: errno=%d\n", errno); return 1; } { time_t t5 = time(0); while (time(0) == t5) ; IRQ_DISABLE(); uint16_t c0 = ctc_ticks; IRQ_ENABLE(); time_t t6 = time(0); while (time(0) < t6 + 2) ; IRQ_DISABLE(); uint16_t dc = ctc_ticks - c0; IRQ_ENABLE(); printf("ctc(50x50): %u in 2 s (~%u Hz, expect ~350)\n", dc, dc / 2); } irq_ctc_remove(); puts("press any key (keyboard must work)..."); getch(); irq_remove(); uint16_t frozen = read_ticks(); time_t t2 = time(0); while (time(0) < t2 + 1) ; if (read_ticks() == frozen) puts("remove: ticks frozen, OK"); else puts("remove: FAIL, still ticking"); puts("irqtest done."); return 0; }