libc/kbd: recovery по Rx-overrun SIO (залипание клавиш) + kbd_raw_sync
Симптом (интермиттентный): при отпускании shift+стрелка иногда стрелка залипает. Диагностика: на чистом одновременном release break-коды обрабатываются верно (проверено MCP) → drain-логика ISR корректна. Остаточное залипание = переполнение 3-байтного аппаратного FIFO SIO при пачке скан-кодов (F0 12 E0 F0 74 = 5 байт) во время длинных DI-окон → потерян break → залипание. Фикс: трамплин после drain читает RR1 SIO (бит5 = Rx Overrun), при overrun делает Error Reset (WR0=0x30) и взводит _kbdraw_overrun. Новый kbd_raw_sync() (звать раз в кадр) по флагу сбрасывает всё held-состояние _kbdraw_down (какой break потерян — неизвестно; реально зажатые перечитаются). pop_ctrl_tick зовёт kbd_raw_sync(). Буфер W2- трамплина 288→320 (трамплин 244 Б). ВНИМАНИЕ: путь overrun НЕ проверен детерминированно (баг интермиттентный, зависит от тайминга DI) — ТРЕБУЕТ ПРОВЕРКИ на железе/в длинной сессии. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -402,6 +402,7 @@ int8_t pop_ctrl_shift_held(void)
|
|||||||
|
|
||||||
void pop_ctrl_tick(void)
|
void pop_ctrl_tick(void)
|
||||||
{
|
{
|
||||||
|
kbd_raw_sync(); /* снять залипшее после Rx-overrun SIO */
|
||||||
rest_ctrl_1();
|
rest_ctrl_1();
|
||||||
read_input();
|
read_input();
|
||||||
read_user_control();
|
read_user_control();
|
||||||
|
|||||||
@@ -46,6 +46,13 @@ void kbd_raw_close(void);
|
|||||||
* на проводе) прибавить KBD_EXT к базовому коду. */
|
* на проводе) прибавить KBD_EXT к базовому коду. */
|
||||||
uint8_t kbd_raw_down(uint16_t code);
|
uint8_t kbd_raw_down(uint16_t code);
|
||||||
|
|
||||||
|
/* Восстановление после Rx-overrun SIO: звать РАЗ В КАДР (до чтения
|
||||||
|
* kbd_raw_down). Аппаратный FIFO SIO 3 байта; при длинных DI-окнах пачка
|
||||||
|
* скан-кодов (напр. shift+стрелка release) переполняет его → потерян break
|
||||||
|
* → залипшая клавиша. Трамплин ловит overrun и взводит флаг; kbd_raw_sync
|
||||||
|
* по флагу сбрасывает ВСЁ held-состояние (реально зажатые перечитаются). */
|
||||||
|
void kbd_raw_sync(void);
|
||||||
|
|
||||||
#define KBD_EXT 0x0100 /* база кода была расширенной (0xE0-префикс) */
|
#define KBD_EXT 0x0100 /* база кода была расширенной (0xE0-префикс) */
|
||||||
|
|
||||||
/* Позиционные коды PS/2 Set 2 — то, что реально нужно платформеру.
|
/* Позиционные коды PS/2 Set 2 — то, что реально нужно платформеру.
|
||||||
|
|||||||
+4
-4
@@ -30,10 +30,10 @@
|
|||||||
#define _IRQ_VEC_BUF_SIZE (256 + 257)
|
#define _IRQ_VEC_BUF_SIZE (256 + 257)
|
||||||
|
|
||||||
/* Буфер под W2-копию кадрового трамплина (small/huge — _irq_tramp в
|
/* Буфер под W2-копию кадрового трамплина (small/huge — _irq_tramp в
|
||||||
* W1). С запасом над реальным размером трамплина (225 Б после
|
* W1). С запасом над реальным размером трамплина (244 Б после
|
||||||
* FIFO-drain цикла в raw-клавиатурной ветке, 2026-07-16 — проверять
|
* FIFO-drain + overrun-recovery в raw-клавиатурной ветке, 2026-07-18 —
|
||||||
* __irq_tramp_end при правках, запас держать ≥ 60 Б). */
|
* проверять __irq_tramp_end при правках, запас держать ≥ 60 Б). */
|
||||||
#define _IRQ_TRAMP_BUF_SIZE 288
|
#define _IRQ_TRAMP_BUF_SIZE 320
|
||||||
|
|
||||||
extern uint8_t _irq_vec_buf[_IRQ_VEC_BUF_SIZE];
|
extern uint8_t _irq_vec_buf[_IRQ_VEC_BUF_SIZE];
|
||||||
|
|
||||||
|
|||||||
@@ -104,6 +104,22 @@ void _irq_tramp(void) __naked
|
|||||||
in a, (#_IRQ_SIO_A) ; ещё байт в FIFO?
|
in a, (#_IRQ_SIO_A) ; ещё байт в FIFO?
|
||||||
rrca ; бит 0 → CF
|
rrca ; бит 0 → CF
|
||||||
jr C, tr_kbd_drain ; да — вычерпать следующий
|
jr C, tr_kbd_drain ; да — вычерпать следующий
|
||||||
|
|
||||||
|
;; --- FIFO опустошён: проверить Rx-overrun (потерян ли байт?) ---
|
||||||
|
;; RR1 SIO бит5 = Rx Overrun Error. При overrun break-код мог
|
||||||
|
;; потеряться (клавиша «залипнет») → взводим _kbdraw_overrun, чтобы
|
||||||
|
;; kbd_raw_sync() в главном цикле снял held-состояние; и Error Reset
|
||||||
|
;; (WR0 команда 0x30), иначе бит залипнет. (z84c15 SIO, Z80-совм.)
|
||||||
|
ld a, #1
|
||||||
|
out (#_IRQ_SIO_A), a ; указатель на RR1
|
||||||
|
in a, (#_IRQ_SIO_A) ; читаем RR1 (указатель авто-сброс в 0)
|
||||||
|
bit 5, a
|
||||||
|
jr Z, tr_kbd_noovr
|
||||||
|
ld a, #0x30
|
||||||
|
out (#_IRQ_SIO_A), a ; WR0 Error Reset
|
||||||
|
ld a, #1
|
||||||
|
ld (__kbdraw_overrun), a
|
||||||
|
tr_kbd_noovr:
|
||||||
pop de
|
pop de
|
||||||
pop hl
|
pop hl
|
||||||
pop af
|
pop af
|
||||||
|
|||||||
@@ -20,6 +20,9 @@
|
|||||||
extern uint8_t _kbdraw_active; /* 0 = raw выключен (дефолт, трамплин
|
extern uint8_t _kbdraw_active; /* 0 = raw выключен (дефолт, трамплин
|
||||||
* ведёт себя как раньше — прямо к DSS) */
|
* ведёт себя как раньше — прямо к DSS) */
|
||||||
extern uint8_t _kbdraw_pending; /* FSM декодера make/break, см. выше */
|
extern uint8_t _kbdraw_pending; /* FSM декодера make/break, см. выше */
|
||||||
|
extern uint8_t _kbdraw_overrun; /* 1 = ISR поймал Rx-overrun SIO (потерян
|
||||||
|
* байт → возможно потерян break); снимает
|
||||||
|
* kbd_raw_sync (чистит _kbdraw_down) */
|
||||||
extern uint8_t _kbdraw_down[512]; /* 0/1 по коду; +256 для расширенных
|
extern uint8_t _kbdraw_down[512]; /* 0/1 по коду; +256 для расширенных
|
||||||
* (префикс 0xE0) — см. kbd_raw_down */
|
* (префикс 0xE0) — см. kbd_raw_down */
|
||||||
|
|
||||||
|
|||||||
@@ -7,4 +7,6 @@
|
|||||||
|
|
||||||
uint8_t _kbdraw_active;
|
uint8_t _kbdraw_active;
|
||||||
uint8_t _kbdraw_pending;
|
uint8_t _kbdraw_pending;
|
||||||
|
uint8_t _kbdraw_overrun; /* ISR взвёл при Rx-overrun SIO (потерян
|
||||||
|
* break) — kbd_raw_sync снимет залипшее */
|
||||||
uint8_t _kbdraw_down[512];
|
uint8_t _kbdraw_down[512];
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* kbd_raw_sync.c — восстановление held-состояния после Rx-overrun SIO.
|
||||||
|
*
|
||||||
|
* Аппаратный приёмный FIFO SIO — 3 байта. Если прерывания запрещены
|
||||||
|
* достаточно долго (DI-окна графики/кадрового IRQ), а в этот момент
|
||||||
|
* приходит пачка скан-кодов (напр. одновременное отпускание shift+стрелка
|
||||||
|
* = F0 12 E0 F0 74, 5 байт) — FIFO переполняется, байт(ы) теряются
|
||||||
|
* аппаратно. Потерянный break → клавиша «залипает» в _kbdraw_down.
|
||||||
|
*
|
||||||
|
* Трамплин ловит overrun (RR1 бит5) и взводит _kbdraw_overrun. Приложение
|
||||||
|
* зовёт kbd_raw_sync() раз в кадр: при взведённом флаге сбрасывает ВСЁ
|
||||||
|
* held-состояние (какой именно break потерян — неизвестно). Реально
|
||||||
|
* зажатые клавиши «перечитаются» их make-повтором/следующим нажатием.
|
||||||
|
*
|
||||||
|
* ВНИМАНИЕ: путь overrun-recovery НЕ проверен детерминированно (баг
|
||||||
|
* интермиттентный, зависит от тайминга DI) — требует проверки на железе.
|
||||||
|
*/
|
||||||
|
#include <string.h>
|
||||||
|
#include "_kbdraw.h"
|
||||||
|
|
||||||
|
void kbd_raw_sync(void)
|
||||||
|
{
|
||||||
|
if (_kbdraw_overrun) {
|
||||||
|
_kbdraw_overrun = 0;
|
||||||
|
memset(_kbdraw_down, 0, sizeof(_kbdraw_down));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user