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
@@ -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