/* 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; }