docs(v4.0.0): the ROM is shared code, GA144-style -- an entry table, a permanent state area

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-15 11:10:08 -04:00
co-authored by Claude Opus 5.5
parent 1ed56b93b4
commit 42f8a13914
3 changed files with 44 additions and 6 deletions
+3
View File
@@ -99,6 +99,9 @@ registers (§10.3).
- **ROM.** Designed, not built: `MACHINE.md` §2, and plan Task 1. It is a read-only range at
`V4_NODE_WORDS` and above. It can be fetched and executed. A store there is an address fault.
A reset keeps it.
- Its routines are shared code, GA144-style (`MACHINE.md` 2.1). Payloads call them through
the entry table at the ROM's base. Their state lives in a reserved RAM area. This sheet will
list each entry's stack effect and the registers it uses once the ROM is built.
## 6. Instruction word
+23
View File
@@ -60,6 +60,29 @@ width (32 and 64 bits).
**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.
@@ -48,9 +48,11 @@ notation, Python 3 (the one-time `.v4` → `.f18` converter), GNU make.
branch that goes somewhere else. Test in Task 5.
3. **A symbol defined twice, or an opcode or reserved word used as a name.** Expected: the same
errors as `text.c`'s `define`. Test in Task 4.
4. **The ROM's scratch (symbol table, token buffer) left in RAM after assembly.** Expected: it is
zeroed before `start` jumps, so nothing of the building is left behind (as `mkimage.c` today).
Test in Task 8, in the whole-memory comparison.
4. **The ROM's assembly-only tables (symbol table, references) left in RAM after assembly.**
Expected: they are zeroed before `start` jumps, so nothing of the building is left behind (as
`mkimage.c` today). The routines' permanent state area (MACHINE.md 2.1) is not cleared: it
belongs to the ROM. Test in Task 8, in the whole-memory comparison, which leaves out exactly
that area.
5. **The console input running dry between blobs.** Expected: the ROM waits on
CONSOLE-STATUS and does not take the absence of a character as the end. Test in Task 3.
@@ -207,6 +209,15 @@ through the fault table rather than a field, check it the way `v4/tests/test_gua
`void rom_boot(v4_node *n);` (attach the ROM and the console input),
`int rom_call(v4_node *n, const char *name, unsigned max_steps);` (push a return to an idle
word, set P, run until it returns; 1 if it returned).
- **The entry table (MACHINE.md 2.1).** `main.f18` starts at `V4_ROM_BASE` with one `jump` per
public routine, in a fixed order: `(KEY) (TOKEN) (NUMBER) (FIND) (DEFINE) (OP) (LIT)
(BRANCH) (BRANCH>) (RESOLVE) (LABEL)`, then the ROM's entry. Each task adds its routines'
entries. Tests call routines only through the entry table, as a payload would. `rom-<w>.sym`
still names every internal routine, for debugging.
- **State area.** The routines' state (`(TOK)`, `(LINE)`, the packer's `(HERE) (CUR) (SLOT)
(LITS) (NLIT)`) lives in a reserved RAM area, a constant of the memory map next to
`host_map.h`'s others, outside dictionary space. The assembly-only tables (Task 4's symbol
table and pool, Task 6's references) live in dictionary space.
- ROM routines from `in.f18` (the console input is `CONSOLE-RX`/`CONSOLE-STATUS`, as
`host_map.h`):
- `(KEY) ( -- c )`: wait while CONSOLE-STATUS is 0, then fetch CONSOLE-RX.
@@ -320,7 +331,7 @@ labels local to a word and settled at `end_word`, a bare name as a call (now or
`main.f18` holds the ROM's entry at `V4_ROM_BASE`: clear its scratch, then loop `(TOKEN)` /
directive or `(ONE)`, stopping at an error or at `start`. On error it writes `(ERR)` to
CONSOLE-TX and halts at a known address `(ROM-FAILED)`. `start NAME` does `text.c`
`v4_text_finish` (resolve every reference, "never defined"), zeroes the scratch (Review
`v4_text_finish` (resolve every reference, "never defined"), zeroes the assembly-only tables (Review
Focus 4), and jumps to NAME.
- [ ] **Step 1: Write the failing test.** Five cases:
- `#, 5 ", DUP store 9000 7 set L here #, L` with `start` to a word that does `;`:
@@ -328,7 +339,8 @@ Focus 4), and jumps to NAME.
- A blob split over two feeds, with an EOT only after the second, and a forward call
resolved by a word in the second (Review Focus 1).
- A reference never defined: error, and P at `(ROM-FAILED)`.
- After `start`, every scratch cell is zero.
- After `start`, every assembly-only table cell is zero, and the state area is as the last
routine left it.
- A header written in the directive form gives the same memory as `text.c`'s `header` for
the same name and flags.
- [ ] **Step 2: Run it and see it fail.**
@@ -355,7 +367,7 @@ token for token. `map-<w>.f18` holds:
`mkimage.c` does (`host_load`, `v4_text_finish`, `main`'s stores) and node B by feeding the
ROM `map-<w>.f18` (constants), the 14 `sys/*.f18` files in order, then the rest of
`map-<w>.f18`, then EOT. Run B until P reaches `(IDLE)`. Require every RAM word equal, A to
B. On a difference, print the first address and the symbol at or below it.
B, outside the ROM's state area. On a difference, print the first address and the symbol at or below it.
- [ ] **Step 2: Run it and see it fail.**
- [ ] **Step 3: Write `v4tof18.py`, generate the files, and fix the ROM** until the memory is
equal at both widths. Fix the ROM, not the test. The test is `text.c` and `mkimage.c` as they