Punch list §25 item 4.3.5f complete. Keyboard-input slice done. New KEY-EVENT ( -- keycode pressed -1 | 0 ) converges amd64's i8042, riscv64's and aarch64's virtio-keyboard-pci behind one shape. Translation needed is minimal: XT Set-1 make codes and Linux input keycodes are numerically identical across the standard 84-key block (a documented historical property of the Linux input subsystem, confirmed against this host's own headers and this tree's own prior live observations), so amd64 needs two lines, riscv64/aarch64 need none. Verified live with a real keypress on all three architectures: identical "-1 1 30" output everywhere. Three-arch acceptance boot clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
154 lines
5.2 KiB
C
154 lines
5.2 KiB
C
/*
|
||
StarForth — Steady-State Virtual Machine Runtime
|
||
|
||
Copyright (c) 2023–2025 Robert A. James
|
||
All rights reserved.
|
||
|
||
Licensed under the StarForth License, Version 1.0
|
||
*/
|
||
|
||
/* keyboard_words.c — raw scancode-ring diagnostic word (FABRIC.md item
|
||
* 4.3.5). Kernel-only, amd64-only; no-op elsewhere. */
|
||
|
||
#include "include/keyboard_words.h"
|
||
#include "../../include/word_registry.h"
|
||
|
||
#if defined(__STARKERNEL__) && defined(ARCH_AMD64)
|
||
#include "starkernel/i8042.h"
|
||
#endif
|
||
|
||
#if defined(__STARKERNEL__) && (defined(ARCH_RISCV64) || defined(ARCH_AARCH64))
|
||
#include "starkernel/virtio_input.h"
|
||
#endif
|
||
|
||
/* KBD-SCAN ( -- c -1 | 0 ) */
|
||
static void kbw_scan(VM *vm)
|
||
{
|
||
#if defined(__STARKERNEL__) && defined(ARCH_AMD64)
|
||
uint8_t sc;
|
||
if (i8042_pop_scancode(&sc)) {
|
||
vm_push(vm, (cell_t)sc);
|
||
vm_push(vm, -1);
|
||
} else {
|
||
vm_push(vm, 0);
|
||
}
|
||
#else
|
||
vm_push(vm, 0);
|
||
#endif
|
||
}
|
||
|
||
/* KBD-DEBUG ( -- isr_count spurious_count ): cheap standing diagnostic,
|
||
* not scaffolding -- confirms the interrupt path is alive (isr_count) and
|
||
* flags the failure mode item 4.3.5 found (a real IRQ misreported as
|
||
* spurious) without needing a live debugger. */
|
||
extern volatile uint32_t g_i8042_isr_count;
|
||
extern volatile uint32_t g_spurious_count;
|
||
static void kbw_debug(VM *vm)
|
||
{
|
||
#if defined(__STARKERNEL__) && defined(ARCH_AMD64)
|
||
vm_push(vm, (cell_t)g_i8042_isr_count);
|
||
vm_push(vm, (cell_t)g_spurious_count);
|
||
#else
|
||
vm_push(vm, 0);
|
||
vm_push(vm, 0);
|
||
#endif
|
||
}
|
||
|
||
/* VKBD-EVENT ( -- code value -1 | 0 ): item 4.3.5c (riscv64) / 4.3.5e
|
||
* (aarch64) virtio-input. Pop one decoded EV_KEY event off the
|
||
* interrupt-fed ring buffer. Pushes code and value and -1 (true) if one
|
||
* was available, or just 0 (false) if the buffer was empty. Distinct word
|
||
* from KBD-SCAN rather than a shared one: different device, different
|
||
* event shape (Linux-style code/value pair vs. a raw XT scancode byte) --
|
||
* convergence onto one interface is item 4.3.5f's explicit job, not this
|
||
* one's. */
|
||
static void kbw_vevent(VM *vm)
|
||
{
|
||
#if defined(__STARKERNEL__) && (defined(ARCH_RISCV64) || defined(ARCH_AARCH64))
|
||
uint16_t code;
|
||
uint32_t value;
|
||
if (virtio_input_pop_event(&code, &value)) {
|
||
vm_push(vm, (cell_t)code);
|
||
vm_push(vm, (cell_t)value);
|
||
vm_push(vm, -1);
|
||
} else {
|
||
vm_push(vm, 0);
|
||
}
|
||
#else
|
||
vm_push(vm, 0);
|
||
#endif
|
||
}
|
||
|
||
/* VKBD-DEBUG ( -- isr_count ): standing diagnostic, same shape as
|
||
* KBD-DEBUG -- confirms the virtio-input interrupt path is alive. */
|
||
extern volatile uint32_t g_virtio_input_isr_count;
|
||
static void kbw_vdebug(VM *vm)
|
||
{
|
||
#if defined(__STARKERNEL__) && (defined(ARCH_RISCV64) || defined(ARCH_AARCH64))
|
||
vm_push(vm, (cell_t)g_virtio_input_isr_count);
|
||
#else
|
||
vm_push(vm, 0);
|
||
#endif
|
||
}
|
||
|
||
/* KEY-EVENT ( -- keycode pressed -1 | 0 ): item 4.3.5f convergence
|
||
* checkpoint. One shared shape across all three architectures instead of
|
||
* KBD-SCAN's raw XT scancode byte or VKBD-EVENT's Linux code/value pair.
|
||
* keycode is the Linux input keycode namespace (linux/input-event-codes.h);
|
||
* pressed is 1 (press) or 0 (release).
|
||
*
|
||
* amd64 needs a real translation, not an invented one: XT Set-1's make
|
||
* code for a key and Linux's keycode for that same key are the *same
|
||
* number*, confirmed against this build host's own
|
||
* /usr/include/linux/input-event-codes.h and against this tree's own
|
||
* live-observed values (item 4.3.5's done note: 'a' -> 30, 'b' -> 48,
|
||
* matching KEY_A=30/KEY_B=48 exactly) -- not a coincidence, a documented
|
||
* historical property of how the Linux input keycode numbering was
|
||
* originally defined around the AT/XT scancode set. Break codes set XT's
|
||
* bit 7 (make|0x80) rather than carrying a separate press/release field,
|
||
* so `keycode = sc & 0x7F, pressed = !(sc & 0x80)` is the whole
|
||
* translation for the entire non-extended key range. Extended
|
||
* (0xE0-prefixed) scancodes are not decoded here -- this checkpoint needs
|
||
* one shared shape proven live per architecture, not full keyboard
|
||
* coverage; that belongs to the REPL wiring item (M8) this checkpoint
|
||
* unblocks.
|
||
*
|
||
* riscv64/aarch64 need no translation at all -- virtio-input's `code`
|
||
* field already lives in the same Linux keycode namespace; `value` is
|
||
* mapped 1:1 except autorepeat (value=2), folded into "still pressed"
|
||
* here since this checkpoint's shape only distinguishes press/release. */
|
||
static void kbw_key_event(VM *vm)
|
||
{
|
||
#if defined(__STARKERNEL__) && defined(ARCH_AMD64)
|
||
uint8_t sc;
|
||
if (i8042_pop_scancode(&sc)) {
|
||
vm_push(vm, (cell_t)(sc & 0x7Fu));
|
||
vm_push(vm, (cell_t)((sc & 0x80u) ? 0 : 1));
|
||
vm_push(vm, -1);
|
||
} else {
|
||
vm_push(vm, 0);
|
||
}
|
||
#elif defined(__STARKERNEL__) && (defined(ARCH_RISCV64) || defined(ARCH_AARCH64))
|
||
uint16_t code;
|
||
uint32_t value;
|
||
if (virtio_input_pop_event(&code, &value)) {
|
||
vm_push(vm, (cell_t)code);
|
||
vm_push(vm, (cell_t)(value == 0u ? 0 : 1));
|
||
vm_push(vm, -1);
|
||
} else {
|
||
vm_push(vm, 0);
|
||
}
|
||
#else
|
||
vm_push(vm, 0);
|
||
#endif
|
||
}
|
||
|
||
void register_keyboard_words(VM *vm)
|
||
{
|
||
register_word(vm, "KBD-SCAN", kbw_scan);
|
||
register_word(vm, "KBD-DEBUG", kbw_debug);
|
||
register_word(vm, "VKBD-EVENT", kbw_vevent);
|
||
register_word(vm, "VKBD-DEBUG", kbw_vdebug);
|
||
register_word(vm, "KEY-EVENT", kbw_key_event);
|
||
}
|