feat(v4): the machine has a ROM -- read and run, never written

A read-only range of V4_ROM_WORDS words at V4_ROM_BASE, above RAM
(MACHINE.md 2, DATASHEET-F18.md 5).  Instruction fetch, @p and data fetches
read it; a running programme's store there is an address fault.  Attached by
the owner like every device; a reset detaches it.  The host node's range is
4096 words.  text.c places branches by the whole address space.  The
nucleus image is byte-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-15 11:25:24 -04:00
co-authored by Claude Opus 5.5
parent 42f8a13914
commit 32753f5479
7 changed files with 165 additions and 11 deletions
+25
View File
@@ -57,6 +57,18 @@
#define V4_NODE_WORDS 1024u
#endif
/* THE ROM (docs/v4.0.0/MACHINE.md section 2, DATASHEET-F18.md section 5).
* A read-only range of V4_ROM_WORDS words at V4_ROM_BASE, just above RAM.
* An instruction fetch, an @p literal and a data fetch there read the ROM; a
* running programme's store there is an address fault. In the model it is
* attached, as every device is, and v4_node_reset detaches it: the owner
* attaches it again after a reset. The range's size is a build parameter,
* as RAM's is; 0 (the default) is a machine with no ROM. */
#ifndef V4_ROM_WORDS
#define V4_ROM_WORDS 0u
#endif
#define V4_ROM_BASE ((v4_cell)V4_NODE_WORDS)
/* 5% safety boundary at each end of node memory, per guard.h. Note the
* arithmetic: at 1024 words that is 52 words either side, 5.2% of memory
* spent on a boundary. That is the cost of the convention on a resource that
@@ -83,6 +95,11 @@ typedef struct {
v4_cell mem[V4_NODE_WORDS];
v4_cell mem_guard_tail[V4_MEM_BOUND];
/* The ROM: its words, and how many there are (0: none). See
* v4_node_rom_attach. */
const v4_cell *rom;
unsigned rom_words;
/* CONSOLE-TX capture (DECOMPOSITION.md section 7). See
* v4_node_console_attach below. */
v4_cell console_tx; /* its word address, or -1: no console */
@@ -334,6 +351,14 @@ v4_cell v4_node_fetch(v4_node *n, v4_cell addr);
/* 1 if `addr` is a word of node memory. */
int v4_node_addr_ok(v4_cell addr);
/* 1 if `addr` can be fetched from: a word of node memory, or of the ROM. */
int v4_node_addr_readable(const v4_node *n, v4_cell addr);
/* Give the machine its ROM: `words` words at V4_ROM_BASE, read from `rom`,
* which must outlive the node. More than V4_ROM_WORDS words, or a null
* `rom`, attaches none. v4_node_reset detaches it. */
void v4_node_rom_attach(v4_node *n, const v4_cell *rom, unsigned words);
/* FAULTS (DECOMPOSITION.md D-14 and D-16, ruled 2026-10-04: an address
* outside the node's memory, and a stack pushed when full or popped when
* empty, are guarded; an error is shown; the node returns to its prompt).