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
+6
-30
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* Runs on the build machine. It assembles capsule/ *.v4 -- the nucleus,
|
||||
* docs/v4.0.0/NUCLEUS.md -- onto a host node with the memory map of
|
||||
* tests/host_map.h and starts the node at its prompt. Then it writes every
|
||||
* tests/host_map.h. It runs nothing: it writes every
|
||||
* word of the node's memory that is not zero, and the addresses a loader
|
||||
* needs, as a C file. No FORTH source is compiled here: what is not in the
|
||||
* nucleus is loaded from capsules when the system boots (v4/system/boot.c).
|
||||
@@ -22,11 +22,8 @@
|
||||
#include "../tests/host_map.h"
|
||||
|
||||
static v4_node n;
|
||||
static v4_exec_state es;
|
||||
static v4_heat h;
|
||||
static v4_text tx;
|
||||
static v4_cell w_key, w_key_end;
|
||||
static unsigned char disk[4 * V4_BLOCK_BYTES];
|
||||
|
||||
static void die(const char *what, const char *detail)
|
||||
{
|
||||
@@ -34,19 +31,6 @@ static void die(const char *what, const char *detail)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* run until the node has taken all its input and is waiting in KEY */
|
||||
static void run_until_waiting(void)
|
||||
{
|
||||
long steps = 0;
|
||||
unsigned idle = 0;
|
||||
while (idle < 64) {
|
||||
if (++steps > 200000000L) die("the node did not come back to its prompt", NULL);
|
||||
if (n.stopped) die("the node stopped on a fault", NULL);
|
||||
(void)v4_exec_step_word(&n, &es, &h);
|
||||
if (n.input_pos == n.input_len && n.p >= w_key && n.p < w_key_end) idle++; else idle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* every entry from xt back: no access control fields set */
|
||||
static void clear_acl(v4_cell xt)
|
||||
{
|
||||
@@ -58,7 +42,7 @@ int main(int argc, char **argv)
|
||||
static const char *const files[] = { "core.v4", "input.v4", "dict.v4", "codegen.v4", "compile.v4", "quit.v4", "forth.v4",
|
||||
"numout.v4", "words.v4", "system.v4", "qmath.v4", "blocks.v4", "log.v4", "acl.v4" };
|
||||
FILE *out;
|
||||
v4_cell k, entry, faults, voc;
|
||||
v4_cell k, line, idle, faults, voc;
|
||||
unsigned count = 0;
|
||||
|
||||
if (argc != 2) die("usage: mkimage OUTPUT.c", NULL);
|
||||
@@ -66,7 +50,8 @@ int main(int argc, char **argv)
|
||||
if (!host_load(&tx, &n, files, (unsigned)(sizeof files / sizeof files[0]))) die("the capsule does not assemble", NULL);
|
||||
if (!v4_text_finish(&tx)) die("not everything is defined", v4_text_error(&tx));
|
||||
if (v4_text_here(&tx) >= DICT_W) die("the capsule's code runs into the dictionary space", NULL);
|
||||
entry = v4_text_word(&tx, "QUIT");
|
||||
line = v4_text_word(&tx, "(LINE)");
|
||||
idle = v4_text_word(&tx, "(IDLE)");
|
||||
faults = v4_text_word(&tx, "(FAULTS)");
|
||||
w_key = v4_text_word(&tx, "KEY");
|
||||
w_key_end = v4_text_word(&tx, "CR");
|
||||
@@ -83,16 +68,6 @@ int main(int argc, char **argv)
|
||||
n.mem[CURRENT] = LATEST;
|
||||
n.mem[SRC] = TIB;
|
||||
|
||||
v4_exec_reset(&es);
|
||||
v4_heat_reset(&h);
|
||||
v4_node_console_attach(&n, CONSOLE_TX);
|
||||
v4_node_console_input_attach(&n, CONSOLE_RX, CONSOLE_ST);
|
||||
v4_node_error_attach(&n, NODE_ERROR);
|
||||
v4_node_fault_attach(&n, faults);
|
||||
v4_node_storage_attach(&n, STORAGE_REG, disk, 4);
|
||||
n.p = entry;
|
||||
run_until_waiting();
|
||||
|
||||
/* The nucleus is the system as COLD finds it: COLD comes back to here,
|
||||
* and FORGET will not go below it. What the capsules add at boot
|
||||
* (v4/system/boot.c) is above it. */
|
||||
@@ -125,7 +100,8 @@ int main(int argc, char **argv)
|
||||
}
|
||||
fprintf(out, "};\n\nconst v4_image v4_capsule_image = {\n cells, %uu,\n %uu, %uu, %uu, %uu,\n", count,
|
||||
(unsigned)V4_CELL_BITS, (unsigned)V4_NODE_WORDS, (unsigned)V4_DATA_RING, (unsigned)V4_RET_RING);
|
||||
fprintf(out, " %ld, %ld,\n %ld, %ld,\n", (long)entry, (long)faults, (long)w_key, (long)w_key_end);
|
||||
fprintf(out, " %ld, %ld, %ld,\n %ld, %uu, %ld,\n %ld,\n %ld, %ld,\n", (long)line, (long)idle, (long)LINE_STATUS,
|
||||
(long)TIB, 1025u, (long)SPAN, (long)faults, (long)w_key, (long)w_key_end);
|
||||
fprintf(out, " %ld, %ld, %ld,\n %ld, %ld,\n %ld,\n %ld,\n %ld, %ld\n};\n", (long)CONSOLE_TX, (long)CONSOLE_RX, (long)CONSOLE_ST,
|
||||
(long)DSTACK_REG, (long)RSTACK_REG, (long)NODE_ERROR, (long)STORAGE_REG, (long)DP, (long)LATEST);
|
||||
if (fclose(out) != 0) die("cannot write", argv[1]);
|
||||
|
||||
Reference in New Issue
Block a user