feat(v4.0.0): nodes that talk -- ports, a node born empty, and the fabric
MESH.md step 1, in the engine, which knows nothing of StarForth or of any kernel. - node: V4_PORTS ports (8), a build parameter; "any port" and the port the last such read came from; a read blocks until the neighbour writes, as a write blocks until the neighbour reads; v4_node_born: empty, P at "any port" - exec: a fetch from a port -- @ @b @+ @p, or of an instruction word when P is a port -- waits for a word; a node executes what arrives at a port without advancing P; a blocked node goes on from the slot it stopped at - fabric: the nodes there are and the table of how their ports are wired, both changed while the nodes run; devices on a port; asleep and awake; a step is every unblocked node executing one instruction word, then every write with a reader waiting being handed over - DECOMPOSITION.md section 6: four named ports withdrawn for V4_PORTS numbered ones and wiring as data, as ruled Verified: tests/test_fabric.c, 53 checks at both widths: two nodes exchange words; an empty node is filled through its port by a device, and by another node, and runs what it was sent; a word is passed on by a node in between; a waiting node executes nothing; the wiring is changed while they run; a node is put to sleep, woken and removed while looping; a node is born while others run; the fabric is given more room. make -C v4 test and make -C v4 sanitize pass. The single-node products are unchanged: hosted-check on three ISAs, and clean qemu with STARFORTH_V4=1 on amd64, aarch64 and riscv64 with lines typed at each prompt (logs/20261006-074907, -075150, -075532). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
2c5427d9c1
commit
9af442f793
+63
-5
@@ -120,9 +120,18 @@ void v4_node_store(v4_node *n, v4_cell addr, v4_cell value)
|
||||
n->console_dropped++;
|
||||
return;
|
||||
}
|
||||
/* The port: the node keeps what it wrote and is blocked until its
|
||||
* neighbour has taken it. -1 when no port is attached. */
|
||||
if (addr == n->port) { n->request = value; n->asking = 1; return; }
|
||||
/* A port: the node keeps what it wrote and is blocked until its
|
||||
* neighbour has taken it. */
|
||||
{
|
||||
int port = v4_node_port_index(n, addr);
|
||||
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 */
|
||||
}
|
||||
/* The stack registers: a store empties the stack. -1 when not attached. */
|
||||
if (addr == n->dstack_reg) { v4_dstack_clear(&n->ds); return; }
|
||||
if (addr == n->rstack_reg) { v4_rstack_clear(&n->rs); return; }
|
||||
@@ -147,6 +156,17 @@ v4_cell v4_node_fetch(v4_node *n, v4_cell addr)
|
||||
if (n->input_pos == n->input_len) n->input_pos = n->input_len = 0;
|
||||
return c;
|
||||
}
|
||||
{
|
||||
int port = v4_node_port_index(n, addr);
|
||||
if (port == (int)V4_PORTS + 1) return (v4_cell)n->last_from;
|
||||
if (port >= 0) {
|
||||
/* the word its neighbour wrote; v4_node_read_ready has said it is there */
|
||||
if (!n->given) return 0;
|
||||
n->given = 0;
|
||||
if (port == (int)V4_PORT_ANY) n->last_from = n->given_port;
|
||||
return n->given_value;
|
||||
}
|
||||
}
|
||||
if (addr == n->dstack_reg) return (v4_cell)n->ds.depth;
|
||||
if (addr == n->rstack_reg) return (v4_cell)n->rs.depth;
|
||||
return v4_node_load(n, addr);
|
||||
@@ -182,11 +202,49 @@ void v4_node_console_attach(v4_node *n, v4_cell addr)
|
||||
n->console_dropped = 0;
|
||||
}
|
||||
|
||||
void v4_node_port_attach(v4_node *n, v4_cell addr)
|
||||
void v4_node_port_attach(v4_node *n, v4_cell base)
|
||||
{
|
||||
n->port = addr;
|
||||
n->port = base;
|
||||
n->asking = 0;
|
||||
n->request = 0;
|
||||
n->ask_port = 0;
|
||||
n->reading = 0;
|
||||
n->read_port = 0;
|
||||
n->given = 0;
|
||||
n->given_value = 0;
|
||||
n->given_port = 0;
|
||||
n->last_from = 0;
|
||||
}
|
||||
|
||||
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 + 1) return -1;
|
||||
return (int)(addr - n->port);
|
||||
}
|
||||
|
||||
int v4_node_read_ready(v4_node *n, v4_cell addr)
|
||||
{
|
||||
int port = v4_node_port_index(n, addr);
|
||||
if (port < 0 || port == (int)V4_PORTS + 1) return 1;
|
||||
if (n->given && (port == (int)V4_PORT_ANY || (unsigned)port == n->given_port)) return 1;
|
||||
n->reading = 1;
|
||||
n->read_port = (unsigned)port;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void v4_node_port_give(v4_node *n, unsigned port, v4_cell value)
|
||||
{
|
||||
n->given = 1;
|
||||
n->given_value = value;
|
||||
n->given_port = port;
|
||||
n->reading = 0;
|
||||
}
|
||||
|
||||
void v4_node_born(v4_node *n, v4_cell base)
|
||||
{
|
||||
v4_node_reset(n);
|
||||
v4_node_port_attach(n, base);
|
||||
n->p = base + (v4_cell)V4_PORT_ANY;
|
||||
}
|
||||
|
||||
void v4_node_port_served(v4_node *n)
|
||||
|
||||
Reference in New Issue
Block a user