diff --git a/docs/v4.0.0/MACHINE.md b/docs/v4.0.0/MACHINE.md new file mode 100644 index 00000000..444a570f --- /dev/null +++ b/docs/v4.0.0/MACHINE.md @@ -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.