feat(v4): the system's UM*, UM/MOD, D+, DNEGATE, Q.* and Q./ call the ROM

MACHINE.md 2.2.  Each is its entry's address, push and ;.  Every node the
tests make carries the host ROM (host_load, Hera's births, the depth and
mesh tests' own nodes), and a division by zero inside the ROM returns to
the prompt (hosted-check).  test_host_quit's fetch outside memory moves
past the ROM's range: 16384 is the ROM's first word now the tests' system
has its ROM, as the product's always had.  dict_hash 0xfec8c47cfc6f437f.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-15 20:16:50 -04:00
co-authored by Claude Opus 5.5
parent 11b5d402b1
commit afd9d46d29
14 changed files with 123 additions and 126 deletions
+24
View File
@@ -13,6 +13,7 @@
#define V4_TESTS_HOST_MAP_H
#include "v4/rom_errors.h"
#include "v4/rom_entries.h"
#include "v4/blocks.h"
#include "v4/text.h"
#include <stdio.h>
@@ -361,6 +362,25 @@ static unsigned host_branch_slots(void)
X("CFBASE", CFS_W) \
X("CFEND", CFS_W + CFS_CELLS)
/* The host node's ROM (MACHINE.md 2), which the tests that link it attach:
* the system calls its math there (MACHINE.md 2.2). */
#if V4_CELL_BITS == 64
extern const v4_cell v4_rom_64[];
extern const unsigned v4_rom_64_words;
#define ROM_IMAGE v4_rom_64
#define ROM_IMAGE_WORDS v4_rom_64_words
#else
extern const v4_cell v4_rom_32[];
extern const unsigned v4_rom_32_words;
#define ROM_IMAGE v4_rom_32
#define ROM_IMAGE_WORDS v4_rom_32_words
#endif
/* The shared ROM entries (MACHINE.md 2.2), as constants ROM-UM* ...: each
* the address of its entry, from the one list (v4/rom_entries.h). The
* system's six words of those names call these. */
#define HOST_ROM_ENTRY_CONSTANT(i, routine, forth, effect) v4_text_constant(tx, "ROM-" forth, V4_ROM_BASE + (v4_cell)(i));
static int host_load(v4_text *tx, v4_node *n, const char *const *files, unsigned count)
{
char path[512];
@@ -372,7 +392,11 @@ static int host_load(v4_text *tx, v4_node *n, const char *const *files, unsigned
#define HOST_CONSTANT(name, value) v4_text_constant(tx, name, (v4_cell)(value));
HOST_CONSTANTS(HOST_CONSTANT)
#undef HOST_CONSTANT
V4_ROM_MATH_ENTRIES(HOST_ROM_ENTRY_CONSTANT)
v4_node_stack_regs_attach(n, DSTACK_REG, RSTACK_REG);
#ifdef V4_ROM_LINKED
v4_node_rom_attach(n, ROM_IMAGE, ROM_IMAGE_WORDS); /* the system calls its math in the ROM (MACHINE.md 2.2) */
#endif
for (i = 0; i < count; i++) {
snprintf(path, sizeof path, "%s/%s", V4_SYS_DIR, files[i]);
if (!v4_text_assemble_file(tx, path)) {
-12
View File
@@ -18,18 +18,6 @@
#include <stdlib.h>
#include <string.h>
#if V4_CELL_BITS == 64
extern const v4_cell v4_rom_64[];
extern const unsigned v4_rom_64_words;
#define ROM_IMAGE v4_rom_64
#define ROM_IMAGE_WORDS v4_rom_64_words
#else
extern const v4_cell v4_rom_32[];
extern const unsigned v4_rom_32_words;
#define ROM_IMAGE v4_rom_32
#define ROM_IMAGE_WORDS v4_rom_32_words
#endif
/* A mesh node's ROM (MACHINE.md 2.2): the shared math only. */
#if V4_CELL_BITS == 64
extern const v4_cell v4_mesh_rom_64[];
+1
View File
@@ -144,6 +144,7 @@ static unsigned starforth_node(unsigned k)
int id = v4_fabric_add(&f, &pool[k], PORT);
v4_node *n = &pool[k].n;
memcpy(n->mem, nucleus.mem, sizeof n->mem);
v4_node_rom_attach(n, ROM_IMAGE, ROM_IMAGE_WORDS); /* the nucleus calls its math in the ROM (MACHINE.md 2.2) */
v4_node_stack_regs_attach(n, DSTACK_REG, RSTACK_REG);
v4_node_error_attach(n, NODE_ERROR);
v4_node_fault_attach(n, w_fault);
+1
View File
@@ -174,6 +174,7 @@ static unsigned starforth_node(unsigned k)
int id = v4_fabric_add(&f, &pool[k], PORT);
v4_node *n = &pool[k].n;
memcpy(n->mem, nucleus.mem, sizeof n->mem);
v4_node_rom_attach(n, ROM_IMAGE, ROM_IMAGE_WORDS); /* the nucleus calls its math in the ROM (MACHINE.md 2.2) */
v4_node_stack_regs_attach(n, DSTACK_REG, RSTACK_REG);
v4_node_error_attach(n, NODE_ERROR);
v4_node_fault_attach(n, w_fault);
+1 -1
View File
@@ -985,7 +985,7 @@ int main(void)
/* ---- an address outside memory (D-14): a message, ERROR, and the prompt ---- */
{
static const char *const lines[] = {
"65 EMIT -1 @ 66 EMIT\n", "65 EMIT 5 -1 ! 66 EMIT\n", "65 EMIT 16384 @ 66 EMIT\n", "65 EMIT 5 16384 ! 66 EMIT\n",
"65 EMIT -1 @ 66 EMIT\n", "65 EMIT 5 -1 ! 66 EMIT\n", "65 EMIT 20480 @ 66 EMIT\n", "65 EMIT 5 16384 ! 66 EMIT\n",
"65 EMIT 99999999 C@ 66 EMIT\n", "65 EMIT 7 -4 C! 66 EMIT\n", "65 EMIT -1 EXECUTE 66 EMIT\n", "65 EMIT 1 -1 +! 66 EMIT\n",
"65 EMIT PAD -8 4 CMOVE 66 EMIT\n", "65 EMIT -9 COUNT 66 EMIT\n", "65 EMIT -9 3 TYPE 66 EMIT\n",
": F0 -1 @ ; : F1 F0 ; : F2 F1 ; : F3 65 EMIT F2 66 EMIT ; F3 67 EMIT\n",
+61
View File
@@ -126,6 +126,65 @@ static int entry_jumps_to(const v4_cell *rom, unsigned i, const char *sym, const
&& v4_iword_branch(V4_ROM_BASE + (v4_cell)i, w, 0) == (v4_cell)target;
}
/* THE SYSTEM CALLS THE ROM. The system as text.c builds it (host_load, the
* ROM attached): each of the six words is a literal of its entry's address,
* then push, then ; -- it goes to the entry and the entry's ; returns to the
* word's caller -- and it gives the table's results. On a node with no ROM
* the call faults rather than computing anything. */
static v4_text tx;
static int system_cases(void)
{
static const char *const files[] = {
#define SYS_FILE_NAME(file) #file ".f18",
V4_SYS_FILES(SYS_FILE_NAME)
#undef SYS_FILE_NAME
};
unsigned k;
if (!host_load(&tx, &n, files, (unsigned)(sizeof files / sizeof files[0])) || !v4_text_finish(&tx)) {
printf(" the system does not assemble: %s\n", v4_text_error(&tx));
return 0;
}
#define CHECK_CALLS(i, routine, forth, effect) { \
v4_cell w = v4_text_word(&tx, forth); \
v4_iword iw = w >= 0 ? (v4_iword)((v4_ucell)n.mem[w] & 0xFFFFFFFFu) : 0; \
CHECK(w >= 0 && v4_iword_op(iw, 0) == V4_OP_FETCH_P && v4_iword_op(iw, 1) == V4_OP_PUSH && v4_iword_op(iw, 2) == V4_OP_SEMI \
&& n.mem[w + 1] == V4_ROM_BASE + (v4_cell)(i), "the system's %s is the ROM's entry %d, then push and ;", forth, i); }
V4_ROM_MATH_ENTRIES(CHECK_CALLS)
#undef CHECK_CALLS
for (k = 0; k < CASES; k++) {
static const char *const forth_of[] = {
#define FORTH_NAME(i, routine, forth, effect) forth,
V4_ROM_MATH_ENTRIES(FORTH_NAME)
#undef FORTH_NAME
};
const math_case *c = &cases[k];
v4_cell got[2] = { 0, 0 };
unsigned i;
int ok;
v4_dstack_reset(&n.ds); v4_rstack_reset(&n.rs); v4_exec_reset(&rom_es); v4_heat_reset(&rom_h);
n.mem[NODE_ERROR] = 0;
v4_dstack_push(&n.ds, CANARY);
for (i = 0; i < c->argc; i++) v4_dstack_push(&n.ds, c->in[i]);
ok = v4_test_call(&n, &rom_es, &rom_h, v4_text_word(&tx, forth_of[c->entry]), 10000000L) > 0;
for (i = c->outc; i-- > 0; ) got[i] = v4_dstack_pop(&n.ds);
CHECK(ok && v4_dstack_pop(&n.ds) == CANARY && got[0] == c->out[0] && got[1] == c->out[1] && n.mem[NODE_ERROR] == c->error,
"the system's %s, case %u: got %lld %lld error %lld", forth_of[c->entry], k,
(long long)got[0], (long long)got[1], (long long)n.mem[NODE_ERROR]);
}
/* the same system with its ROM taken away: UM* does not return */
v4_node_rom_attach(&n, ROM_IMAGE, 0u);
v4_dstack_reset(&n.ds); v4_rstack_reset(&n.rs); v4_exec_reset(&rom_es); v4_heat_reset(&rom_h);
v4_dstack_push(&n.ds, 12345); v4_dstack_push(&n.ds, 67890);
{
unsigned faults = n.faults;
long r = v4_test_call(&n, &rom_es, &rom_h, v4_text_word(&tx, "UM*"), 100000L);
CHECK(r <= 0 && n.faults > faults && n.fault_kind == V4_FAULT_ADDRESS && n.fault_addr == V4_ROM_BASE,
"with no ROM, the system's UM* faults at the ROM's address and computes nothing: returned %ld, %u faults, kind %u at %lld",
r, n.faults - faults, n.fault_kind, (long long)n.fault_addr);
}
return 1;
}
int main(void)
{
printf("v4 ROM math tests: V4_CELL_BITS=%d\n", V4_CELL_BITS);
@@ -151,6 +210,8 @@ int main(void)
cases_on("host", ROM_IMAGE, ROM_IMAGE_WORDS);
cases_on("mesh", MESH_ROM, MESH_ROM_WORDS);
CHECK(system_cases(), "the system the tests build with text.c");
printf(" %d checks, %d failures\n", checks, failures);
return failures != 0;
}
+1
View File
@@ -143,6 +143,7 @@ static int host_born(void *self)
v4_node_stack_regs_attach(&pool[k].n, DSTACK_REG, RSTACK_REG);
v4_node_error_attach(&pool[k].n, NODE_ERROR);
v4_node_fault_attach(&pool[k].n, w_fault);
v4_node_rom_attach(&pool[k].n, ROM_IMAGE, ROM_IMAGE_WORDS); /* the nucleus calls its math in the ROM (MACHINE.md 2.2) */
v4_blocks_init(&node_blocks[k], BUF0_W);
if (k != 0) { /* Hera's kernel is wired where she is made */
node_kernel[k].take = node_kernel_take; node_kernel[k].give = 0; node_kernel[k].self = &pool[k];