46bd9ad0f1
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>
61 lines
2.4 KiB
C
61 lines
2.4 KiB
C
/*
|
||
* 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);
|
||
}
|
||
}
|
||
}
|