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>
188 lines
7.3 KiB
C
188 lines
7.3 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
|
||
*/
|
||
|
||
/**
|
||
* repl.h - Emergency FORTH REPL for LithosAnanke kernel
|
||
*/
|
||
|
||
#ifndef STARKERNEL_REPL_H
|
||
#define STARKERNEL_REPL_H
|
||
|
||
#include "vm.h"
|
||
#include "starkernel/homeblocks_sig.h"
|
||
|
||
struct blkio_dev;
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
/**
|
||
* sk_repl - Run the emergency FORTH REPL on the serial console.
|
||
*
|
||
* Blocks until vm->halted is set (BYE word) or the VM encounters a halt.
|
||
* Runs with interrupts enabled; the APIC heartbeat continues to fire.
|
||
*
|
||
* @param vm Mama VM instance (must be fully initialised)
|
||
*/
|
||
void sk_repl(VM *vm);
|
||
|
||
/**
|
||
* sk_repl_run - Bare REPL loop (no banner).
|
||
*
|
||
* Same as sk_repl but skips the version/welcome banner. Used by START
|
||
* to enter a child VM's interpreter loop without reprinting the header.
|
||
*
|
||
* @param vm Fully initialised VM instance
|
||
*/
|
||
void sk_repl_run(VM *vm);
|
||
|
||
/**
|
||
* sk_repl_step - Execute one REPL turn on a VM and return.
|
||
*
|
||
* Prints the VM's prompt, reads one line, interprets it, prints ok/ERROR,
|
||
* then returns. Used by the Compudynamics VM-STEP primitive so Hera can
|
||
* give a single REPL quantum to a child VM without surrendering control
|
||
* for the full sk_repl_run() loop.
|
||
*
|
||
* @param vm Fully initialised VM instance
|
||
* @return 1 if the VM is still running, 0 if it halted during this turn
|
||
*/
|
||
int sk_repl_step(VM *vm);
|
||
|
||
/**
|
||
* sk_repl_set_active_vm - Redirect REPL input to a different VM (USE word).
|
||
*
|
||
* Pass NULL to restore default dispatch (Mama's VM).
|
||
* The change takes effect on the next REPL iteration.
|
||
*
|
||
* @param vm Target VM, or NULL for default
|
||
*/
|
||
void sk_repl_set_active_vm(VM *vm);
|
||
|
||
/**
|
||
* sk_repl_get_active_vm - Return the current USE-redirected VM, or NULL.
|
||
*/
|
||
VM *sk_repl_get_active_vm(void);
|
||
|
||
/**
|
||
* sk_repl_get_homeblocks_dev / sk_repl_get_homeblocks_sig - The currently
|
||
* attached home-blocks USB drive, or NULL if none is attached / the
|
||
* attached drive didn't check out as HOMEBLOCKS_SIG_OK (FABRIC-2.md
|
||
* §F.6/§F.9/§F.18). Both return NULL together; never one without the
|
||
* other.
|
||
*/
|
||
struct blkio_dev *sk_repl_get_homeblocks_dev(void);
|
||
const homeblocks_sig_t *sk_repl_get_homeblocks_sig(void);
|
||
|
||
/**
|
||
* sk_repl_get_attached_blk_dev - The currently attached USB block
|
||
* device, regardless of home-blocks recognition (FABRIC-2.md
|
||
* §F.8/§F.19) -- MINT's own target, since a blank/unminted drive never
|
||
* sets sk_repl_get_homeblocks_dev() above. NULL if nothing is attached.
|
||
*/
|
||
struct blkio_dev *sk_repl_get_attached_blk_dev(void);
|
||
|
||
/**
|
||
* sk_repl_register_words - Registers repl.c's own FORTH-visible words
|
||
* (currently just BLK-ATTACH-ACK, Artemis's storage-attach reply target --
|
||
* see sk_word_blk_attach_ack()'s doc comment in repl.c). Call once from
|
||
* register_forth79_words() alongside the other __STARKERNEL__-only
|
||
* registration calls.
|
||
*/
|
||
void sk_repl_register_words(VM *vm);
|
||
|
||
/**
|
||
* sk_console_getkey - Real body of the standard dictionary's KEY word
|
||
* (called from shim.c's getchar()). Blocks until a key is available from
|
||
* either input source (serial console or the PS2/virtio keyboard-event
|
||
* bridge), servicing the heartbeat/idle loop while waiting so a KEY call
|
||
* from inside any word never stalls the heartbeat. No echo -- that's the
|
||
* caller's responsibility, same as any standard KEY.
|
||
*
|
||
* @param active_vm VM whose idle dispatch runs while waiting (see
|
||
* sk_repl_idle()'s own doc comment on why this is a
|
||
* parameter rather than read via sk_repl_get_active_vm())
|
||
* @return the key read, as an unsigned byte value
|
||
*/
|
||
int sk_console_getkey(VM *active_vm);
|
||
|
||
/**
|
||
* sk_console_key_available - Real body of the standard dictionary's
|
||
* ?TERMINAL word (called from sf_terminal_ready()). Non-blocking peek:
|
||
* returns 1 if a key is ready without consuming it (a following
|
||
* sk_console_getkey() returns that exact key), 0 otherwise.
|
||
*/
|
||
int sk_console_key_available(void);
|
||
|
||
/**
|
||
* sk_console_readline - Real body of the standard dictionary's
|
||
* QUERY/EXPECT words (called from shim.c's fgets()). Reads one line from
|
||
* the console with echo and backspace support, servicing the heartbeat/
|
||
* idle loop while waiting -- the same line editor the REPL's own prompt
|
||
* uses internally, so a mid-word EXPECT behaves identically to typing at
|
||
* "ok>" itself.
|
||
*
|
||
* @param buf Destination buffer
|
||
* @param size Buffer capacity, including the NUL terminator
|
||
* @param active_vm VM whose idle dispatch runs while waiting
|
||
* @param reanchor_prompt Nonzero to re-print the "ok> " prompt whenever
|
||
* an idle bottom half (heartbeat, USB attach/detach) writes
|
||
* to the console while this readline blocks at a bare,
|
||
* untyped prompt -- keeps the top-level prompt as the last
|
||
* thing shown once the chatter dies down. Callers whose
|
||
* prompt line is their own (shim.c's fgets(), i.e.
|
||
* QUERY/EXPECT/ACCEPT) pass 0 so "ok> " never gets stamped
|
||
* onto their mid-word input context.
|
||
* @return number of characters placed in buf, not counting the NUL, or -1
|
||
* (2026-09-06) when reanchor_prompt is nonzero and the attached
|
||
* identity logged out while this call was blocked waiting for
|
||
* input with nothing typed yet -- see repl.c's own doc comment
|
||
* on this function for what a caller must do with -1.
|
||
*/
|
||
int sk_console_readline(char* buf, int size, VM* active_vm, int reanchor_prompt);
|
||
|
||
/**
|
||
* sk_repl_headless_wait - Idle-service loop with no interactive surface
|
||
* at all: no banner, no prompt, no console_getc()/readline. Runs
|
||
* heartbeat_service() and the same SK_IDLE_BEAT_INTERVAL-gated
|
||
* sk_repl_idle(mama) cadence sk_console_readline()'s own idle branch
|
||
* uses -- so USB/WIREBIND/Zuse-attach detection, the heartbeat, and all
|
||
* other idle-tick subsystems keep running -- until a real identity is
|
||
* currently attached (Zuse's own session, or a WIREBIND user), at which
|
||
* point it returns.
|
||
*
|
||
* Revised 2026-09-06: originally exited on a one-way sticky "has anyone
|
||
* ever logged in this boot" flag (sk_console_mark_login()/sk_console_
|
||
* login_occurred(), both retired) -- that let a real gap through, found
|
||
* live: once the flag tripped once, it never reset, so a later full
|
||
* logout (nobody attached at all) fell through to a bare, unauthenticated
|
||
* prompt instead of going silent again. This now checks live attach
|
||
* state instead (repl.c's own sk_console_identity_present()), and is
|
||
* called from two places: once from kernel_main.c in place of an
|
||
* immediate sk_repl(mama) call when EMERGENCY_CONSOLE_ENABLED is off (the
|
||
* default, 2026-09-05) -- no thumbdrive, no prompt, at boot -- and again
|
||
* from inside sk_repl_run()'s own main loop, every time nobody is
|
||
* currently attached, so the same silence re-engages after any later
|
||
* logout mid-boot too. When EMERGENCY_CONSOLE_ENABLED is on (the debug/
|
||
* recovery escape hatch), neither call site applies -- the console shows
|
||
* immediately and stays visible regardless of attach state, exactly as
|
||
* before this change.
|
||
*
|
||
* @param mama Hera's own VM instance -- the idle-dispatch target,
|
||
* same as every other sk_repl_idle() caller uses.
|
||
*/
|
||
void sk_repl_headless_wait(VM *mama);
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* STARKERNEL_REPL_H */
|