Files
LithosAnanake/docs/v4.0.0/MACHINE.md
T

7.3 KiB
Raw Blame History

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 capsule, such as starshipos.4th.

    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 EXECs 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) EXECed 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. Where starforth.4th loads. Proposed: with forth79.4th, by the kernel and before POST, because v3's StarForth words are system words and v3's POST covers them. Layer 3 is init.4th's.
  5. 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.