libc/kbd: kbd_raw_poll + замер потери нажатий при зажатом Shift (KBD-1)
Симптом: при удерживаемом Shift часть нажатий стрелок не отрабатывает
(~15 % по наблюдению пользователя), без Shift потерь нет.
Переведено в числа: нажимается Home — тоже расширенная клавиша (тот же
E0-префикс и тот же «fake shift»), но игрой игнорируется, поэтому рельеф
комнаты на результат не влияет. Счётчики — брейкпоинты MAME с действием
{ b@ADDR = b@ADDR+1 ; g } на входе клавиатурной ветки трамплина, на чтении
порта 0x18 и на установке make-бита.
Что измерено (10 нажатий Shift+Home, дошло make):
игра идёт, опрос ВКЛ 9/10 игра идёт, опрос ВЫКЛ 9/10
игра ЗАМОРОЖЕНА (блитов нет вообще, длинных DI нет) 8/10
Обе исходные гипотезы отпали:
- длина наших DI-окон ни при чём (в замороженном кадре потерь больше);
- снятие di в accel-ядрах libbgi УРОНИЛО машину — режим «акселератор при
EI» из docs/new/06-accel.md §6.6 в этой прошивке недоступен.
Байт теряется НИЖЕ нашего кода: на 49 прочитанных байт пришлось только 28
входов в клавиатурную ветку, то есть ~44 % импульсов запроса прерывания не
обслуживается и трёхбайтовый FIFO SIO переполняется.
Потолок приёма измерен отдельной программой tests/kbdpoll (ничего, кроме
kbd_raw_poll в цикле): 25 нажатий -> 25 make, 250 байт из 250, ноль потерь.
Значит опрос лечит полностью, вопрос только в плотности: нужно раз в
~0.5 мс, а шесть вызовов за 60-мс кадр давали раз в 10 мс.
Поэтому вызовы из roomtest.c УБРАНЫ (они стояли там, где прерывания и так
разрешены, и дублировали трамплин — 9/10 с ними и без). Сама функция
kbd_raw_poll оставлена в libc: она корректна и нужна как основа плотного
опроса. В заголовке и в libc-reference — честная оговорка, чтобы её не
ставили в игровой цикл «на всякий случай» без замера.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -57,6 +57,30 @@ uint8_t kbd_raw_down(uint16_t code);
|
||||
* «отваливался» при каждом overrun (см. kbd_raw_sync.c). */
|
||||
void kbd_raw_sync(void);
|
||||
|
||||
/* Вычерпать приёмный FIFO ОПРОСОМ, не дожидаясь прерывания. Возвращает
|
||||
* 0 (FIFO был пуст, ~40 тактов) или 1 (что-то вычерпано и декодировано в
|
||||
* ту же карту, что ведёт трамплин).
|
||||
*
|
||||
* Зачем: на каждый принятый байт запрос прерывания живёт единицы
|
||||
* микросекунд, и пропущенный импульс не «догоняется» — байт лежит в
|
||||
* 3-байтовом FIFO до следующего прерывания. Пачки в 5 байт (тап стрелки;
|
||||
* при зажатом Shift — ещё и «fake shift» вокруг расширенного кода) при
|
||||
* этом переполняют FIFO: теряется make («нажатие не сработало») или break
|
||||
* (залипание).
|
||||
*
|
||||
* ЧЕСТНАЯ ОГОВОРКА ПО ЭФФЕКТИВНОСТИ (замер 2026-08-01, PoP roomtest,
|
||||
* см. applications/PoP/roomtest/TASKS.md, KBD-1): расстановка «несколько
|
||||
* вызовов за кадр, после тяжёлых фаз» НЕ ДАЁТ НИЧЕГО — потери те же, что
|
||||
* без неё. Такие вызовы попадают в участки, где прерывания и так
|
||||
* разрешены, и лишь дублируют трамплин. Смысл появляется только у
|
||||
* ПЛОТНОГО опроса (в цикле ожидания, десятки-сотни раз за кадр), и это
|
||||
* ещё не подтверждено замером. Не ставить эту функцию в игровой цикл
|
||||
* «на всякий случай» — сначала померить.
|
||||
*
|
||||
* Тело идёт под DI и БЕЗУСЛОВНО делает EI на выходе: рассчитано на вызов
|
||||
* из главного цикла, из ISR звать нельзя. */
|
||||
uint8_t kbd_raw_poll(void);
|
||||
|
||||
#define KBD_EXT 0x0100 /* база кода была расширенной (0xE0-префикс) */
|
||||
|
||||
/* Позиционные коды PS/2 Set 2 — то, что реально нужно платформеру.
|
||||
|
||||
Reference in New Issue
Block a user