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:
co-authored by
Claude Opus 5.5
parent
1ed56b93b4
commit
42f8a13914
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user