docs(v4.0.0): the F18 engine in the VM's place -- design

From the rulings of 2026-10-05 and v3's code.  The kernel stays untouched;
what is replaced is the part of a v3 VM that executes FORTH.  Sets out the
interface the kernel reaches a VM through (interpret this text, a
character out, asking the kernel, the stacks and dictionary, a word being
executed, an error, a tick, the dictionary hash), what a node needs for
each, what becomes of the lone-node work, seven steps, and what is open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-05 17:59:17 -04:00
co-authored by Claude Opus 5.5
parent ff53ec4bb4
commit ab7a9bf06f
+179
View File
@@ -0,0 +1,179 @@
# StarForth v4.0.0 — The F18 engine in the VM's place
Design, 2026-10-05. Written from Captain Bob's rulings of that day
(`V3-PARITY.md` sections 1a to 1h, where each is recorded with its words)
and from v3's code. It replaces the lone-node assumptions of `NUCLEUS.md`
sections 5.3 and 7 to 9.
## 1. The principle
`JUSTIFICATION.md` section 16: v4 is equivalent to v3 at any point in time;
"the only difference is the machine underneath: the F18-derived engine
instead of the original StarForth VM."
Ruled 2026-10-05: v4 is exactly like v3 in functional requirements up to
the first FORTH prompt, and that is the stopping point for now. Nothing is
stubbed, simulated or stood in for.
So v4 is not a new system beside LithosAnanke. It is LithosAnanke with a
different machine executing its FORTH.
## 2. What stays, and what is replaced
**Stays, untouched:** everything the kernel does. The Stadium and each
patron's own accounts; sessions; the switcher; kernel-Hermes; the capsule
directory, birth protocol, hashing, signing and parity; the block
subsystem and its devices; identity and Zuse; the HAL console, Hestia, the
console proxies and the kernel's REPL; the heartbeat; the boot order in
`kernel_main.c`.
**Replaced:** the part of a v3 VM that executes FORTH.
| v3 | v4 |
|---|---|
| The inner interpreter (`v3/src/vm.c`, `kernel/src/vm/vm_core.c`) | The node: `v4/src`, 32 opcodes |
| The dictionary as a list of C `DictEntry` records | The dictionary in the node's memory (`v4/capsule/dict.v4`) |
| The FORTH-79 words as C functions (`v3/src/word_source`) | The assembled nucleus (`v4/capsule/*.v4`) and colon definitions in `capsules/v4/forth79.4th` |
| The outer interpreter and compiler in C | The same, in the nucleus |
A v3 VM is also a record the kernel keeps: its identity, its Stadium ID,
its heartbeat state, its place in the registry, its Zuse flags. That
record stays. What changes is what stands behind it.
## 3. The interface
The kernel reaches a VM through a small number of things. Each is listed
with what v3 has, what was ruled, and what a node needs. This is the whole
of the work: when a node answers all of these, the kernel's boot runs on
it as it runs on a v3 VM.
### 3.1 Interpret this text
*v3:* `vm_interpret(vm, text)`. The kernel's REPL hands over each line it
has read; `capsule_exec_payload` hands over each line of a capsule;
kernel-Hermes hands over a message's payload when the target drains its
queue. The VM runs the text and returns, with its error flag set or not.
*Ruled:* the kernel hands a node a whole line and takes characters back;
the node's own prompt loop plays no part at that level. A node receives a
message by being handed its text.
*v4:* the node has an entry that interprets the text in its input buffer
and then stops, saying how the line ended: completed, ended in an error,
or `QUIT`. It prints no prompt and no ` ok`. The buffer takes 1024
characters, a block, as v3's does. `QUIT` and `ABORT` end the line and
return to whoever handed it over. `KEY`, `EXPECT` and `QUERY` stay
FORTH-79 words that read characters.
With this one entry v3's capsule loader, REPL and message drain can all
drive a node, and `v4/system/boot.c`'s own loader is not needed.
### 3.2 A character out
*v3:* the host service `putc`, then `console_putc`; the fabric adds
`[user@VM]`.
*v4:* the node's `EMIT` gives the character to its host, which calls the
same service. Present today.
### 3.3 Asking the kernel
*v3:* a kernel word is a C function registered in the VM's dictionary:
`BIRTH`, `KILL`, `USE`, the block words, the Stadium and Hermes words, the
framebuffer words. It takes its arguments from the VM's data stack.
*Ruled:* a node asks for a block by number and the kernel decides the
rest; a node sends a message by asking.
*v4:* a kernel word is a dictionary entry on the node whose code hands a
request to the kernel, with its arguments on the node's data stack. The
C functions are v3's. **How the request is carried is not designed yet**
and is the first thing step 2 settles.
### 3.4 The stacks and the dictionary, from the kernel's side
*v3:* `vm_push`, `vm_pop`, `vm_find_word`, and the fields of a
`DictEntry` (the kernel pins `BIRTH` and `CAPSULE-BIRTH` by setting two of
them).
*v4:* the same operations on the node's stacks and on entries in the
node's memory.
### 3.5 A word is being executed
*v3:* the inner loop, for every word: the ACL's countdown and recheck,
`execution_heat`, `stadium_word_dispatch`, the rolling window, pipelining.
*Ruled:* the word card stays exactly as v3 — a run-time check, the TTL
adaptive from the word's own count. Every kind of patron keeps its own
accounts; the word's are as v3. Opcodes are counted and left unwired.
*v4:* the node dispatches a word at the `call` opcode, one place in the
engine. The node does there what v3's loop does. A word that is to be
checked must be called, so the in-line words that can be called become
calls.
### 3.6 An error
*v3:* `vm->error`. *v4:* how a line ended (3.1), and the node's error
register for a C function to raise one.
### 3.7 A tick
*v3:* the kernel's timer drives `vm_tick` and the heartbeat state in the
VM's record. *v4:* unchanged; that state is the record's, not the
engine's.
### 3.8 The dictionary hash
*v3:* `vm_dict_hash_fn`, a hook the birth protocol calls. *v4:* the same
hook, answered from the node's dictionary.
## 4. What was built on the detour
| Built 2026-10-05 | What becomes of it |
|---|---|
| `kernel_main.c` calling `sk_v4_run()` before the fleet tables | Goes at step 4. Until then it is how the bare-metal build is kept booting while the interface is built. |
| `v4/system/boot.c`: its own capsule loader and `PARITY:V4_*` lines | Goes at step 4, when v3's birth protocol loads the capsules and prints v3's parity lines. |
| The node's prompt loop, and the code that strips ` ok` from its output | Goes at step 1. |
| `capsules/v4/forth79.4th`, `post79.4th`, `mkpost.py`, the rules | Stay. POST is the gate for every word moved out of the nucleus. |
| `(CATCH)`, `(EMIT-HOOK)`, `NODE-ERROR` by name | Stay; POST uses them. |
| The per-call-target count (`v4/src/heat.c`, `call[]`) | Goes at step 3, when the node does at `call` what v3 does. |
| The hosted Linux product | Stays, on the same interface. Hosted v3 has no fleet and neither has hosted v4. |
## 5. Steps
Each ends with all six builds booting and agreeing, and is committed with
its logs.
1. **Interpret this text (3.1).** The node's line entry; no prompt loop.
The hosts print the prompt and ` ok`, as v3's REPL does.
2. **Asking the kernel, and the stacks from the kernel's side (3.3,
3.4).** Settle how a request is carried. Kernel words callable from a
node.
3. **A word is being executed (3.5).** The hook at `call`; the ACL's
countdown and recheck; the word's count; `stadium_word_dispatch`.
In-line words become calls. The per-call-target count goes.
4. **In place.** Under `STARFORTH_V4` the kernel's own boot brings the
node up where it brings a v3 VM up, after the fleet tables; the
kernel's REPL drives it; blocks come from the block subsystem.
`sk_v4_run()` and `boot.c` go.
5. **Hera as v3 has her.** `init.4th` runs on the node; v3's whole POST;
v3's parity lines.
6. **The fleet.** Hestia and Artemis; message delivery; the switcher.
7. **Identity and the prompt.** Zuse; `[zuse@Hera] ok>`.
Moving words from the assembled nucleus to `forth79.4th` goes on beside
these, a group at a time, with POST after each.
## 6. Open, and where each must be settled
| Open | Before |
|---|---|
| How a node's request to the kernel is carried | Step 2 |
| How the node tells a dictionary entry from a bare address at `call` | Step 3 |
| `EXECUTE`, which enters a word by a return | Step 3 |
| `>R R> R@ I J LEAVE`, which cannot be called | Step 3 |
| The node's safe moment for message delivery and switching | Step 6 |
| `PAD 42 OVER !`, a byte address given to `!` (D-1) | Step 5 |
| Which word patrons' accounts the hosted product keeps, having no Stadium | Step 3 |