Files
LithosAnanke/src/word_source/keyboard_words.c
T
Robert Allan JamesandClaude Sonnet 5 d0835c674b FORTH: KEY-EVENT unified keyboard interface, closes 4.3.5-4.3.5f (item 4.3.5f)
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>
2026-08-08 12:48:05 -04:00

154 lines
5.2 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
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);
}