Reorganize source tree: kernel/, v3/, v4/ split and board infrastructure

Source tree reorganization:
- Move StarForth v3 engine to v3/ (src/, include/, Makefile)
- Move kernel to kernel/ (src/, include/, linker/, Makefile)
- Create v4/ skeleton for F18-ISA golden model (DECOMPOSITION.md, JUSTIFICATION.md)
- Move FABRIC-0..4.md to docs/fabric/
- Move ONTOLOGY.md and ROADMAP.md to docs/

Board infrastructure:
- Add boards/ser5/, boards/raspi/, boards/milkv/, boards/zynq7020/
- Each board has board.mk (ISA, CPU flags, boot recipe) and README.md
- Root Makefile becomes thin dispatcher: boot_image, all, clean, docs take TARGET
- make boot_image TARGET=SER5|RASPI|MILKV builds one GPT/MBR image per board
- ZYNQ7020 target exists but stops with clear error (ARMv7 port not built yet)
- scripts/mkdiskimage.sh builds disk images for all boards

Docs pipeline:
- docs/book/ with LaTeX master (main.tex) and Makefile
- pandoc converts Markdown to LaTeX at build time
- Two Lua filters: table-widths.lua (wide tables wrap), code-breaks.lua (inline code breaks)
- make docs builds single PDF (754 pages, 0 missing characters)
- make docs TARGET=<board> adds board appendix
- build/docs/<book|board>/meta.tex stamps git commit into PDF

Bug fixes:
- 42 include paths that only worked by accident now use correct relative paths
- clang-18 hardcode replaced with configurable CC variable (fixed aarch64 build)
- Pi 5: kernel_2712.img linked at 0x80000, .bss zeroed, memory reserved
- Doxyfile, .clang-tidy, README.md, Kconfig paths updated

Verified:
- Hosted v3 build passes 1012 tests, 0 failures
- SER5 image boots in QEMU (OVMF), POST passes, K exact (65536 = Q48_ONE)
- Milk-V image boots in QEMU (OpenSBI + U-Boot + bootefi), POST passes
- make clean TARGET=<board> removes only that board and its ISA objects
- make all builds all boards, hosted v3, and docs in one run

Co-authored-by: Junie <junie@jetbrains.com>
This commit is contained in:
rajames
2026-10-01 15:40:09 -04:00
co-authored by Junie
parent 3c709c115b
commit a8b70e88d3
630 changed files with 2646 additions and 2036 deletions
+189
View File
@@ -0,0 +1,189 @@
/*
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-0.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
#if defined(__STARKERNEL__)
#include "starkernel/console.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. */
/* FABRIC-0.md item 4.4v: shared C-level implementation, so the REPL
* keyboard bridge (repl.c) and the KEY-EVENT FORTH word below poll the
* exact same converged event stream rather than each re-deriving the
* per-arch translation kbw_key_event's own doc comment already explains
* (XT Set-1 make code == Linux keycode for the non-extended range; break
* codes set bit 7 instead of carrying a separate field). */
int sk_key_event_poll(uint16_t *keycode, int *pressed)
{
#if defined(__STARKERNEL__) && defined(ARCH_AMD64)
uint8_t sc;
if (i8042_pop_scancode(&sc)) {
*keycode = (uint16_t)(sc & 0x7Fu);
*pressed = (sc & 0x80u) ? 0 : 1;
return 1;
}
return 0;
#elif defined(__STARKERNEL__) && (defined(ARCH_RISCV64) || defined(ARCH_AARCH64))
uint16_t code;
uint32_t value;
if (virtio_input_pop_event(&code, &value)) {
*keycode = code;
*pressed = (value == 0u) ? 0 : 1;
return 1;
}
return 0;
#else
(void)keycode; (void)pressed;
return 0;
#endif
}
static void kbw_key_event(VM *vm)
{
uint16_t keycode;
int pressed;
if (sk_key_event_poll(&keycode, &pressed)) {
vm_push(vm, (cell_t)keycode);
vm_push(vm, (cell_t)pressed);
vm_push(vm, -1);
} else {
vm_push(vm, 0);
}
}
/* ALT+TAB ( -- ): FABRIC-0.md item 4.4y-revised. Programmatic equivalent of
* the physical Alt+TAB interception (repl.c's sk_kbd_getc()) -- both call
* console_fb_toggle_graphics(), so there is exactly one state-machine
* transition, invoked two ways. */
static void kbw_alt_tab(VM *vm)
{
(void)vm;
#if defined(__STARKERNEL__)
console_fb_toggle_graphics();
#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);
register_word(vm, "ALT+TAB", kbw_alt_tab);
}