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>
108 lines
4.6 KiB
C
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;
|
|
}
|