Files
Sprinter-SDCC/libc/kbd/kbd_raw_sync.c
T
snark13 0280b05933 libc/kbd: held-карта клавиш в биты (512 -> 64 Б); эталон размеров принят
Разгрузка W1/W2 под будущий ИИ стражей: _kbdraw_down был БАЙТОМ на
скан-код (512 Б в _DATA при 32-килобайтной раскладке).  Теперь бит на
код: код>>3 = байт, код&7 = бит, расширенные (префикс 0xE0) — смещение
+32 байта вместо +256.

Трамплин прерывания строит маску СДВИГОМ, а не таблицей: таблица
потребовала бы `ld hl,#метка` внутри трамплина, а он копируется в W2
побайтно и обязан быть без абсолютных само-ссылок (см. его шапку).
Маска строится в BC, поэтому в клавиатурной ветке добавлен push/pop bc.
Трамплин вырос 244 -> 267 Б, буфер копии поднят 320 -> 336 (запас 69 Б).

Проверено в MAME на roomtest, все три класса клавиш:
  - обычные: '=' (обход комнат) и 'K' (чит-убийство стража — читал
    guardhp_curr/delta: 3/0 -> 0/-3);
  - расширенные (E0): стрелка вправо — Kid добежал до края комнаты;
  - модификаторы: удержание Shift ставит бит 2 байта 2 карты
    (скан-код 0x12), отпускание снимает.

Скорость: кадр 334 716 -> 338 508 тактов (+1.1 %) на битовой арифметике
в kbd_raw_down (~15 вызовов за кадр); при бюджете 430 000 это 0.79
периода вместо 0.78 — регрессии нет.

Итог по roomtest: данные 4422 -> 4022 Б, куча W2 996 -> 1294 Б.

Эталон размеров принят заново (make size-baseline): _CODE десяти
программ вырос на 14-23 Б — это код битовой арифметики в трамплине и
kbd_raw_down, обмен на -448 Б данных, которые size_check не считает.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-30 00:50:37 +03:00

51 lines
2.8 KiB
C

/*
* kbd_raw_sync.c — восстановление held-состояния после Rx-overrun SIO.
*
* Аппаратный приёмный FIFO SIO — 3 байта. Если прерывания запрещены
* достаточно долго (DI-окна графики/кадрового IRQ), а в этот момент
* приходит пачка скан-кодов (напр. быстрый тап стрелки = E0 74 + E0 F0 74,
* 5 байт) — FIFO переполняется, байт(ы) теряются аппаратно. Потерянный
* break → клавиша «залипает» в _kbdraw_down.
*
* Трамплин ловит overrun (RR1 бит5) и взводит _kbdraw_overrun. Приложение
* зовёт kbd_raw_sync() раз в кадр: при взведённом флаге сбрасывается
* held-состояние ВСЕХ клавиш, КРОМЕ модификаторов (Shift/Ctrl/Alt —
* таблица ниже). Обычные реально зажатые клавиши «перечитаются» их
* make-повтором (typematic) за ~0.1 с. Модификаторы НЕ сбрасываем
* принципиально: PS/2 автоповторяет только ПОСЛЕДНЮЮ нажатую клавишу,
* удерживаемый Shift при повторе стрелки не шлёт НИЧЕГО — сброшенный
* модификатор невозможно перечитать, он «отваливался» до перенажатия
* (баг PoP: Shift+→ = осторожный шаг превращался в бег, 2026-07-22).
* Цена: если overrun потерял именно break модификатора, тот залипнет до
* следующего нажатия — редкий случай против регулярного отвала.
*/
#include <string.h>
#include "_kbdraw.h"
/* Скан-коды модификаторов (PS/2 Set 2): L/R Shift, LCtrl, LAlt,
* RCtrl (E0 14 → +256), RAlt (E0 11 → +256). */
static const uint16_t _kbd_mod_codes[6] = {
0x12, 0x59, 0x14, 0x11, 0x0114, 0x0111
};
void kbd_raw_sync(void)
{
uint8_t save[6];
uint8_t i;
if (!_kbdraw_overrun) return;
_kbdraw_overrun = 0;
/* Карта упакована по битам (см. _kbdraw.h): сохраняем/возвращаем
* именно БИТ модификатора, а не байт. */
for (i = 0; i < 6; i++) {
uint16_t c = _kbd_mod_codes[i];
save[i] = (uint8_t)((_kbdraw_down[c >> 3] >> (c & 7)) & 1);
}
memset(_kbdraw_down, 0, sizeof(_kbdraw_down));
for (i = 0; i < 6; i++) {
uint16_t c = _kbd_mod_codes[i];
if (save[i]) _kbdraw_down[c >> 3] |= (uint8_t)(1 << (c & 7));
}
}