178 lines
9.0 KiB
Markdown
178 lines
9.0 KiB
Markdown
# 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.
|
||
|
||
### 1.1 What it is for
|
||
|
||
This is an operating system, not a toy (Captain Bob, 2026-10-15). Once everything is assembled
|
||
and compiled, the system is a multi-user, multitasking operating system. That is all the boot
|
||
in section 3 makes.
|
||
|
||
Then the system's init, `init.4th`, brings it up:
|
||
- it turns on security;
|
||
- it starts the system a module at a time and a node at a time;
|
||
- whoever is logged in gets a prompt: Zuse, `rajames`, `00` to `09`, or whoever it is.
|
||
|
||
From the prompt a user can do anything, in FORTH. The operating system's utilities are written
|
||
in FORTH.
|
||
|
||
## 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.
|
||
|
||
### 2.1 The ROM is shared code, GA144-style (ruled 2026-10-15)
|
||
|
||
The ROM is both the tractor's engine and part of the payload's engine. Payload code calls ROM
|
||
routines at run time, as GA144 applications call their node ROMs. The routines are:
|
||
- the tokenizer;
|
||
- number conversion;
|
||
- the slot packer, branch placement and resolution, which is the code generator for any
|
||
language built on top;
|
||
- a generic table from names to values.
|
||
|
||
What this asks of the ROM:
|
||
- **An entry table at the ROM's base**, one jump per routine. Payloads call through it, never
|
||
to an address inside the ROM, so a rebuilt ROM breaks no payload. Each entry's stack effect
|
||
and the registers it uses (A, B) are listed in `DATASHEET-F18.md`.
|
||
- **A reserved, permanent RAM area** for the routines' state (token buffer, packer state),
|
||
fixed in the memory map. Tables needed only while the system assembles may still use
|
||
dictionary space and be cleared afterwards.
|
||
- **Nothing language-specific.** This is the rule of 7.1, which matters more now that every
|
||
payload depends on the ROM.
|
||
|
||
Direction (Captain Bob, 2026-10-15): much more GA144-ish. Take what serves from colorForth's
|
||
wiring, drop its odd concepts, add our own. That is what v4 becomes, on the way to v5 and later.
|
||
|
||
## 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`**, the system's init (section 7, item 6). From here the boot is `init.4th`
|
||
only. 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.
|
||
5. **`forth79.4th` names all 130 Required words**, the single-opcode ones (`DUP`, `+`, `@`)
|
||
included. The `.f18` primitives carry their own names; the `.f18` layer holds no FORTH-79
|
||
names at all.
|
||
6. **`init.4th` is the system's init**, as `init` and its rc files are on a Unix system: it
|
||
initializes the system. Whatever it says runs after POST, and what it says is the system's
|
||
configuration, not part of this design.
|