The host node starts in its ROM (entry 12), and the boot feeds it the system's source through the console: capsules/v4/sys/map-64.f18, the fourteen .f18 blobs and end.f18, each found, hash-checked and signature-checked as any capsule, then EOT. The ROM assembles the system and starts it at (IDLE); the host reads the image record (v4_image_from_node) for what only the assembled system knows. A ROM error is reported with its blob, line and meaning, then PARITY:FAIL. Deleted: v4/tools/mkimage.c, capsules/v4/nucleus-64.f18, v4/capsule/*.v4, v4/tools/v4tof18.py. The .f18 files are the source now. - text.c speaks the rest of the ROM's language (set, here, store, start; v4_text_value, v4_text_start), so the oracle reads the same source: test_host_rom_nucleus compares the ROM against text.c on the .f18 files, word for word, image record included. Host tests load the .f18 files. - mkmap image writes v4_map_image (the map's description of the system); hosted and the kernel link the ROM and the map instead of v4_image_64.c. - Hera (Captain Bob's ruling, option 1): births stream the system the ROM assembled, as assembled code; hera.4th is unchanged. test_host_unit's host builds the system with the ROM. - New parity lines: PARITY:V4_F18 per blob, PARITY:V4_ROM words=2049 rom_hash=0xa6c792b5821010b7 instructions=60725216. Acceptance: amd64, aarch64, riscv64 boot to ok> with PARITY:V4_POST tests=538 pass=538 fail=0, POST: PASSED, and PARITY:V4_SYSTEM word_count=317 dict_hash=0xe5a57f3eb72ff94a on all three -- the same hash as the prebuilt nucleus gave. make -C v4 test test-32 hosted-check: all pass. Logs: logs/20261015-141648, -141938, -142350. Startup cost under QEMU TCG, the ROM's assembly (last V4_F18 line to V4_ROM): amd64 26.7 s of 132 s to ok>; aarch64 41.0 s of 195 s; riscv64 20.5 s of 101 s. Hosted native: +0.85 s. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
78 lines
2.5 KiB
C
78 lines
2.5 KiB
C
/* image.c -- the StarForth system, as its host knows it. See image.h.
|
|
*
|
|
* Nothing here uses the C library: the bare-metal kernel links this file.
|
|
*/
|
|
#include "v4/image.h"
|
|
|
|
int v4_image_born(v4_node *n, v4_exec_state *es, v4_heat *h, const v4_image *im)
|
|
{
|
|
if (im->cell_bits != (unsigned)V4_CELL_BITS || im->node_words != (unsigned)V4_NODE_WORDS
|
|
|| im->data_ring != (unsigned)V4_DATA_RING || im->ret_ring != (unsigned)V4_RET_RING)
|
|
return 0;
|
|
|
|
v4_node_born(n, im->port);
|
|
v4_exec_reset(es);
|
|
v4_heat_reset(h);
|
|
|
|
v4_node_console_attach(n, im->console_tx);
|
|
v4_node_console_input_attach(n, im->console_rx, im->console_status);
|
|
v4_node_stack_regs_attach(n, im->dstack_reg, im->rstack_reg);
|
|
v4_node_error_attach(n, im->node_error);
|
|
v4_node_fault_attach(n, im->fault_table);
|
|
return 1;
|
|
}
|
|
|
|
int v4_image_from_node(const v4_node *n, v4_image *im)
|
|
{
|
|
v4_cell r = im->record, idle, faults, key, key_end;
|
|
if (r < 0 || r + 3 >= (v4_cell)V4_NODE_WORDS) return 0;
|
|
idle = n->mem[r]; faults = n->mem[r + 1]; key = n->mem[r + 2]; key_end = n->mem[r + 3];
|
|
if (idle <= 0 || idle >= (v4_cell)V4_NODE_WORDS || faults <= 0 || faults >= (v4_cell)V4_NODE_WORDS
|
|
|| key <= 0 || key_end <= key || key_end >= (v4_cell)V4_NODE_WORDS)
|
|
return 0;
|
|
im->idle = idle;
|
|
im->fault_table = faults;
|
|
im->key_start = key;
|
|
im->key_end = key_end;
|
|
return 1;
|
|
}
|
|
|
|
int v4_image_waiting(const v4_node *n, const v4_image *im)
|
|
{
|
|
return n->input_pos == n->input_len && n->p >= im->key_start && n->p < im->key_end;
|
|
}
|
|
|
|
void v4_image_seal(v4_node *n, const v4_image *im)
|
|
{
|
|
n->mem[im->boot_cells] = n->mem[im->dp];
|
|
n->mem[im->boot_cells + 1] = n->mem[im->latest];
|
|
n->mem[im->fence] = (n->mem[im->dp] + 3) / 4;
|
|
}
|
|
|
|
/* FNV-1a over the node's memory below HERE, a cell at a time, low byte
|
|
* first, and then LATEST. */
|
|
#define FNV_OFFSET 0xcbf29ce484222325ULL
|
|
#define FNV_PRIME 0x00000100000001b3ULL
|
|
|
|
static uint64_t hash_cell(uint64_t h, v4_cell c)
|
|
{
|
|
v4_ucell u = (v4_ucell)c;
|
|
unsigned i;
|
|
for (i = 0; i < V4_CELL_BITS / 8; i++) {
|
|
h ^= (uint64_t)((u >> (8 * i)) & 0xffu);
|
|
h *= FNV_PRIME;
|
|
}
|
|
return h;
|
|
}
|
|
|
|
uint64_t v4_image_dict_hash(const v4_node *n, const v4_image *im)
|
|
{
|
|
uint64_t h = FNV_OFFSET;
|
|
v4_cell here = (n->mem[im->dp] + 3) / 4, k;
|
|
|
|
if (here < 0) here = 0;
|
|
if (here > (v4_cell)V4_NODE_WORDS) here = (v4_cell)V4_NODE_WORDS;
|
|
for (k = 0; k < here; k++) h = hash_cell(h, n->mem[k]);
|
|
return hash_cell(h, n->mem[im->latest]);
|
|
}
|