docs(v4.0.0): MACHINE.md -- the machine, its ROM, and the capsule: one prebuilt F18 binary, the rest source

For review; nothing built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-15 05:35:38 -04:00
co-authored by Claude Opus 5.5
parent c7bf68fe13
commit 58f3837498
+128
View File
@@ -0,0 +1,128 @@
# StarForth v4.0.0 — The Machine, its ROM, and the Capsule
Design, 2026-10-15. Captain Bob's rulings in conversation the same day, recorded here.
Where this file and `NUCLEUS.md` disagree, this file wins: it replaces `NUCLEUS.md`
sections 2, 4, 5.3 (what is loaded and by whom), 7 (the nucleus line) and 10. `NUCLEUS.md`
section 6 (POST) stands.
**Status: for review. Nothing here is built.**
## 1. The idea
A capsule is a semi-truck. The VM is the tractor. Behind it is the trailer, and the trailer
is source.
The Altair 8800 had the machine and no ROM; a loader was toggled in by hand. v4 has the
machine and a ROM.
| Part | What it is | Where it is |
|---|---|---|
| **Engine** | Executes the 32 F18 opcodes: registers, stacks, memory, ports. Nothing else. | The C golden model (`v4/src`) now; the FPGA later. The two are the same. |
| **ROM** | **The VM.** A prebuilt binary of F18 opcodes. It assembles `.f18` source. It knows no FORTH. | At the head of every capsule; read-only to the node |
| **Trailer** | Source, as named blobs. `.f18` is F18 assembler. `.4th` is FORTH. The blob's name gives its type. | The capsule directory (`capsules/`) |
The ROM is the only binary. It runs the same on the C engine and on the FPGA: one binary, the
same behaviour. Assemble FORTH from the trailer and the node is a FORTH machine. Assemble Lisp
and it would be a Lisp machine. The engine and the ROM do not change.
## 2. The ROM
**What it does.** It reads a named blob and acts on its type:
- `.f18`: assembles it into the node's memory. Mnemonics to slots, literals, labels and
branches, names for addresses.
- `.4th`: hands it, a line at a time, to whatever the `.f18` source has built. The ROM itself
does not interpret FORTH. Until a `.f18` has built an interpreter, a `.4th` cannot be
loaded.
**What it does not do.** No FORTH: no dictionary layout, no `:`, no `INTERPRET`, no
vocabularies. These are `.f18` source.
**How it is made.** The ROM is written in F18 assembler and assembled once, off the node, as a
bitstream is. That build is the only thing done off the node. It produces one ROM per cell
width (32 and 64 bits).
**Read-only.** A store into the ROM is an address fault. Seal and `COLD` never go below it.
## 3. The boot
1. **The machine.** The engine is reset and runs the ROM.
2. **The primitives.** The loader feeds the system's `.f18` blobs to the ROM, which assembles
them. They hold everything written in opcodes: the stack and arithmetic words, the
registers and ports, and the FORTH machinery itself (the text interpreter, `:` and `;`,
the dictionary).
3. **FORTH.** The interpreter just built compiles `forth79.4th`, then the StarForth system
`.4th` words. Ruled: the kernel loads `forth79.4th` as the system's own vocabulary, before
POST and before `init.4th`, the way v3 registers its words.
4. **POST**, with the existing test DSL: the case table `v4/system/post_cases.c` (name, lines,
expected error, stack and output) and its runner `v4/system/post.c`. Seal before it,
`COLD` after, as now.
5. **`init.4th`.** From here the boot is `init.4th` only. It `EXEC`s `starshipos.4th` and sets
`STARSHIPOS` as the search vocabulary. No boot policy is written in C.
6. `ok>`.
The **loader** in steps 2 and 3 is whoever owns the machine: the kernel on bare metal, the
hosted program on Linux, the ARM side on the Zynq. It finds each blob by name, checks its hash
and signature as now (`NUCLEUS.md` 5.3, items 1–3), and gives the source to the node.
## 4. Other nodes
A newborn node blocks on its ports and executes what arrives (`v4_node_born`). Hera births a
node by streaming it the ROM through the port that joins them, then the `.f18` and `.4th`
blobs it is to carry. Today `hera.4th`'s `(NUCLEUS)` streams the prebuilt 311-word nucleus; it
streams the ROM instead.
## 5. What changes
| Today | Becomes |
|---|---|
| `v4/capsule/*.v4`, 14 files, 311 words, assembled on the build machine | `.f18` blobs under `capsules/v4/`, assembled by the ROM at boot |
| `v4/tools/mkimage.c` → `nucleus-64.f18`, a prebuilt dictionary | Builds the ROM only. The nucleus binary is gone. |
| `v4/src/text.c`, the assembler in C | The ROM's assembler is F18 code. `text.c` builds the ROM, as the first assembler builds the next. |
| `forth79.4th`: `U*`, `U/MOD` only | Every FORTH-79 word that is not an opcode, a register or the FORTH machinery (`NUCLEUS.md` 4, rule 1). It moves group by group, with POST after each (`NUCLEUS.md` 8, step 3). |
| `boot_capsules[]` in `v4/system/boot.c` | The system list (step 2, then step 3) is the loader's. Everything after POST is `init.4th`'s. |
| `capsules/v4/starshipos.4th` (uncommitted) | `EXEC`ed by `init.4th` |
### 5.1 v3 leaves the build
v3 goes from every build as though it never existed:
- the `system=` switch and `STARFORTH_V4=0`;
- `v3/src` in the kernel and the hosted `make`;
- the v3 VM (`kernel/src/vm/`, `capsule/`);
- the v3 capsules;
- v3's POST and `PARITY:M7.1a`.
The Tripod, kernel-Hermes, the C ACL and the v3 PKI words go with it. v4 has rebuilt only the
start of the Tripod (`hera.4th`).
POST needs nothing from v3 at run time. `post_cases.c` is committed. `mkpost.py` needs a v3
binary only to write the cases again.
## 6. Order of work
1. **The ROM.** Write the F18 assembler in F18 assembler. Build it with `text.c`. On the C
engine it must assemble today's `.v4` files to the same memory `mkimage.c` produces.
Proof: the same `dict_hash`, `PARITY:V4_POST tests=538 pass=538`.
2. **The trailer.** The `.v4` files become `.f18` blobs. The boot runs ROM, then `.f18`, then
`forth79.4th`, then POST. `mkimage.c` keeps only the ROM.
3. **`init.4th`.** It takes over after POST. `starshipos.4th` is loaded from it.
4. **Hera** streams the ROM, not the nucleus.
5. **FORTH-79 out of the `.f18`**, group by group, into `forth79.4th`, with POST after each.
6. **v3 out of the build.**
Each step is accepted as `.claude/CLAUDE.md` says:
- three ISAs, `clean qemu`, booting v4 to `ok>` with POST passing and `dict_hash` equal across
all three;
- `make -C v4 test-32`.
## 7. For Captain Bob to rule
1. **What the ROM's assembler knows of names.** `text.c` today has `header`, which lays down a
FORTH dictionary entry. That is FORTH, so it belongs in `.f18` source. The ROM would know
only its own symbols: labels and named addresses. Is that the line?
2. **Format of an `.f18` blob.** `.4th` keeps the `Block N` format, 64 × 16. Today's `.v4` has
1080 lines over 64 characters. Proposed: `.f18` is plain text with no block format.
3. **The `v3/` tree.** Deleted, or kept out of every build but left in the repository? Kept,
it lets `mkpost.py` write POST's cases again.
4. **ROM size.** It is whatever the assembler and blob reader take. It is set when step 1 is
built.