libbgi: idle-хук в ожидании кадра; им лечится потеря нажатий с Shift
Причина потерь (замеры — applications/PoP/roomtest/TASKS.md, KBD-1): при
зажатом Shift PS/2 обрамляет расширенный код «фиктивным шифтом», нажатие
стрелки становится 5 байтами вместо 2, а импульс запроса прерывания здесь
теряется примерно в 44 % случаев — трёхбайтовый FIFO SIO переполняется, и
байт пропадает ДО чтения порта. Лечится только плотным вычерпыванием: раз
в ~0.5 мс. Столько времени есть даром — при пейсинге «3 растровых кадра на
логический тик» процессор проводит ~42 мс из 60 в gfx_wait_vsync, крутя
опрос луча и больше ничего не делая.
- gfx_set_idle_hook(fn) — что вызывать, пока gfx_wait_vsync ждёт луч.
Состояние в отдельном data-модуле (_gfx_idle_state.c), чтобы не тянуть
сеттер в программы, которые хук не ставят.
- Лучевой цикл зовёт хук в обеих фазах. BC (счётчик таймаута)
сохраняется, косвенный вызов — push адреса возврата + jp (hl), так как
`call (hl)` в Z80 нет; без хука это ret по нулевому указателю, порядка
двух десятков тактов в цикле, который и так сжигает время.
- Путь FPS-делителя не затронут: там ожидание через HALT.
- roomtest вешает на хук kbd_raw_poll.
Проверка в MAME счётчиками (брейкпоинты с { b@ADDR = b@ADDR+1 ; g } на
чтении порта 0x18 и на установке make-бита): 35 нажатий Shift+Home → 35
make, ноль потерь; до фикса было 9 из 10. Боевой сценарий: четыре Shift+→
подряд дали четыре осторожных шага (Kid.x 114 -> 147). _CODE +170 Б,
кадровый бюджет не затронут.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -62,6 +62,7 @@ static void gfx_wait_vsync_beam(void)
|
||||
;; --- фаза 1: дождаться bit5==1 (гарантированно в blank) ---
|
||||
ld bc, #0 ; ~65536 попыток на фазу — таймаут
|
||||
_gwv_wait1:
|
||||
call _gwv_idle ; занять простой (см. gfx_set_idle_hook)
|
||||
in a, (#0xFE)
|
||||
bit 5, a
|
||||
jr nz, _gwv_have1
|
||||
@@ -75,6 +76,7 @@ static void gfx_wait_vsync_beam(void)
|
||||
;; --- фаза 2: дождаться bit5==0 (сам переход — начало кадра) ---
|
||||
ld bc, #0
|
||||
_gwv_wait0:
|
||||
call _gwv_idle
|
||||
in a, (#0xFE)
|
||||
bit 5, a
|
||||
jr z, _gwv_done
|
||||
@@ -83,6 +85,26 @@ static void gfx_wait_vsync_beam(void)
|
||||
or c
|
||||
jr nz, _gwv_wait0
|
||||
;; таймаут и здесь — переходим к тому же фолбэку
|
||||
jr _gwv_fallback
|
||||
|
||||
;; --- вызов idle-хука ------------------------------------- *
|
||||
;; BC (счётчик таймаута) сохраняем: хук — обычная C-функция и
|
||||
;; клобберит всё, кроме IX. Косвенный вызов через push адреса
|
||||
;; возврата + jp (hl): `call (hl)` в Z80 нет. Цена холостого
|
||||
;; прохода — около двух десятков тактов в цикле, который и так
|
||||
;; сжигает время впустую.
|
||||
_gwv_idle:
|
||||
ld hl, (__gfx_idle_hook)
|
||||
ld a, h
|
||||
or l
|
||||
ret z ; хук не поставлен
|
||||
push bc
|
||||
ld de, #_gwv_idle_ret
|
||||
push de ; адрес возврата для jp (hl)
|
||||
jp (hl)
|
||||
_gwv_idle_ret:
|
||||
pop bc
|
||||
ret
|
||||
|
||||
_gwv_fallback:
|
||||
ei
|
||||
|
||||
Reference in New Issue
Block a user