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>
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* _sleep_calib.h — внутренности калиброванного busy-wait, общие для
|
||||
* sleep() и delayms() (НЕ публичный заголовок).
|
||||
*
|
||||
* Калибровка лениво запускается ПЕРВЫМ вызовом sleep() ИЛИ delayms() —
|
||||
* если программа не зовёт ни одну из них, весь этот код даже не
|
||||
* линкуется (DCE по модулям). См. sleep_redesign / delayms в памяти.
|
||||
*/
|
||||
#ifndef _SLEEP_CALIB_INTERNAL_H
|
||||
#define _SLEEP_CALIB_INTERNAL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Итераций тесного цикла на ОДИН кадр (~20 мс @ 50 Гц); 0 = ещё не
|
||||
* откалибровано (или калибровка не удалась — irq_install занят). */
|
||||
extern uint16_t _sleep_units_per_frame;
|
||||
|
||||
/* Итераций на 1 мс — производное от _sleep_units_per_frame/20,
|
||||
* вычисляется один раз при калибровке (одно 16-битное деление на
|
||||
* константу, НЕ умножение и НЕ 32 бита). */
|
||||
extern uint16_t _sleep_units_per_ms;
|
||||
|
||||
/* Один раз откалиброваться против реального кадрового тика; при
|
||||
* неудаче (EBUSY — фрейм-хук занят другим irq_install()-клиентом)
|
||||
* оставляет оба поля в 0 — вызывающий берёт свой fallback. */
|
||||
void _sleep_calibrate(void);
|
||||
|
||||
/* Прогнать units итераций тесного цикла — чистый busy-wait. */
|
||||
void _sleep_spin(uint16_t units);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user