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:
rajames
2026-10-05 18:17:37 -04:00
co-authored by Claude Opus 5.5
parent ab7a9bf06f
commit 01c447f9ab
17 changed files with 771 additions and 253 deletions
+35 -1
View File
@@ -26,7 +26,8 @@ int v4_image_boot(v4_node *n, v4_exec_state *es, v4_heat *h, const v4_image *im,
v4_node_fault_attach(n, im->fault_table);
if (disk && blocks) v4_node_storage_attach(n, im->storage_reg, disk, blocks);
n->p = im->entry;
n->mem[im->line_status] = V4_LINE_COMPLETED;
n->p = im->idle;
return 1;
}
@@ -34,3 +35,36 @@ int v4_image_waiting(const v4_node *n, const v4_image *im)
{
return n->input_pos == n->input_len && n->p >= im->key_start && n->p < im->key_end;
}
/* One byte of the node's memory: four to a cell, the first lowest, at either
* cell width -- as C! stores them (v4/capsule/core.v4). */
static void put_byte(v4_node *n, v4_cell baddr, unsigned c)
{
v4_cell word = baddr / 4;
unsigned shift = 8u * (unsigned)(baddr % 4);
v4_ucell mask = (v4_ucell)0xFFu << shift;
n->mem[word] = (v4_cell)(((v4_ucell)n->mem[word] & ~mask) | ((v4_ucell)(c & 0xFFu) << shift));
}
int v4_line_begin(v4_node *n, const v4_image *im, const char *text, unsigned len)
{
unsigned i;
if (len + 1u > im->tib_bytes) return 0;
for (i = 0; i < len; i++) put_byte(n, im->tib + (v4_cell)i, (unsigned char)text[i]);
put_byte(n, im->tib + (v4_cell)len, 0);
n->mem[im->span] = (v4_cell)len;
v4_rstack_reset(&n->rs);
n->p = im->line;
return 1;
}
int v4_line_done(const v4_node *n, const v4_image *im)
{
return n->p == im->idle;
}
int v4_line_status(const v4_node *n, const v4_image *im)
{
return (int)n->mem[im->line_status];
}