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:
Александр Петров
2026-08-01 15:33:16 +03:00
parent 774b1cc7c4
commit b56f2b4582
7 changed files with 299 additions and 9 deletions
+26 -9
View File
@@ -279,15 +279,32 @@ Quick wins:
- [ ] **kbd_raw: частые Rx-overrun в MAME при тапах** (roomtest,
2026-07-22) — замеры watchpoint-счётчиками: при стабильном
удержании клавиши overrun'ов ноль, но каждый быстрый тап (5 байт:
E0 74 + E0 F0 74 при FIFO 3) даёт overrun. Подозрение: dev-MAME
не эмулирует прерывание SIO на каждый принятый байт (байты
вычерпываются только кадровым IRQ 50 Гц) и/или подаёт пачку без
реальных ~1 мс/байт — на железе per-byte INT должен делать
overrun'ы редкостью. Проверить mame/sources/MAME/src/mame/
sinclair/sprinter.cpp (путь байта клавиатуры → INT) и при
желании поправить dev-MAME. Recovery-политика уже терпима к
частым overrun'ам (селективный wipe, docs/kbd-games.md), но
аккорд «держу →, тапнул ↑» остаётся уязвим.
E0 74 + E0 F0 74 при FIFO 3) даёт overrun.
**Уточнение 2026-08-01 (по коду драйвера, прежняя гипотеза
НЕВЕРНА):** dev-MAME per-byte INT ДАЁТ —
`mame/sources/MAME/src/mame/sinclair/sprinter.cpp`
`on_kbd_data()` ставит `m_irqs->in_set<1>()` на каждый принятый
байт. Но тут же заводит `m_irq_off_timer` на **32 такта CPU**, и
`irq_off()` снимает линию — то есть импульс, пришедшийся на наше
DI-окно, теряется НАСОВСЕМ (байт остаётся в FIFO до следующего
IRQ или кадрового 50 Гц). А DI-окна у нас длинные: ядра
акселератора держат `di` на весь блит (`libbgi/bgi256/
_bgi_blit_cols_raw.c`), это сотни микросекунд против 32 тактов.
**Замерено 2026-08-01 (PoP roomtest, счётчики в MAME): обе
«наши» гипотезы отпали.** (а) `kbd_raw_poll()` из главного цикла
не меняет ничего (9/10 с ним и без); (б) снятие `di` в accel-ядрах
УРОНИЛО машину — режим «акселератор при EI» тут недоступен; и сама
длина DI ни при чём (в замороженном кадре без блитов потерь
БОЛЬШЕ). Байт теряется ДО чтения порта: на 49 прочитанных байт
только 28 входов в клавиатурную ветку, т.е. ~44 % импульсов
запроса не обслужены и 3-байтовый FIFO переполняется. Главный
подозреваемый — `m_irq_off_timer` в sprinter.cpp: он ОДИН на два
источника (экран + клавиатура), `irq_off()` гасит обе линии, так
что кадровое прерывание способно обрезать клавиатурный импульс.
Полный протокол — applications/PoP/roomtest/TASKS.md, KBD-1.
Recovery-политика уже терпима к частым overrun'ам (селективный
wipe, docs/kbd-games.md), но аккорды «держу →, тапнул ↑» и
«держу Shift, тапаю ←» остаются уязвимы.
## Known quirks (зафиксированы, обходы в libc)