/* * sleep — заблокироваться на N секунд калиброванным busy-wait'ом (см. * _sleep_calib.c — общий движок с delayms()). * * Старая версия (50 halt = 1 c) предполагала, что КАЖДОЕ прерывание — * кадровый тик 50 Гц; с CBL/клавиатурой на векторе 0xFF это неверно * (CBL может прерывать в разы/десятки раз чаще кадра — sleep() вернулся * бы намного раньше срока). * * sleep(seconds) — вложенный цикл: внешний по секундам, внутренний * ровно 50 раз калиброванный _sleep_spin() — та же структура, что и в * старой версии (внешний секунды, внутренний 50×halt), только вместо * halt — калиброванный спин. Umножения/32-бит арифметики нет. * * Fallback: если фрейм-хук уже занят другим irq_install()-клиентом * (EBUSY) — калибровку сделать некорректно, откатываемся к старому * "50 halt ~ 1 c" поведению для этого конкретного вызова. */ #include #include "_sleep_calib.h" /* Старое поведение — фолбэк, если calibrate() не может безопасно * получить кадровый хук. */ static void _sleep_legacy(unsigned int seconds) __naked { (void)seconds; __asm _slg_outer: ld a, h or l ret Z ld b, #50 ; 50 halt-ов ~ 1 c (при ЕДИНСТВЕННОМ ; источнике прерываний на векторе 0xFF) _slg_inner: halt djnz _slg_inner dec hl jr _slg_outer __endasm; } void sleep(unsigned int seconds) { if (seconds == 0) return; if (!_sleep_units_per_frame) _sleep_calibrate(); if (!_sleep_units_per_frame) { _sleep_legacy(seconds); return; } while (seconds--) { uint8_t frame = 50; /* 50 кадров ~ 1 с при 50 Гц */ while (frame--) { _sleep_spin(_sleep_units_per_frame); } } }