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>
v4/
StarForth v4: the 32-instruction F18-derived core. The design lives in
docs/v4.0.0/JUSTIFICATION.md (why) and docs/v4.0.0/DECOMPOSITION.md
(every v3 word mapped to a v4 fate).
The first deliverable is the hosted C99 golden model (JUSTIFICATION.md §10,
step 1). It must pass POST and hold K≡1.0 with 32- and 64-bit cells on all
three host ISAs.
Acceptance (JUSTIFICATION.md §16): v4 must be equivalent to v3 at any point
in time, with the same vocabularies and behaviour, on the F18-derived engine;
and every ISA, hosted and bare metal, must still reach its ok prompt.
make -C v4 test passing is a development check, not acceptance.
What exists so far is the single node: registers, circular stacks, memory, all
32 opcodes, per-opcode and per-call-target heat, and three console
registers (CONSOLE-TX, which captures output, and CONSOLE-RX and CONSOLE-STATUS, which hand out
input a test feeds) standing in for the console node until the mesh exists. The tests load definitions
onto a node either opcode by opcode (v4/include/v4/asm.h) or as text in the notation DECOMPOSITION.md
uses (v4/include/v4/text.h). make -C v4 test builds
and runs the tests at both cell widths; make -C v4 sanitize repeats them
under ASan and UBSan. There is no POST and no K measurement yet.
The system: nucleus, capsules, prompt
docs/v4.0.0/NUCLEUS.md is the design. A v4 system is four things:
| Part | Where | What it is |
|---|---|---|
| Engine | v4/src |
The golden model of the 32-opcode node |
| Nucleus | v4/capsule/*.v4, built by v4/tools/mkimage.c |
The assembled words, as a memory image linked into the binary |
| Capsules | capsules/v4/*.4th, baked by tools/mkcapsule.c |
FORTH source, loaded when the system comes up |
| Boot | v4/system/boot.c |
Starts the nucleus, checks and loads each capsule, prints the parity lines, gives the prompt |
Two products link the same four and differ only in the console:
- Hosted Linux,
v4/tools/hosted.c:make -C v4 hostedbuildsv4/build/starforth4-amd64,-aarch64and-riscv64, static, 64-bit cells. - Bare metal,
kernel/src/v4/sk_v4.c:make -f kernel/Makefile ARCH=<arch> STARFORTH_V4=1.
A boot prints:
PARITY:V4_NUCLEUS words=292 image_hash=0x...
PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=0x... capsule_hash=0x... dict_hash=0x...
PARITY:OK
ok>
Every build of one commit prints the same hashes. make -C v4 hosted-check
boots the three hosted binaries (the two foreign ones under user-mode QEMU)
and fails unless their output is identical and ends in PARITY:OK.
A capsule line the node does not answer ok to ends the boot, naming the
capsule, block and line, with PARITY:FAIL and POST: FAILED.
State, 2026-10-05, after ENGINE.md step 1: all six builds start the nucleus,
load v4:forth79.4th, pass POST and reach ok>, with the same lines:
PARITY:V4_NUCLEUS words=296 image_hash=0x736921433a2e0e97
PARITY:V4_CAPSULE name=v4:forth79.4th capsule_id=... dict_hash=0x01a3a48159f28a3e
PARITY:V4_POST tests=550 pass=550 fail=0
PARITY:V4_CAPSULE name=v4:post79.4th capsule_id=... dict_hash=0x212b7b70848080e7
PARITY:OK
POST: PASSED
ok>
Bare-metal logs: logs/20261005-185506/amd64/, logs/20261005-185734/aarch64/,
logs/20261005-190101/riscv64/. On each, six lines were then typed at the
prompt through the serial port — a definition, its use with the capsule's
U*, an unknown word, a kernel word no one serves, and BYE — and each
was answered as the hosted binary answers it. The
capsules were unsigned (no signing key on this machine).
A node is handed a line (docs/v4.0.0/ENGINE.md 3.1). It does not read
its own command line and prints no prompt. Its host puts the text in the
node's input buffer and starts it at (LINE); the node interprets the text
and stops at (IDLE), leaving in (LINE-STATUS) how it ended. 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. v4_line_begin, v4_line_done and
v4_line_status (v4/include/v4/image.h) are that interface;
v4_boot_line (v4/system/boot.c) is the one loop the hosted binary, the
kernel and the capsule loader all run it with.
A node asks its kernel by writing to its port (ENGINE.md 3.3). The
write blocks the node until it has been served. A kernel word is a
dictionary entry made by n KERNEL-WORD name, whose body writes n to the
port; its arguments and results are on the data stack. BYE is the one
kernel word so far. A node can be stopped between any two instruction
words and is blocked while it waits at its port, which is what a system of
many users and tasks, preemptive and cooperative, needs of it
(ENGINE.md 3a).
This is still the lone node. On bare metal kernel_main.c starts it
before the fleet tables, beside the kernel's own system and not in the VM's
place. ENGINE.md sets out the steps from here; step 1 is done and step 2 is
part done. V3-PARITY.md records the rulings it is built from.
What this does not yet show. forth79.4th holds two definitions, U*
and U/MOD. Every other word is still in the assembled nucleus, so POST is
so far a test of the assembled words. Moving them to the capsule, a group at
a time with POST after each, is the next step (NUCLEUS.md section 8).
POST
capsules/v4/post79.4th: 550 cases in blocks 7000 up, covering 126 of the
130 words of the FORTH-79 Required Word Set. 443 are v3's cases with what
the hosted v3 binary did as the expected result. The other 107, and the 27
v3 cases left out, are listed with reasons in docs/v4.0.0/POST79.md.
make -C v4 postboots the amd64 system: the quick check after a change.make -C v4 hosted-checkboots all three hosted ISAs and compares them.make -C v4 post79writes the capsule again (tools/mkpost.py,tools/post79_rules.py); it needs the hosted v3 binary.
POST is FORTH: a harness of FORTH-79 words and two nucleus hooks, (CATCH)
and (EMIT-HOOK). It forgets itself when it has finished. The boot passes
only on seeing POST's tally line with fail=0 (v4/system/boot.c). A colon
definition broken on purpose (U/MOD without its last SWAP) fails five
cases and the boot stops with POST: FAILED.
Not tested: KEY, EXPECT, QUERY (the keyboard) and QUIT (it returns
without ok).
Open: PAD 42 OVER ! faults on v4, because PAD is a byte address and !
takes a cell address (D-1). FORTH-79 expects it to work. The v3 case for it
is left out until that is ruled.
The Required Word Set list in tools/mkpost.py was written from memory of
the standard and has not been checked against the document.