# 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). **Size.** Whatever it takes. **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 the `.4th` capsules, in three layers (ruled 2026-10-15): 1. **`forth79.4th`**: the FORTH-79 Standard, adhered to 100 percent. 2. **`starforth.4th`**: the StarForth words. 3. **Anything else**: every other system capsule, such as `starshipos.4th`. All three load before POST (section 7, item 4). Ruled: the kernel loads them 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: what must follow `COLD`, such as setting `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) | A system capsule, loaded before POST | ### 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` joins the system capsules. 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. Ruled 2026-10-15 1. **The VM is a machine**: registers, a control unit, the opcodes. Names, dictionary entries (`text.c`'s `header`) and every other part of FORTH are source, not machine. 2. **`.f18` blobs are plain text**, laid out as pretty-printed F18 code. No `Block N` format. 3. **v3 is deleted once v4 is shown at parity with v3, not before.** Until then the `v3/` tree stays, as the reference to compare against and for `mkpost.py`. 4. **Everything that can load before POST does.** That is the system. `forth79.4th`, `starforth.4th` and every other system capsule load before POST. POST tests the system. ## 8. Still open 1. **Where the standard's names live.** "100 percent" in `forth79.4th`: does it name all 130 Required words, including the ones that are single opcodes (`DUP`, `+`, `@`)? Proposed: yes. The `.f18` primitives carry their own names, and `forth79.4th` gives every standard word its standard name and behaviour. The `.f18` layer then holds no FORTH-79 names at all. 2. **What `init.4th` does after POST**, now that the system loads before it: what follows `COLD`, such as making `STARSHIPOS` the search vocabulary and starting Hera's births.