feat(v4.0.0): the wait replaces looking and the console release; step 6d written up

The engine's console release (v4_fabric_interrupt_error), a device's
pending, and the count of words since a look are removed: nothing uses
them.  MESH.md 4.1, 7b and 7c say what was built, where it differs from
what was approved and why, and what is still a limit; step 6d is marked
built, with the defects found on the way.

make -C v4 test and sanitize at both widths, hosted-check, lint; three
bare-metal boots.  POST 538 of 538, word_count=317,
dict_hash=0x6a39c0bb9d183418 on all six.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-08 01:24:09 -04:00
co-authored by Claude Opus 5.5
parent ec817a8264
commit 2b587206ee
13 changed files with 638 additions and 181 deletions
-60
View File
@@ -70,10 +70,6 @@ static void count_for_ever(void)
v4_asm_branch(&as, V4_OP_JUMP, again);
}
/* a device that says whether it has something pending */
static int *dev_has;
static int device_has(void *self) { (void)self; return *dev_has; }
/* Let time pass until nothing more can happen, or `max` steps. */
static unsigned settle(unsigned max)
{
@@ -392,62 +388,6 @@ int main(void)
CHECK(ND(a)->n.asking && ND(a)->n.request == 5 && ND(c)->n.reading && ND(c)->n.mem[OUT] == 0, "looking takes nothing and gives nothing: both wait as they did");
CHECK(!ND(b)->n.stopped && ND(b)->n.reading, "and the one that looked did not wait to look");
/* ---- a node blocked on the first word of a message, while a device of its own has something for it ---- */
{
static int has; /* what the device says it has pending */
static stream none;
static v4_device dev;
v4_fabric_init(&f, places, 4);
for (i = 0; i < 3; i++) v4_node_reset(&pool[i].n);
a = loaded(0); /* looks about, then writes two words to its port 0 */
LIT(PB + (v4_cell)V4_PORTS + 3); O(BANG_B); O(FETCH_B); O(DROP);
LIT(PB + 0); O(BANG_B); LIT(1); O(STORE_B); LIT(2); O(STORE_B); wait_for_ever();
b = loaded(1); /* never reads */
LIT(OUT); O(BANG_A);
{
v4_cell again = v4_asm_label(&as);
O(FETCH_A); LIT(1); O(ADD); O(STORE_A);
v4_asm_branch(&as, V4_OP_JUMP, again);
}
CHECK(v4_asm_ok(&as) && v4_fabric_wire(&f, a, 0, b, 3), "a writer that looks first, wired to a node that never reads");
dev.take = stream_take; dev.give = 0; dev.self = &none; dev.pending = device_has; has = 1; dev_has = &has;
CHECK(v4_fabric_wire_device(&f, a, 5, &dev), "and to a device, which has something for it");
for (i = 0; i < 40; i++) (void)v4_fabric_step(&f);
CHECK(ND(a)->n.asking && ND(a)->n.request == 1 && v4_node_words_since_look(&ND(a)->n) == 0, "the writer is blocked on its first word, and waits: the fabric has no error for it");
v4_fabric_interrupt_error(&f, 21);
for (i = 0; i < 40; i++) (void)v4_fabric_step(&f);
CHECK(ND(a)->n.asking && ND(a)->n.faults == 0, "nor is a bare node let go when it has: it cannot take an error");
v4_node_error_attach(&ND(a)->n, OUT + 20);
v4_node_fault_attach(&ND(a)->n, 900);
has = 0;
for (i = 0; i < 40; i++) (void)v4_fabric_step(&f);
CHECK(ND(a)->n.asking && ND(a)->n.faults == 0, "a node that can take one waits all the same while the device has nothing for it");
has = 1;
(void)v4_fabric_step(&f);
CHECK(!ND(a)->n.asking && ND(a)->n.fault_kind == V4_FAULT_RAISED && ND(a)->n.fault_addr == 21 && ND(a)->n.mem[OUT + 20] == 21,
"when it has, the writer is let go and the error raised on it");
/* once the first word has gone, it is not let go: the message must be finished */
v4_fabric_init(&f, places, 4);
for (i = 0; i < 3; i++) v4_node_reset(&pool[i].n);
a = loaded(0);
LIT(PB + (v4_cell)V4_PORTS + 3); O(BANG_B); O(FETCH_B); O(DROP);
LIT(PB + 0); O(BANG_B); LIT(1); O(STORE_B); LIT(2); O(STORE_B); wait_for_ever();
b = loaded(1); /* reads one word, and no more */
LIT(PB + 3); O(BANG_B); O(FETCH_B); LIT(OUT); O(BANG_A);
{
v4_cell again = v4_asm_label(&as);
O(FETCH_A); LIT(1); O(ADD); O(STORE_A);
v4_asm_branch(&as, V4_OP_JUMP, again);
}
CHECK(v4_asm_ok(&as) && v4_fabric_wire(&f, a, 0, b, 3) && v4_fabric_wire_device(&f, a, 5, &dev), "the same, to a node that reads one word and no more");
v4_node_error_attach(&ND(a)->n, OUT + 20);
v4_node_fault_attach(&ND(a)->n, 900);
v4_fabric_interrupt_error(&f, 21);
for (i = 0; i < 60; i++) (void)v4_fabric_step(&f);
CHECK(ND(a)->n.asking && ND(a)->n.request == 2 && ND(a)->n.faults == 0, "blocked on its second word with the device still pending, the writer waits");
}
/* ---- the wait (MESH.md 7c): a node offers a word and sleeps ---- */
{
static stream none;
+1 -2
View File
@@ -71,8 +71,7 @@ static int console_take(void *self, v4_cell value)
}
return 1;
}
static int console_pending(void *self) { (void)self; return going_at < going.count; }
static const v4_device console = { console_take, console_give, 0, console_pending };
static const v4_device console = { console_take, console_give, 0 };
static int is_empty(const char *s) { return s[0] == 0; }
+3 -5
View File
@@ -140,7 +140,7 @@ static int host_born(void *self)
v4_node_fault_attach(&pool[k].n, w_fault);
v4_blocks_init(&node_blocks[k], BUF0_W);
if (k != 0) { /* Hera's kernel is wired where she is made */
node_kernel[k].take = node_kernel_take; node_kernel[k].give = 0; node_kernel[k].self = &pool[k]; node_kernel[k].pending = 0;
node_kernel[k].take = node_kernel_take; node_kernel[k].give = 0; node_kernel[k].self = &pool[k];
if (!v4_fabric_wire_device(&f, (unsigned)place, 0, &node_kernel[k])) return -1;
}
return place;
@@ -194,7 +194,7 @@ static int kernel_take(void *self, v4_cell value) /* a request */
if (value < FIRST_REQUEST || !v4_manage_serve(&manage, hera_place, (unsigned)(value - FIRST_REQUEST))) refused++;
return 1;
}
static const v4_device kernel = { kernel_take, kernel_give, 0, 0 };
static const v4_device kernel = { kernel_take, kernel_give, 0 };
/* ---- the console: a device on Hera's port 1 ---- */
#define CONSOLE_ID 1
@@ -237,8 +237,7 @@ static int console_take(void *self, v4_cell value)
}
return 1;
}
static int console_pending(void *self) { (void)self; return going_at < going.count; }
static const v4_device console = { console_take, console_give, 0, console_pending };
static const v4_device console = { console_take, console_give, 0 };
/* Is there a node that will execute at the next step? A step in which a
* node only faulted counts nothing done (exec.h), and it goes on from its
@@ -384,7 +383,6 @@ int main(void)
/* ---- Hera is born empty, and takes in the nucleus ---- */
v4_fabric_init(&f, places, PLACES);
v4_fabric_gone_error(&f, V4_ERROR_NO_ONE);
v4_fabric_interrupt_error(&f, V4_ERROR_INTERRUPTED);
place = host_born(0);
CHECK(place == 0, "a node is born");
hera_place = (unsigned)place;