feat(v4.0.0): a node is handed a line -- ENGINE.md step 1
A v4 node no longer reads its own command line or prints a prompt. Its host puts a line of text in the node's input buffer and starts it at (LINE); the node interprets it and stops at (IDLE), leaving in (LINE-STATUS) how it ended: completed, an error, or QUIT. The host says " ok" or " ERROR" and prompts, as the kernel's REPL does for a v3 VM. A line may be 1024 characters, a block, as v3's. Ruled 2026-10-05 (V3-PARITY.md 1b); design ENGINE.md 3.1. - quit.v4: (REPL), the node's prompt loop, is gone; (LINE) (IDLE) (DONE) - image.h/.c: v4_line_begin, v4_line_done, v4_line_status; the node is idle at switch-on - boot.c: v4_boot_line, the one loop the hosted binary, the kernel and the capsule loader hand a line with; the code that took " ok" and the prompt back out of the node's output is gone - hosted.c, sk_v4.c: the prompt and the line editing are the host's - test_host_quit.c: the tests are the node's host; two tests of the old 80-character prompt line now test a whole line, 1024 and 1025 characters Verified: make -C v4 test passes at both widths; hosted-check passes on three ISAs; clean qemu with STARFORTH_V4=1 on amd64, aarch64 and riscv64 passes POST (550 of 550) with the same hashes as hosted, and three lines typed at each bare-metal prompt through the serial port are answered correctly (logs/20261005-180922, -181152, -181541). Still the lone node: kernel_main.c starts it before the fleet tables. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
ab7a9bf06f
commit
01c447f9ab
+20
-6
@@ -11,7 +11,6 @@
|
||||
* PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=0x... capsule_hash=0x... dict_hash=0x...
|
||||
* PARITY:OK
|
||||
* POST: PASSED
|
||||
* ok>
|
||||
*
|
||||
* or, if anything is wrong, what was wrong and then
|
||||
*
|
||||
@@ -21,9 +20,10 @@
|
||||
* A capsule is found by name in the directory tools/mkcapsule.c baked into
|
||||
* the binary, its hash is recomputed, its signature is checked -- one that
|
||||
* does not verify refuses the capsule, a missing one is only reported, as
|
||||
* for v3's capsules -- and its blocks are given to the node a line at a
|
||||
* time as if typed. The node must answer " ok" to every line; the first
|
||||
* line it does not accept ends the boot. What a line prints is shown.
|
||||
* for v3's capsules -- and its blocks are handed to the node a line at a
|
||||
* time (docs/v4.0.0/ENGINE.md 3.1). Every line must complete; the first
|
||||
* that ends in an error, or in QUIT, ends the boot. What a line prints is
|
||||
* shown.
|
||||
*
|
||||
* The dictionary hash is FNV-1a over the node's memory below HERE, a cell at
|
||||
* a time, low byte first, then LATEST. It does not depend on the machine:
|
||||
@@ -40,13 +40,27 @@ typedef struct {
|
||||
v4_heat *h;
|
||||
const v4_image *im; /* the nucleus */
|
||||
void (*out)(const char *text, unsigned len); /* the console */
|
||||
int (*key)(void); /* a character for a line that reads the keyboard, or 0: there is none */
|
||||
} v4_boot;
|
||||
|
||||
/* What `key` returns when it has no character. */
|
||||
#define V4_BOOT_KEY_NONE (-1) /* not yet: it is asked again */
|
||||
#define V4_BOOT_KEY_END (-2) /* and there never will be */
|
||||
|
||||
/* Start the node from the nucleus image, with `disk` as its block storage
|
||||
* (see v4_image_boot), and load the capsules. Returns 1 with the node
|
||||
* waiting at its prompt, the prompt printed; or 0, the failure printed. */
|
||||
* (see v4_image_boot), and load the capsules. Returns 1 with the node idle,
|
||||
* waiting to be handed a line; or 0, the failure printed. It prints no
|
||||
* prompt: that is the host's. */
|
||||
int v4_boot_run(const v4_boot *b, unsigned char *disk, unsigned blocks);
|
||||
|
||||
/* Hand the node a line and run it to its end, sending what it prints to
|
||||
* `out`. Returns how it ended -- V4_LINE_QUIT, V4_LINE_COMPLETED or
|
||||
* V4_LINE_ERROR (image.h) -- or one of these: */
|
||||
#define V4_BOOT_LINE_TOO_LONG (-1) /* more than the node's input buffer holds; nothing was run */
|
||||
#define V4_BOOT_LINE_STOPPED (-2) /* the node stopped on a fault, or never finished */
|
||||
#define V4_BOOT_LINE_NO_INPUT (-3) /* the line read the keyboard and there is no more input */
|
||||
int v4_boot_line(const v4_boot *b, const char *text, unsigned len);
|
||||
|
||||
/* The dictionary hash of a node started from `im`. */
|
||||
uint64_t v4_boot_dict_hash(const v4_node *n, const v4_image *im);
|
||||
|
||||
|
||||
+33
-9
@@ -29,9 +29,17 @@ typedef struct {
|
||||
/* what the image was built for */
|
||||
unsigned cell_bits, node_words, data_ring, ret_ring;
|
||||
|
||||
/* where to start, and where a fault goes */
|
||||
v4_cell entry; /* QUIT */
|
||||
v4_cell fault_table; /* (FAULTS) */
|
||||
/* The node is handed a line (docs/v4.0.0/ENGINE.md 3.1). Its host puts
|
||||
* text in the input buffer and starts it at `line`; it stops at `idle`,
|
||||
* with how the line ended in the cell `line_status`. At switch-on it
|
||||
* is at `idle`. */
|
||||
v4_cell line; /* (LINE) */
|
||||
v4_cell idle; /* (IDLE) */
|
||||
v4_cell line_status; /* word address of the variable (LINE-STATUS) */
|
||||
v4_cell tib; /* byte address of the input buffer */
|
||||
unsigned tib_bytes; /* its size: a line may be one less */
|
||||
v4_cell span; /* word address of the variable SPAN */
|
||||
v4_cell fault_table; /* (FAULTS): where a fault goes */
|
||||
|
||||
/* KEY's code: a node whose P is in key_start .. key_end - 1 with no
|
||||
* character pending is waiting for one */
|
||||
@@ -53,17 +61,33 @@ typedef struct {
|
||||
/* The image built from v4/capsule (the generated file defines it). */
|
||||
extern const v4_image v4_capsule_image;
|
||||
|
||||
/* How a line ended. */
|
||||
#define V4_LINE_QUIT 0 /* QUIT: nothing is to be said */
|
||||
#define V4_LINE_COMPLETED 1 /* the host says " ok" */
|
||||
#define V4_LINE_ERROR 2 /* the message is printed; the host says " ERROR" */
|
||||
|
||||
/* Reset `n`, load the image into it, attach its registers -- with `disk`,
|
||||
* `blocks` blocks of 1024 bytes, as its block storage, or none if `disk` is
|
||||
* 0 -- and leave it about to execute its first instruction. Returns 1, or 0
|
||||
* if the image is not for this build of the engine (nothing is then done).
|
||||
*
|
||||
* After it, the caller runs the node: v4_exec_step_word again and again,
|
||||
* taking what the node prints from n->console (and setting n->console_len
|
||||
* back to 0) and giving it what is typed with v4_node_console_feed. */
|
||||
* 0 -- and leave it idle, waiting to be handed a line. Returns 1, or 0 if
|
||||
* the image is not for this build of the engine (nothing is then done). */
|
||||
int v4_image_boot(v4_node *n, v4_exec_state *es, v4_heat *h, const v4_image *im,
|
||||
unsigned char *disk, unsigned blocks);
|
||||
|
||||
/* Hand the node `len` characters of text to interpret. Returns 1, or 0 if
|
||||
* the text is longer than the node's input buffer holds (nothing is then
|
||||
* done). After it the host runs the node -- v4_exec_step_word again and
|
||||
* again, taking what the node prints from n->console and setting
|
||||
* n->console_len back to 0 -- until v4_line_done; if v4_image_waiting comes
|
||||
* first, the line is reading the keyboard, and the host gives it characters
|
||||
* with v4_node_console_feed. */
|
||||
int v4_line_begin(v4_node *n, const v4_image *im, const char *text, unsigned len);
|
||||
|
||||
/* 1 when the node has finished the line it was handed and is idle again. */
|
||||
int v4_line_done(const v4_node *n, const v4_image *im);
|
||||
|
||||
/* How the line just finished ended: V4_LINE_QUIT, _COMPLETED or _ERROR. */
|
||||
int v4_line_status(const v4_node *n, const v4_image *im);
|
||||
|
||||
/* 1 if the node is waiting for a character: it is inside KEY and none is
|
||||
* pending. */
|
||||
int v4_image_waiting(const v4_node *n, const v4_image *im);
|
||||
|
||||
Reference in New Issue
Block a user