/* SPDX-License-Identifier: LicenseRef-Starship-1.0 * Copyright (c) 2023-2026 Robert A. James */ /* test_mesh_boot.c -- the kernel's boot of the fabric (v4/mesh.h), on the host, with this program as * its owner, as the kernel will be (#189, ENGINE step 4 Phase 1, Task 5b; Captain Bob, 2026-11-13: * "Build it to proper spec"). No scheduler: every node steps together. * * The boot: the nucleus assembled by the ROM, Hera born empty and given it, FORTH-79, POST, the * kernel's capsules -- and the same parity lines v4_boot_run prints. Then: a line; NODE-ME; a node * born (11 2 2 BIRTH), given the nucleus and FORTH-79 by Hera, answering a line of its own; and * killed, its room given back. * * Linked as the hosted product is (v4/Makefile), with mesh.c, manage.c and a mesh node's ROM. */ #include "v4/mesh.h" #include "v4/message.h" #include "block_subsystem.h" #include #include static int failures = 0, checks = 0; #define CHECK(c,...) do{checks++; if(!(c)){failures++; printf("FAIL %s:%d: ",__FILE__,__LINE__); printf(__VA_ARGS__); printf("\n");}}while(0) #define PLACES 8u static v4_place places[PLACES]; static v4_wire_queue queues[32]; static v4_manage_entry reg[PLACES]; static v4_blocks blocks[PLACES]; static v4_device kernel[PLACES]; static v4_fabric_node nucleus, hera, pool[PLACES]; static int used[PLACES]; static unsigned roomed, given_back, borns, gones, parities; static v4_image im; static v4_mesh ms; static int no_room; /* the owner has no room to give */ static v4_fabric_node *room(void *self) { unsigned k; (void)self; if (no_room) return 0; for (k = 0; k < PLACES; k++) if (!used[k]) { used[k] = 1; roomed++; return &pool[k]; } return 0; } static void unroom(void *self, v4_fabric_node *x) { (void)self; used[x - pool] = 0; given_back++; } static void born(void *self, unsigned place) { (void)self; (void)place; borns++; } static void gone(void *self, unsigned place) { (void)self; (void)place; gones++; } static void parity(void *self, unsigned place, v4_cell number, const v4_node *n) { (void)self; (void)place; (void)number; (void)n; parities++; } static char said[1u << 16]; static unsigned said_len; static void out(const char *text, unsigned len) { if (said_len + len + 1 < sizeof said) { memcpy(said + said_len, text, len); said_len += len; said[said_len] = 0; } } static int key(void) { return V4_BOOT_KEY_END; } static const char *const words[] = { "BYE" }; static unsigned served; static void serve(v4_node *n, unsigned request) { (void)n; if (request == 1) served++; } static const char *const capsules[] = { "v4:centre.4th", "v4:hera.4th" }; static unsigned char ram[(size_t)BLK_RAM_BLOCKS * BLK_FORTH_SIZE]; extern void sf_time_init(void); extern void log_set_level(int level); /* what a line printed, and how it ended */ static const char *line(v4_cell node, const char *text, int *how) { said_len = 0; said[0] = 0; *how = v4_mesh_tell(&ms, node, text, (unsigned)strlen(text)); return said; } int main(void) { int how; const char *r; printf("v4 mesh boot: V4_CELL_BITS=%d\n", V4_CELL_BITS); sf_time_init(); log_set_level(-1); CHECK(blk_subsys_init(ram, sizeof ram) == BLK_OK, "the kernel's blocks"); im = v4_map_image; ms.places = places; ms.capacity = PLACES; ms.queues = queues; ms.queue_count = sizeof queues / sizeof queues[0]; ms.reg = reg; ms.blocks = blocks; ms.nucleus = &nucleus; ms.hera = &hera; ms.kernel = kernel; ms.room = room; ms.unroom = unroom; ms.born = born; ms.gone = gone; ms.parity = parity; ms.out = out; ms.key = key; ms.words = words; ms.word_count = 1; ms.serve = serve; ms.capsules = capsules; ms.capsule_count = 2; ms.im = &im; ms.self = 0; /* ---- the boot ---- */ CHECK(v4_mesh_boot(&ms) == 1, "the boot: %s", said); CHECK(strstr(said, "PARITY:V4_ROM ") != 0, "the ROM assembled the nucleus, and said so"); CHECK(strstr(said, "PARITY:V4_CAPSULE name=v4:forth79.4th ") && strstr(said, "PARITY:V4_CAPSULE name=v4:centre.4th ") && strstr(said, "PARITY:V4_CAPSULE name=v4:hera.4th "), "FORTH-79 and the kernel's capsules, each with its parity line"); CHECK(strstr(said, "PARITY:V4_POST tests=539 pass=539 fail=0") != 0, "POST passes on Hera, born in the fabric"); CHECK(strstr(said, "PARITY:V4_SYSTEM word_count=") && strstr(said, "PARITY:OK\nPOST: PASSED\n"), "the system line, and POST: PASSED"); if (failures) { printf(" %d checks, %d failures\n", checks, failures); return 1; } /* ---- lines, as messages ---- */ r = line(V4_MESH_HERA, "3 4 + .", &how); CHECK(how == V4_TEXT_COMPLETED && strcmp(r, "7 ") == 0, "a line to Hera: \"%s\" (%d)", r, how); r = line(V4_MESH_HERA, "NODE-ME .", &how); CHECK(how == V4_TEXT_COMPLETED && strcmp(r, "0 ") == 0, "NODE-ME: Hera is at place 0: \"%s\"", r); r = line(V4_MESH_HERA, "NOSUCH", &how); CHECK(how == V4_TEXT_ERROR && strstr(r, "UNKNOWN WORD") != 0, "an unknown word ends in an error: \"%s\"", r); r = line(V4_MESH_HERA, "BYE", &how); CHECK(served == 1, "a kernel word is served by the owner"); /* ---- a birth, and a kill ---- */ r = line(V4_MESH_HERA, "11 2 2 BIRTH .", &how); CHECK(how == V4_TEXT_COMPLETED && roomed == 1 && borns == 1 && parities == 1, "11 2 2 BIRTH: a node is born in the owner's room, given the system, and its parity recorded: \"%s\" (%d)", r, how); CHECK(v4_mesh_node(&ms, 11) != 0, "node 11 is in the fabric"); r = line(11, "6 7 * .", &how); CHECK(how == V4_TEXT_COMPLETED && strcmp(r, "42 ") == 0, "node 11 answers a line of its own: \"%s\" (%d)", r, how); r = line(V4_MESH_HERA, "S\" 6 7 * .\" 11 SEND 11 AWAIT .", &how); CHECK(how == V4_TEXT_COMPLETED && strstr(r, "42 ") && strstr(r, "1 "), "and through Hera, as the prompt reaches it: she sends node 11 a line and awaits it: \"%s\" (%d)", r, how); r = line(V4_MESH_HERA, "11 KILL", &how); CHECK(how == V4_TEXT_COMPLETED && v4_mesh_node(&ms, 11) == 0 && given_back == 1 && gones == 1, "11 KILL: the node is gone, and its room given back: \"%s\" (%d)", r, how); r = line(V4_MESH_HERA, "3 4 + .", &how); CHECK(how == V4_TEXT_COMPLETED && strcmp(r, "7 ") == 0, "and Hera goes on: \"%s\"", r); /* ---- the edges (Captain Bob, 2026-11-13: "Check for the edge cases") ---- */ r = line(V4_MESH_HERA, "11 2 2 BIRTH .", &how); CHECK(how == V4_TEXT_COMPLETED && v4_mesh_node(&ms, 11) != 0, "after a kill, 11 is born again, in the room given back (%d)", how); r = line(V4_MESH_HERA, "11 3 2 BIRTH .", &how); CHECK(how == V4_TEXT_ERROR, "a number that is live is not born again: an error (%d) \"%s\"", how, r); r = line(11, "1 0 /", &how); CHECK(how == V4_TEXT_ERROR, "a fault on node 11 ends its line in an error (%d) \"%s\"", how, r); r = line(11, "2 3 + .", &how); CHECK(how == V4_TEXT_COMPLETED && strcmp(r, "5 ") == 0, "and node 11 goes on: \"%s\"", r); r = line(V4_MESH_HERA, "99 KILL", &how); CHECK(how == V4_TEXT_ERROR && strstr(r, "no such node"), "KILL of a node there is not: an error, \"%s\"", r); r = line(V4_MESH_HERA, "10 KILL", &how); CHECK(how == V4_TEXT_ERROR && v4_mesh_node(&ms, 10) != 0, "Hera does not kill herself: \"%s\"", r); no_room = 1; r = line(V4_MESH_HERA, "12 3 2 BIRTH .", &how); CHECK(how == V4_TEXT_ERROR && v4_mesh_node(&ms, 12) == 0, "no room: the birth fails in an error, \"%s\"", r); no_room = 0; r = line(V4_MESH_HERA, "3 4 + .", &how); CHECK(how == V4_TEXT_COMPLETED && strcmp(r, "7 ") == 0, "and Hera goes on: \"%s\"", r); { char big[V4_MSG_MAX_CHARS + 8]; memset(big, ' ', sizeof big - 1); big[sizeof big - 1] = 0; r = line(V4_MESH_HERA, big, &how); CHECK(how == V4_BOOT_LINE_TOO_LONG, "a line too long for a message is not run (%d)", how); } /* a node set going for ever does not hold the console: Hera's line ends, and node 11 goes on * running between lines -- every node steps together, not only while a line runs */ r = line(V4_MESH_HERA, "S\" VARIABLE N1 : SPIN BEGIN 1 N1 +! AGAIN ;\" 11 SEND 11 AWAIT .", &how); CHECK(how == V4_TEXT_COMPLETED && strstr(r, "1 "), "node 11 is given SPIN, which runs for ever (%d) \"%s\"", how, r); r = line(V4_MESH_HERA, "S\" SPIN\" 11 SEND", &how); CHECK(how == V4_TEXT_COMPLETED, "Hera's line ends, though node 11 now runs for ever (%d) \"%s\"", how, r); { v4_fabric_node *x = v4_mesh_node(&ms, 11); v4_uheat_t before = x ? x->es.anticlock : 0; unsigned k; for (k = 0; k < 1000; k++) v4_mesh_step(&ms); /* the host's idle: the fabric steps on */ CHECK(x && x->es.anticlock > before + 1000u, "between lines node 11 runs on: every node steps together"); } r = line(V4_MESH_HERA, "11 KILL", &how); CHECK(how == V4_TEXT_COMPLETED && v4_mesh_node(&ms, 11) == 0, "and a node running for ever is killed (%d) \"%s\"", how, r); /* a wait no one will answer: the next line breaks it */ r = line(V4_MESH_HERA, "11 2 2 BIRTH DROP 12 AWAIT", &how); CHECK(how == V4_BOOT_LINE_WAITING, "AWAIT on a node that will never say: the line waits (%d)", how); r = line(V4_MESH_HERA, "3 4 + .", &how); CHECK(how == V4_TEXT_COMPLETED && strstr(r, "Interrupted") && strstr(r, "7 ") > strstr(r, "Interrupted"), "and the next line ends the wait \"Interrupted\", and is then run (MESH.md 7b.6): \"%s\" (%d)", r, how); r = line(V4_MESH_HERA, "3 4 + .", &how); CHECK(how == V4_TEXT_COMPLETED && strcmp(r, "7 ") == 0 && ms.owed == 0, "and nothing more is owed: \"%s\"", r); printf(" %d checks, %d failures\n", checks, failures); return failures ? 1 : 0; }