Files
Sprinter-SDCC/libc/time/sleep.c
T
snark13 46bd9ad0f1 gfx/time: vsync через polling бита кадра, sleep/delayms без halt-подсчёта
gfx_wait_vsync() и sleep() раньше предполагали, что КАЖДОЕ прерывание
на векторе 0xFF — кадровый тик; с CBL/клавиатурой на том же векторе
это уже не так.

gfx_wait_vsync(): вместо halt — polling бита 5 порта 0xFE (реальная
позиция луча, см. MAME kbd_fe_r), доступного пока включён CBL bit7
порта 0x004E. Разделяемое владение портом с CBL через
_cbl_port_ref/unref (тот же ref-counting паттерн, что у IM2-таблицы) —
cbl_close() возвращает "немой" режим вместо полного выключения, если
gfx ещё держит ссылку. Fallback на halt при таймауте.

sleep()/delayms(): калиброванный busy-wait по духу delayms.asm вместо
подсчёта halt-пробуждений. Калибровка одна на кадр (не на секунду —
не переполняет uint16_t и не требует умножения/32-бит арифметики),
общий движок libc/time/_sleep_calib.c для обеих функций. Fallback на
старое поведение при EBUSY (фрейм-хук занят другим irq_install()).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-08 10:47:57 +03:00

61 lines
2.4 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 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 <unistd.h>
#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);
}
}
}