Files
LithosAnanake/v4/tools/hosted.c
T
rajamesandClaude Opus 5.5 8df6c16766 feat(v4.0.0): a node asks its kernel by a blocking write to its port
ENGINE.md step 2, the carrier.  Ruled 2026-10-05 (V3-PARITY.md 1i), on
DECOMPOSITION.md section 6: a write to a port blocks until the neighbour
reads.

- node: v4_node_port_attach, v4_node_port_served; a store to the port keeps
  the value as the request and blocks the node
- exec: a blocked node executes nothing; served, it goes on from the opcode
  after the store, in the same instruction word; a fault meanwhile abandons
  the rest of the word
- compile.v4: n KERNEL-WORD name makes a word whose body writes n to the
  port; its arguments and results are on the data stack
- boot: the kernel's words are made by handing the node text, and requests
  are served between the node's opcodes; one no one serves is error 12
- BYE, the first kernel word: hosted it leaves the program, as hosted v3;
  on the lone node it is v3's cold restart
- ENGINE.md 3a: multiuser, multitasking, preemptive and cooperative, and
  what that asks of the engine

Verified: make -C v4 test passes at both widths, with tests/test_port.c;
hosted-check passes on three ISAs; clean qemu with STARFORTH_V4=1 on amd64,
aarch64 and riscv64 passes POST with the same hashes as hosted, and a
kernel word no one serves and BYE typed at each prompt are answered
(logs/20261005-185506, -185734, -190101; -185234 is an amd64 run in which
those two lines were not typed).

Not done: v3's own C functions serving a node.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 19:03:03 -04:00

78 lines
2.5 KiB
C

/* hosted.c -- StarForth v4 as a Linux program: the nucleus image on the
* golden model, its capsules loaded as the system comes up (v4/include/v4/
* boot.h, the same boot the bare-metal kernel runs), the console on stdin
* and stdout.
*
* It runs until its input ends. Blocks are kept in memory and are gone
* when it stops.
*/
#include "v4/boot.h"
#include <stdio.h>
#include <string.h>
#define BLOCKS 64u
static v4_node n;
static v4_exec_state es;
static v4_heat h;
static unsigned char disk[BLOCKS * V4_BLOCK_BYTES];
static void console_out(const char *text, unsigned len)
{
(void)fwrite(text, 1, len, stdout);
}
/* a character for a line that reads the keyboard */
static int console_key(void)
{
int c;
fflush(stdout);
c = getchar();
return c == EOF ? V4_BOOT_KEY_END : c;
}
/* THE KERNEL'S WORDS, for a node that is a Linux program: the words that
* are C in hosted v3 because only the host can do them. */
static const char *const kernel_words[] = { "BYE" };
static int leaving;
static void serve(v4_node *node, unsigned request)
{
(void)node;
if (request == 1) { /* BYE ( -- ): as hosted v3, say so and leave */
fputs("Goodbye!\n", stdout);
leaving = 1;
}
}
/* The prompt is the host's, as it is the kernel's REPL's for a v3 VM: read a
* line, hand it to the node, say how it ended. */
int main(void)
{
static char line[1026];
v4_boot boot;
boot.n = &n; boot.es = &es; boot.h = &h; boot.im = &v4_capsule_image;
boot.out = console_out; boot.key = console_key;
boot.words = kernel_words; boot.word_count = sizeof kernel_words / sizeof kernel_words[0]; boot.serve = serve;
if (!v4_boot_run(&boot, disk, BLOCKS)) { fflush(stdout); return 1; }
for (;;) {
size_t len;
int how;
fputs("ok> ", stdout);
fflush(stdout);
if (!fgets(line, sizeof line, stdin)) { putchar('\n'); return 0; }
len = strlen(line);
if (len && line[len - 1] == '\n') len--;
how = v4_boot_line(&boot, line, (unsigned)len);
if (how == V4_LINE_COMPLETED) fputs(" ok\n", stdout);
if (leaving) { fflush(stdout); return 0; }
else if (how == V4_LINE_ERROR) fputs(" ERROR\n", stdout);
else if (how == V4_BOOT_LINE_TOO_LONG) fputs("Line too long\n ERROR\n", stdout);
else if (how == V4_BOOT_LINE_NO_INPUT) { putchar('\n'); return 0; }
else if (how == V4_BOOT_LINE_STOPPED) { fflush(stdout); fprintf(stderr, "starforth4: the node stopped on a fault\n"); return 1; }
}
}