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:
@@ -57,22 +57,32 @@ const uint8_t n_banks = 4;
|
||||
/* Режим читов (pop_cheat.h): на время разработки включаем в main. */
|
||||
uint8_t pop_cheats;
|
||||
|
||||
/* ПОТЕРЯ НАЖАТИЙ ПРИ ЗАЖАТОМ Shift — НЕ ЧИНИТСЯ ИЗ ЭТОГО ЦИКЛА.
|
||||
/* ПОТЕРЯ НАЖАТИЙ ПРИ ЗАЖАТОМ Shift — лечится ПЛОТНЫМ опросом клавиатуры.
|
||||
*
|
||||
* Здесь стояли шесть вызовов kbd_raw_poll() (вычерпать FIFO клавиатуры
|
||||
* после каждой тяжёлой фазы кадра). Убраны: замерено, что они не меняют
|
||||
* НИЧЕГО — 9 дошедших make-байт из 10 нажатий и с ними, и без них. Они
|
||||
* стояли ровно там, где прерывания и так разрешены, то есть добавляли то,
|
||||
* что трамплин делает сам.
|
||||
* При зажатом Shift PS/2 обрамляет расширенный код «фиктивным шифтом», и
|
||||
* одно нажатие стрелки превращается в 5 байт вместо 2 (отпускание — тоже
|
||||
* 5). Приёмный FIFO SIO — 3 байта, а импульс запроса прерывания здесь
|
||||
* теряется примерно в 44 % случаев, поэтому байты копятся и один из
|
||||
* полусотни пропадает ДО чтения порта: нажатие «не срабатывает».
|
||||
*
|
||||
* Настоящая причина лежит НИЖЕ нашего кода: при зажатом Shift PS/2 шлёт на
|
||||
* расширенную клавишу вдвое больше байт («fake shift»), а импульс запроса
|
||||
* прерывания пропускается примерно в 44 % случаев — байты копятся в
|
||||
* трёхбайтовом FIFO SIO и один из полусотни теряется ДО чтения порта.
|
||||
* Длина наших DI-окон ни при чём: в замороженном кадре, где блитов нет
|
||||
* вообще, потерь БОЛЬШЕ, а не меньше.
|
||||
* Что НЕ помогает (замерено, TASKS.md/KBD-1): редкий опрос (несколько
|
||||
* вызовов за кадр — они попадают туда, где прерывания и так разрешены, и
|
||||
* лишь дублируют трамплин) и укорачивание DI-окон графики (в кадре вообще
|
||||
* без блитов потерь БОЛЬШЕ). Снимать `di` в accel-ядрах нельзя — машина
|
||||
* уходит в перезагрузку.
|
||||
*
|
||||
* Полный протокол замеров и куда копать дальше — TASKS.md, KBD-1. */
|
||||
* Что помогает: опрос раз в ~0.5 мс. Столько времени берётся из ожидания
|
||||
* кадра — процессор всё равно крутит там ~42 мс из 60, ничего не делая.
|
||||
* Поэтому kbd_raw_poll вешается idle-хуком на gfx_wait_vsync (см.
|
||||
* kbd_idle ниже); полезной работы это не отнимает. Потолок приёма
|
||||
* подтверждён отдельно (tests/kbdpoll: 25 нажатий → 25, 250 байт из 250). */
|
||||
|
||||
/* Обёртка ради типа: хук — void(*)(void), а kbd_raw_poll возвращает
|
||||
* «было ли что вычерпано». Приводить указатель кастом не хочется. */
|
||||
static void kbd_idle(void)
|
||||
{
|
||||
kbd_raw_poll();
|
||||
}
|
||||
|
||||
/* seq_2_stand (types.h seqids) — Kid стоит, ждёт ввода. */
|
||||
#define SEQ_STAND 2
|
||||
@@ -317,6 +327,7 @@ int main(void)
|
||||
puts("kbd_raw open failed");
|
||||
return 1;
|
||||
}
|
||||
gfx_set_idle_hook(kbd_idle); /* вычерпывать FIFO, пока ждём кадр */
|
||||
|
||||
while (!kbd_raw_down(KBD_ESC)) {
|
||||
/* SPACE — тумблер дабл-буфера (edge, чтоб одно нажатие = один
|
||||
@@ -583,6 +594,7 @@ int main(void)
|
||||
}
|
||||
}
|
||||
|
||||
gfx_set_idle_hook(0); /* снять хук ДО закрытия raw-канала */
|
||||
pop_ctrl_close();
|
||||
closegraph();
|
||||
pop_bg_free();
|
||||
|
||||
Reference in New Issue
Block a user