feat(v4.0.0): the wire in the engine -- whole messages, put and taken in one step

Queues of whole messages on the wires between nodes (v4/wire.h), the six
addresses and ten operations a node asks of the fabric (MESH.md 7d.3), and the
fabric's pool of queues. Engine only: the nucleus does not use any of it yet.
The ports in the host map move to BUF0_W - 140 so that the new addresses are
not among the nucleus variables, with a compile-time check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-08 13:50:15 -04:00
co-authored by Claude Opus 5.5
parent 50be766e7b
commit d5cd64605d
14 changed files with 1267 additions and 22 deletions
+3 -3
View File
@@ -260,7 +260,7 @@ unsigned v4_exec_step_word(v4_node *n, v4_exec_state *es, v4_heat *h)
/* D-14: a node that faulted with no handler has stopped. A node that
* has written to its port is blocked until it has been served. */
if (n->stopped || n->asking || n->reading) return 0;
if (n->stopped || n->asking || n->reading || n->doing) return 0;
if (es->resume && es->resume_faults != n->faults) es->resume = 0; /* it faulted while blocked: P is the handler */
if (es->resume) {
/* unblocked: the rest of the word it was in */
@@ -305,8 +305,8 @@ unsigned v4_exec_step_word(v4_node *n, v4_exec_state *es, v4_heat *h)
}
executed++;
if (n->asking) {
/* The store was to the port. The node is blocked here; what is
if (n->asking || n->doing) {
/* The store was to the port, or to Do. The node is blocked here; what is
* left of the word waits until it has been served. */
if (slot + 1 < V4_SLOT_COUNT) {
es->resume = 1;
+236 -4
View File
File diff suppressed because it is too large Load Diff
+36 -2
View File
@@ -87,13 +87,17 @@ void v4_node_store(v4_node *n, v4_cell addr, v4_cell value)
* neighbour has taken it. */
{
int port = v4_node_port_index(n, addr);
if (port == (int)V4_PORT_WIRE) { n->wire = (value >= 0 && value < (v4_cell)V4_PORTS) ? (unsigned)value : V4_PORTS; return; }
if (port == (int)V4_PORT_A) { n->wire_a = value; return; }
if (port == (int)V4_PORT_B) { n->wire_b = value; return; }
if (port == (int)V4_PORT_DO) { n->do_op = value; n->doing = 1; return; }
if (port >= 0 && port < (int)V4_PORTS) {
n->request = value;
n->ask_port = (unsigned)port;
n->asking = 1;
return;
}
if (port >= 0) { v4_node_fault(n, V4_FAULT_ADDRESS, addr); return; } /* "any" and "which port" are not written to */
if (port >= 0) { v4_node_fault(n, V4_FAULT_ADDRESS, addr); return; } /* "any", "which port", How and Have are not written to */
}
/* The stack registers: a store empties the stack. -1 when not attached. */
if (addr == n->dstack_reg) { v4_dstack_clear(&n->ds); return; }
@@ -122,6 +126,12 @@ v4_cell v4_node_fetch(v4_node *n, v4_cell addr)
if (port == (int)V4_PORTS + 1) return (v4_cell)n->last_from;
if (port == (int)V4_PORTS + 2) { n->since_look = 0; return (v4_cell)n->writers; }
if (port == (int)V4_PORTS + 3) { n->since_look = 0; return (v4_cell)n->readers; }
if (port == (int)V4_PORT_WIRE) return (v4_cell)n->wire;
if (port == (int)V4_PORT_A) return n->wire_a;
if (port == (int)V4_PORT_B) return n->wire_b;
if (port == (int)V4_PORT_DO) return n->do_op;
if (port == (int)V4_PORT_HOW) return n->how;
if (port == (int)V4_PORT_HAVE) { n->have_fetched = 1; return (v4_cell)n->have; }
if (port >= 0) {
/* the word its neighbour wrote; v4_node_read_ready has said it is there */
if (!n->given) return 0;
@@ -180,6 +190,14 @@ void v4_node_port_attach(v4_node *n, v4_cell base)
n->writers = 0;
n->readers = 0;
n->since_look = 0;
n->wire = 0;
n->wire_a = 0;
n->wire_b = 0;
n->doing = 0;
n->do_op = 0;
n->how = 0;
n->have = 0;
n->have_fetched = 0;
}
void v4_node_port_status(v4_node *n, unsigned writers, unsigned readers)
@@ -190,7 +208,7 @@ void v4_node_port_status(v4_node *n, unsigned writers, unsigned readers)
int v4_node_port_index(const v4_node *n, v4_cell addr)
{
if (n->port < 0 || addr < n->port || addr > n->port + (v4_cell)V4_PORTS + 3) return -1;
if (n->port < 0 || addr < n->port || addr > n->port + (v4_cell)V4_PORT_HAVE) return -1;
return (int)(addr - n->port);
}
@@ -225,6 +243,22 @@ void v4_node_port_served(v4_node *n)
n->since_look++;
}
int v4_node_doing(const v4_node *n)
{
return n->doing;
}
void v4_node_done(v4_node *n, v4_cell how)
{
n->how = how;
n->doing = 0;
}
void v4_node_have(v4_node *n, unsigned mask)
{
n->have = mask;
}
unsigned v4_node_words_since_look(const v4_node *n)
{
return n->since_look;
+124
View File
@@ -0,0 +1,124 @@
/* wire.c -- a queue of whole messages. See wire.h.
*
* Nothing here uses the C library: the bare-metal kernel links this file.
*/
#include "v4/wire.h"
#include "v4/message.h"
void v4_wire_reset(v4_wire_queue *q)
{
unsigned i;
for (i = 0; i < V4_WIRE_CELLS; i++) q->cell[i] = 0;
q->head = 0;
q->used = 0;
q->mark = 0;
q->arrived = 0;
}
unsigned v4_wire_cells(v4_cell length)
{
if (length < 0 || length > (v4_cell)V4_MSG_MAX_CHARS) return 0;
return V4_WIRE_HEADER + ((unsigned)length + 3u) / 4u;
}
/* the cell `off` cells from the front */
static unsigned slot(const v4_wire_queue *q, unsigned off)
{
unsigned s = q->head + off;
return s >= V4_WIRE_CELLS ? s - V4_WIRE_CELLS : s;
}
/* the cells the message `off` cells from the front takes */
static unsigned size_at(const v4_wire_queue *q, unsigned off)
{
return v4_wire_cells(q->cell[slot(q, off + 6u)]);
}
int v4_wire_room(const v4_wire_queue *q, unsigned cells)
{
return cells <= V4_WIRE_CELLS - q->used ? V4_WIRE_DONE : V4_WIRE_NO_ROOM;
}
/* `n` cells, already checked to fit, onto the back */
static unsigned back(v4_wire_queue *q, unsigned n)
{
unsigned at = q->used;
q->used += n;
q->arrived = 1;
return at;
}
int v4_wire_put(v4_wire_queue *q, const v4_cell *header7, const v4_cell *text)
{
unsigned n = v4_wire_cells(header7[6]), at, i;
if (n == 0) return V4_WIRE_NOT_A_MESSAGE;
if (v4_wire_room(q, n) != V4_WIRE_DONE) return V4_WIRE_NO_ROOM;
at = back(q, n);
for (i = 0; i < V4_WIRE_HEADER; i++) q->cell[slot(q, at + i)] = header7[i];
for (; i < n; i++) q->cell[slot(q, at + i)] = text[i - V4_WIRE_HEADER];
return V4_WIRE_DONE;
}
void v4_wire_first(v4_wire_queue *q)
{
q->mark = 0;
}
int v4_wire_next(v4_wire_queue *q)
{
if (q->mark >= q->used) return V4_WIRE_NO_MESSAGE;
q->mark += size_at(q, q->mark);
return q->mark < q->used ? V4_WIRE_DONE : V4_WIRE_NO_MESSAGE;
}
int v4_wire_look(const v4_wire_queue *q, v4_cell *header7)
{
unsigned i;
if (q->mark >= q->used) return V4_WIRE_NO_MESSAGE;
for (i = 0; i < V4_WIRE_HEADER; i++) header7[i] = q->cell[slot(q, q->mark + i)];
return V4_WIRE_DONE;
}
/* the marked message is off the queue; the mark is at the one that followed */
static void remove_marked(v4_wire_queue *q)
{
unsigned n = size_at(q, q->mark), i;
if (q->mark == 0) {
q->head = slot(q, n);
} else {
for (i = q->mark; i + n < q->used; i++) q->cell[slot(q, i)] = q->cell[slot(q, i + n)];
}
q->used -= n;
}
int v4_wire_take(v4_wire_queue *q, v4_cell *header7, v4_cell *text, unsigned text_cap)
{
unsigned n, i;
if (q->mark >= q->used) return V4_WIRE_NO_MESSAGE;
n = size_at(q, q->mark);
if (n - V4_WIRE_HEADER > text_cap) return V4_WIRE_NOT_A_MESSAGE;
for (i = 0; i < V4_WIRE_HEADER; i++) header7[i] = q->cell[slot(q, q->mark + i)];
for (; i < n; i++) text[i - V4_WIRE_HEADER] = q->cell[slot(q, q->mark + i)];
remove_marked(q);
return V4_WIRE_DONE;
}
int v4_wire_drop(v4_wire_queue *q)
{
if (q->mark >= q->used) return V4_WIRE_NO_MESSAGE;
remove_marked(q);
return V4_WIRE_DONE;
}
int v4_wire_move(v4_wire_queue *from, v4_wire_queue *to)
{
unsigned n, at, i;
if (from->mark >= from->used) return V4_WIRE_NO_MESSAGE;
n = size_at(from, from->mark);
if (from == to || v4_wire_room(to, n) != V4_WIRE_DONE) return V4_WIRE_NO_ROOM;
at = back(to, n);
for (i = 0; i < n; i++) to->cell[slot(to, at + i)] = from->cell[slot(from, from->mark + i)];
to->cell[slot(to, at + 3u)] = (v4_cell)(from->cell[slot(from, from->mark + 3u)] - 1);
remove_marked(from);
return V4_WIRE_DONE;
}