Files
LithosAnanake/v4/tests/rom_harness.h
T
rajamesandClaude Opus 5.5 084c520a54 feat(v4): the ROM assembles text as text.c does -- words, labels, macros, FOR, directives, start
word.f18: (NEXT-TOKEN) reads the console or a macro being expanded; labels,
branches by name (a label of the word, or a word, now or later), the
table of branches waiting, end of word, FOR/NEXT/UNEXT, macros, &NAME,
CONST+N, and (ONE), which dispatches a token.  A forward branch to a name
not yet defined waits on a placeholder symbol, filled in by (DEFINE).
dir.f18: constant set here #, ", store, and start, which resolves, clears
the tables the ROM used and runs the word it names.  main.f18: the ROM
itself, entry 12; on an error it stops at (ROM-FAILED) with the code and
line in its state, for the loader to report.  sym.f18 generalized: any
counted string, placeholders, a hash of only a name's own cells.

test_host_rom_asm.c gives test_text.c's own texts (accepted and refused),
its four real definitions and the ROM's directives to text.c and to the
ROM: the same words, the same errors on the same lines, at both widths.
The ROM is 2036 words.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 12:24:08 -04:00

103 lines
3.5 KiB
C

/* rom_harness.h -- run the ROM's routines on a host node, for tests.
*
* The ROM (capsules/v4/rom, built by tools/mkrom.c into $(BINDIR)/rom-<w>.c)
* is attached to a host node as the machine's ROM. A routine is called
* through the ROM's entry table, as a payload calls it (MACHINE.md 2.1): the
* table's order is fixed, and is rom_entries[] below. Where a test needs to
* know whether P is inside a routine, the ROM's symbols are read from
* $(BINDIR)/rom-<w>.sym (V4_ROM_SYM).
*/
#ifndef V4_TESTS_ROM_HARNESS_H
#define V4_TESTS_ROM_HARNESS_H
#include "v4/testcode.h"
#include "host_map.h"
#include <stdio.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
/* The entry table, in its fixed order: entry i is at V4_ROM_BASE + i. */
static const char *const rom_entries[] = {
"(KEY)", "(TOKEN)", "(NUMBER)", "(FIND)", "(DEFINE)", "(OPCODE)",
"(OP)", "(LIT)", "(BRANCH)", "(BRANCH>)", "(RESOLVE)", "(LABEL)", "(ROM)"
};
#define ROM_ENTRIES (sizeof rom_entries / sizeof rom_entries[0])
static v4_exec_state rom_es;
static v4_heat rom_h;
/* The address a payload calls for the routine `name`: its entry. */
static v4_cell rom_entry(const char *name)
{
unsigned i;
for (i = 0; i < ROM_ENTRIES; i++) if (strcmp(rom_entries[i], name) == 0) return V4_ROM_BASE + (v4_cell)i;
printf("rom_harness: %s is not in the entry table\n", name);
return -1;
}
/* Call the routine through its entry. 1 if it returned within `max_words`
* instruction words; 0 if not, and the node is left where it got to, to be
* fed and resumed. */
static int rom_call(v4_node *n, const char *name, long max_words)
{
return v4_test_call(n, &rom_es, &rom_h, rom_entry(name), max_words) >= 0;
}
/* Go on with a call that had not returned. 1 if it now has. */
static int rom_resume(v4_node *n, long max_words)
{
long words = 0;
while (n->p != V4_TEST_HALT) {
if (words++ >= max_words || n->stopped) return 0;
(void)v4_exec_step_word(n, &rom_es, &rom_h);
}
return 1;
}
/* 1 if P is inside the ROM's word `name`: at or after it, and before the
* next word the ROM has. */
static int rom_in(const v4_node *n, const char *name)
{
FILE *f = fopen(V4_ROM_SYM, "r");
char sym[80];
long addr, start = -1, next = -1;
if (!f) { printf("rom_harness: cannot read %s\n", V4_ROM_SYM); return 0; }
while (fscanf(f, "%79s %ld", sym, &addr) == 2)
if (strcmp(sym, name) == 0) start = addr;
rewind(f);
while (fscanf(f, "%79s %ld", sym, &addr) == 2)
if (start >= 0 && addr > start && (next < 0 || addr < next)) next = addr;
fclose(f);
if (start < 0) return 0;
if (next < 0) next = (long)V4_ROM_BASE + (long)ROM_IMAGE_WORDS;
return (long)n->p >= start && (long)n->p < next;
}
/* Reset `n`, attach the ROM and the console's receive registers. */
static void rom_boot(v4_node *n)
{
(void)host_load; /* host_map.h's loader is not used here */
(void)host_branch_slots;
(void)rom_call; /* not every test uses every helper */
(void)rom_resume;
(void)rom_in;
v4_node_reset(n);
v4_exec_reset(&rom_es);
v4_heat_reset(&rom_h);
v4_node_rom_attach(n, ROM_IMAGE, ROM_IMAGE_WORDS);
v4_node_console_input_attach(n, CONSOLE_RX, CONSOLE_ST);
}
#endif /* V4_TESTS_ROM_HARNESS_H */