Files
LithosAnanake/v4/src/manage.c
T
rajamesandClaude Opus 5.5 348eed7fa1 feat(v4.0.0): five nodes from nothing -- Hera asks for nodes, births and joins them
MESH.md step 5, in the fabric under test; the products are still one
node each until steps 8 and 9.

manage.c: what Hera asks of whoever holds the fabric, eleven requests by
KERNEL-WORD -- NODE-ME -BORN -WIRE -UNWIRE -SLEEP -WAKE -KILL -PARITY and
CAPSULE-OPEN -CELL -LINE. Nucleus: PORT!, SEND-ON, AWAIT, (SEAL).
capsules/v4/hera.4th: BIRTH and UNIT, the unit rule in FORTH and nowhere
else. The dictionary hash moves to the engine (v4_image_dict_hash).

test_host_unit.c, 34 checks, 64-bit: Hera is born empty, takes the
nucleus through her port, FORTH-79, POST and her capsule; 10 UNIT; four
nodes are born, each takes the nucleus and FORTH-79 through its port from
Hera and passes POST 538/538; four parities, one dictionary hash; they
talk, and a message between two corners not wired goes by Hera.

All v4 tests at both widths and under ASan+UBSan. hosted-check on three
ISAs. Bare metal: logs/20261006-143934 (amd64), -144204 (aarch64),
-144601 (riscv64).

Open, recorded in MESH.md: not run at 32 bits; a node that never answers
leaves Hera waiting; the capsules are read from files in the test, not
from the baked directory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-06 14:48:23 -04:00

108 lines
4.6 KiB
C

/* manage.c -- what Hera asks of whoever holds the fabric. See manage.h.
*
* Nothing here uses the C library: the bare-metal kernel links this file.
*/
#include "v4/manage.h"
const char *const v4_manage_words[V4_MANAGE_WORDS] = {
"NODE-ME", "NODE-BORN", "NODE-WIRE", "NODE-UNWIRE", "NODE-SLEEP", "NODE-WAKE", "NODE-KILL", "NODE-PARITY",
"CAPSULE-OPEN", "CAPSULE-CELL", "CAPSULE-LINE"
};
/* A character of the node's memory: four to a cell, the first lowest, as
* the nucleus keeps text (v4/capsule/core.v4). */
static int in_memory(v4_cell baddr) { return baddr >= 0 && (baddr >> 2) < (v4_cell)V4_NODE_WORDS; }
static char char_at(const v4_node *n, v4_cell baddr)
{
return (char)(((v4_ucell)n->mem[baddr >> 2] >> (8 * (unsigned)(baddr & 3))) & 0xFFu);
}
static void char_put(v4_node *n, v4_cell baddr, char c)
{
unsigned shift = 8 * (unsigned)(baddr & 3);
v4_ucell cell = (v4_ucell)n->mem[baddr >> 2];
cell = (cell & ~((v4_ucell)0xFFu << shift)) | ((v4_ucell)(unsigned char)c << shift);
n->mem[baddr >> 2] = (v4_cell)cell;
}
static unsigned place_of(v4_cell x) { return x < 0 ? ~0u : (unsigned)x; }
int v4_manage_serve(const v4_manage *m, unsigned place, unsigned request)
{
v4_fabric_node *asker = v4_fabric_node_at(m->f, place);
v4_node *n;
v4_cell a, b, c, d;
if (!asker || request >= V4_MANAGE_WORDS) return 0;
n = &asker->n;
switch (request) {
case 0: /* NODE-ME ( -- place ) */
v4_dstack_push(&n->ds, (v4_cell)place);
break;
case 1: /* NODE-BORN ( -- place | -1 ) */
v4_dstack_push(&n->ds, (v4_cell)(m->born ? m->born(m->self) : -1));
break;
case 2: /* NODE-WIRE ( a pa b pb -- flag ) */
d = v4_dstack_pop(&n->ds); c = v4_dstack_pop(&n->ds); b = v4_dstack_pop(&n->ds); a = v4_dstack_pop(&n->ds);
v4_dstack_push(&n->ds, v4_fabric_wire(m->f, place_of(a), place_of(b), place_of(c), place_of(d)) ? -1 : 0);
break;
case 3: /* NODE-UNWIRE ( a pa -- ) */
b = v4_dstack_pop(&n->ds); a = v4_dstack_pop(&n->ds);
(void)v4_fabric_unwire(m->f, place_of(a), place_of(b));
break;
case 4: /* NODE-SLEEP ( place -- ) */
a = v4_dstack_pop(&n->ds);
v4_fabric_sleep(m->f, place_of(a));
break;
case 5: /* NODE-WAKE ( place -- ) */
a = v4_dstack_pop(&n->ds);
v4_fabric_wake(m->f, place_of(a));
break;
case 6: { /* NODE-KILL ( place -- ) */
v4_fabric_node *was;
a = v4_dstack_pop(&n->ds);
if (place_of(a) == place) break; /* not itself: there would be no one to answer */
was = v4_fabric_remove(m->f, place_of(a));
if (was && m->gone) m->gone(m->self, place_of(a), was);
break;
}
case 7: { /* NODE-PARITY ( place number -- ) */
v4_fabric_node *it;
b = v4_dstack_pop(&n->ds); a = v4_dstack_pop(&n->ds);
it = v4_fabric_node_at(m->f, place_of(a));
if (it && m->parity) m->parity(m->self, place_of(a), b, &it->n);
break;
}
case 8: { /* CAPSULE-OPEN ( baddr u -- flag ) */
char name[64];
unsigned i, len;
b = v4_dstack_pop(&n->ds); a = v4_dstack_pop(&n->ds);
len = b < 0 ? 0u : (unsigned)b;
if (len == 0 || len > sizeof name || !in_memory(a) || !in_memory(a + (v4_cell)len - 1) || !m->open) {
v4_dstack_push(&n->ds, 0);
break;
}
for (i = 0; i < len; i++) name[i] = char_at(n, a + (v4_cell)i);
v4_dstack_push(&n->ds, m->open(m->self, name, len) ? -1 : 0);
break;
}
case 9: /* CAPSULE-CELL ( -- w flag ) */
a = 0;
if (m->cell && m->cell(m->self, &a)) { v4_dstack_push(&n->ds, a); v4_dstack_push(&n->ds, -1); }
else { v4_dstack_push(&n->ds, 0); v4_dstack_push(&n->ds, 0); }
break;
case 10: { /* CAPSULE-LINE ( baddr -- u | -1 ) */
char text[V4_MANAGE_LINE];
int len, i;
a = v4_dstack_pop(&n->ds);
len = m->line ? m->line(m->self, text) : -1;
if (len > V4_MANAGE_LINE) len = V4_MANAGE_LINE;
if (len > 0 && (!in_memory(a) || !in_memory(a + len - 1))) len = -1;
for (i = 0; i < len; i++) char_put(n, a + i, text[i]);
v4_dstack_push(&n->ds, (v4_cell)len);
break;
}
}
return 1;
}