feat(v4.0.0): messages are whole and wait on the wire -- a node keeps none but the one it is doing

Step 6e, tasks 2 and 3 (docs/v4.0.0/MESH.md 7d).  The nucleus puts, looks
at, takes, moves and drops whole messages through the six addresses after
its ports; its own ring of messages waiting, the refusals owed, (GATE) and
the looking words' use are gone.  SEND, an answer, a NACK and a GONE go or
are refused at once; what a text prints waits for room; a text is not
begun until the wire its answer goes by has room for it, and that room is
kept.  The lone node's host (v4/system/boot.c) keeps its two wires and
does its operations; the test hosts' consoles put and take whole messages
through the fabric.  New: tests/test_host_depth.c, every message path of
a mesh node at every depth of both stacks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
rajames
2026-10-08 15:59:37 -04:00
co-authored by Claude Opus 5.5
parent 83694b18be
commit b1d09af043
12 changed files with 1621 additions and 834 deletions
+58 -39
View File
@@ -65,12 +65,7 @@
#define SRC (BVARS + 8)
#define SRC_HOOK (BVARS + 9)
#define QUIET (BUF0_W - 10) /* 1 while the node does something that is no text's doing: an error then is not told (quit.v4, (RAISED)) */
#define A_WORD (BUF0_W - 113) /* AWAIT's look through the messages waiting: the answer's word, */
#define A_LEFT (BUF0_W - 114) /* how many cells are still to be looked at, */
#define A_FOUND (BUF0_W - 115) /* and what was found */
#define REFUSED (BUF0_W - 7) /* how many of this node's messages it has been told were refused */
#define OWED_COUNT (BUF0_W - 8) /* how many refusals this node owes and has not sent yet, at most 8 */
#define OWED (BUF0_W - 112) /* those: for each, the node it is owed to and the node the refused message was for */
#define ACL_HOOK (BUF0_W - 6) /* the xt of the access control recheck word, or 0 */
#define LINE_STATUS (BUF0_W - 9) /* how the last line ended: 0 QUIT, 1 completed, 2 an error */
#define PORT (BUF0_W - 140) /* the node's ports (node.h): V4_PORTS of them, then "any port", "which port" and the rest as far as V4_PORT_HAVE. Port 0 is where its requests go. */
@@ -79,24 +74,42 @@
#define ROUTE_DEFAULT (BUF0_W - 18) /* the port address for a node not in the table, or 0: there is none */
#define LOST (BUF0_W - 19) /* how many messages have been let go for want of a way */
#define PRINT_TO (BUF0_W - 20) /* where what the text being served prints is to go: the node, */
#define WRITERS (PORT + (v4_cell)V4_PORTS + 2) /* which ports have a neighbour waiting to write to this node (node.h) */
#define READERS (PORT + (v4_cell)V4_PORTS + 3) /* and which have one waiting to read from it */
#define PRINT_PORT (BUF0_W - 33) /* and the port address that leads there */
#define DONE_PORT (BUF0_W - 34) /* the port address that leads back to whoever sent the text being served */
#define MQ_HEAD (BUF0_W - 35) /* the messages waiting to be dealt with: where the oldest begins, */
#define MQ_TAIL (BUF0_W - 36) /* where the next will go, */
#define MQ_COUNT (BUF0_W - 37) /* and how many cells they take */
#define PRINT_PORT (BUF0_W - 33) /* and the port, by its number, that leads there */
#define DONE_PORT (BUF0_W - 34) /* the port, by its number, that leads back to whoever sent the text being served */
/* WHOLE MESSAGES (MESH.md 7d.4; core.v4). A node keeps no message but the one it is doing: these are what it
* builds one in and looks at one with, and where it has got to in going through its wires. */
#define WIRE (PORT + (v4_cell)V4_PORT_WIRE) /* the six addresses after the ports (node.h): the wire an operation is about, */
#define WIRE_A (PORT + (v4_cell)V4_PORT_A) /* what it needs, */
#define WIRE_B (PORT + (v4_cell)V4_PORT_B)
#define WIRE_DO (PORT + (v4_cell)V4_PORT_DO) /* the operation, */
#define WIRE_HOW (PORT + (v4_cell)V4_PORT_HOW) /* how it went, */
#define WIRE_HAVE (PORT + (v4_cell)V4_PORT_HAVE) /* and which wires have a message */
#define S_HAVE (BUF0_W - 35) /* which wires had a message when the node last asked, */
#define S_MASK (BUF0_W - 36) /* those of them still to be gone through, */
#define S_WIRE (BUF0_W - 37) /* the one being gone through, */
#define S_ON (BUF0_W - 38) /* and whether its mark has been put at its first message */
#define KEEP (BUF0_W - 40) /* the port the answer to the text being done goes by, on whose wire 8 cells are kept for it; -1: none */
#define DEFER (BUF0_W - 41) /* a port whose wire had no room for the answer to text that waits to be begun; -1: none */
#define IN_HDR (BUF0_W - 56) /* the seven words of the message a wire's mark is at */
#define ONE (BUF0_W - 49) /* the one word of text of a NACK, a GONE or an answer, coming or going */
#define OUT_HDR (BUF0_W - 112) /* the seven words of a message this node is putting on a wire */
#define W_NEED (BUF0_W - 105) /* the wait for room: how many cells, */
#define W_PORT (BUF0_W - 104) /* and on which port's wire */
#define P_WAY (BUF0_W - 103) /* the port a message being passed on goes by */
#define A_SELF (BUF0_W - 102) /* 1: a message of this node's own, for the node it waits on, came back and was let go here */
#define SEND_PTR (BUF0_W - 101) /* where the next word of a text being made ready to send goes */
#define OUT_TEXT (OUT_W - 64) /* what was printed, four characters to a cell, as it goes on the wire: 64 cells */
#define SEND_TEXT (OUT_W - 400) /* the text of a message SEND is putting, four characters to a cell: 256 cells */
/* FREE, plain memory: BUF0_W - 8; - 32 .. - 21; - 100 .. - 97; - 115 .. - 113; and OUT_W - 144 .. OUT_W - 65. They and
* the cells above held the messages waiting, the refusals owed and what went with them (MESH.md 7a, 7b), which a
* node no longer keeps. */
#define AWAIT_FROM (BUF0_W - 39) /* the node whose word of how text ended is waited for */
#define GATE_PORT (BUF0_W - 38) /* the port address a message is about to be begun on */
#define NEAR (BUF0_W - 64) /* for each port, the number of the node on the other end; 0: not told */
#define MQ_HDR (BUF0_W - 56) /* a message being taken in: its seven words and the port it came on */
#define MQ_W (OUT_W - 400) /* the messages waiting: each is its seven words, the port it came on, its text */
#define MQ_CELLS 400
#define ROUTES (BUF0_W - 96) /* the table of ways: 16 entries of a node and the port address that leads to it */
#define ROUTE_MAX 16
#define ME (BUF0_W - 13) /* this node's number: a message is for it when its first word is this */
#define OUT_PTR (BUF0_W - 14) /* where the next character printed goes: a cell of the output buffer */
#define REPLY (BUF0_W - 15) /* the address of the port the message being served came on */
#define REPLY (BUF0_W - 15) /* the port, by its number, the text being served came on */
#define MSG (BUF0_W - 48) /* the header of the message being served, 7 cells */
#define OUT_W (BUF0_W - 400) /* the output buffer: 256 cells, a character to a cell */
#define OUT_CELLS 256
@@ -106,12 +119,12 @@
#define BOOT_CELLS (BVARS + 14) /* (BOOT): DP and LATEST as the loader left them, 2 cells */
#define BUF0_W (BVARS - (v4_cell)(V4_BLOCK_SLOTS * V4_BLOCK_CELLS)) /* the block window: the kernel's slots, 256 cells each (v4/blocks.h) */
/* The ports and the addresses after them, through V4_PORT_HAVE (node.h, MESH.md 7d.3), are not memory and must be where
* no variable is: after the output buffer, which ends at BUF0_W - 144, and before A_FOUND, the first variable above it.
* no variable is: after the output buffer, which ends at BUF0_W - 144, and before OUT_HDR, the first variable above it.
* With 8 ports that is 18 addresses, BUF0_W - 140 to BUF0_W - 123. (They were once among the variables, and what was
* stored to the variables was stored to ports.) */
typedef char host_map_ports_fit[(PORT >= OUT_W + OUT_CELLS && PORT + (v4_cell)V4_PORT_HAVE < A_FOUND) ? 1 : -1];
/* Nothing printed and no message waiting: a node's variables for them, as at switch-on. */
#define HOST_MESSAGES_EMPTY(n) do { (n)->mem[OUT_PTR] = OUT_W; (n)->mem[MQ_HEAD] = MQ_W; (n)->mem[MQ_TAIL] = MQ_W; (n)->mem[MQ_COUNT] = 0; } while (0)
typedef char host_map_ports_fit[(PORT >= OUT_W + OUT_CELLS && PORT + (v4_cell)V4_PORT_HAVE < OUT_HDR) ? 1 : -1];
/* Nothing printed: a node's variable for it, as at switch-on. */
#define HOST_MESSAGES_EMPTY(n) do { (n)->mem[OUT_PTR] = OUT_W; } while (0)
#define QVARS (BUF0_W - 4) /* (Q): quit.v4, system.v4 and blocks.v4, 4 cells */
#define WBUF (WBUF_W * 4)
#define TIB (TIB_W * 4)
@@ -125,8 +138,8 @@ typedef char host_map_ports_fit[(PORT >= OUT_W + OUT_CELLS && PORT + (v4_cell)V4
#ifndef DICT_END_W
#define DICT_END_W ((v4_cell)13824) /* 512 cells lower than it was: the block window is four slots now */
#endif
/* the messages waiting are above the dictionary */
typedef char host_map_queue_fits[(MQ_W >= DICT_END_W) ? 1 : -1];
/* the texts made ready for the wire are above the dictionary */
typedef char host_map_texts_fit[(SEND_TEXT >= DICT_END_W && SEND_TEXT + 256 <= OUT_TEXT && OUT_TEXT + 64 == OUT_W) ? 1 : -1];
/* How many slots, from slot 0, a branch may sit in on a node this size: those
* whose address field reaches every word of it. */
@@ -194,27 +207,33 @@ static int host_load(v4_text *tx, v4_node *n, const char *const *files, unsigned
v4_text_constant(tx, "(PRINT-PORT)", PRINT_PORT);
v4_text_constant(tx, "(DONE-PORT)", DONE_PORT);
v4_text_constant(tx, "(ROUTES)", ROUTES);
v4_text_constant(tx, "(WRITERS)", WRITERS);
v4_text_constant(tx, "(READERS)", READERS);
v4_text_constant(tx, "-PORTS", -(v4_cell)V4_PORTS);
v4_text_constant(tx, "(NEAR)", NEAR);
v4_text_constant(tx, "(GATE-PORT)", GATE_PORT);
v4_text_constant(tx, "(AWAIT-FROM)", AWAIT_FROM);
v4_text_constant(tx, "(MQ)", MQ_W);
v4_text_constant(tx, "(MQ-END)", MQ_W + MQ_CELLS);
v4_text_constant(tx, "-MQ-ORDINARY", -(v4_cell)(MQ_CELLS - 7 - 36)); /* the same for a message that is not a refusal or a GONE: 36 cells are kept for those */
v4_text_constant(tx, "(WIRE)", WIRE);
v4_text_constant(tx, "(WIRE-A)", WIRE_A);
v4_text_constant(tx, "(WIRE-B)", WIRE_B);
v4_text_constant(tx, "(WIRE-DO)", WIRE_DO);
v4_text_constant(tx, "(WIRE-HOW)", WIRE_HOW);
v4_text_constant(tx, "(WIRE-HAVE)", WIRE_HAVE);
v4_text_constant(tx, "(S-HAVE)", S_HAVE);
v4_text_constant(tx, "(S-MASK)", S_MASK);
v4_text_constant(tx, "(S-WIRE)", S_WIRE);
v4_text_constant(tx, "(S-ON)", S_ON);
v4_text_constant(tx, "(KEEP)", KEEP);
v4_text_constant(tx, "(DEFER)", DEFER);
v4_text_constant(tx, "(IN)", IN_HDR);
v4_text_constant(tx, "(ONE)", ONE);
v4_text_constant(tx, "(OUT-HDR)", OUT_HDR);
v4_text_constant(tx, "(W-NEED)", W_NEED);
v4_text_constant(tx, "(W-PORT)", W_PORT);
v4_text_constant(tx, "(P-WAY)", P_WAY);
v4_text_constant(tx, "(A-SELF)", A_SELF);
v4_text_constant(tx, "(SEND^)", SEND_PTR);
v4_text_constant(tx, "(OUT-TEXT)", OUT_TEXT);
v4_text_constant(tx, "(SEND-TEXT)", SEND_TEXT);
v4_text_constant(tx, "(QUIET)", QUIET);
v4_text_constant(tx, "(A-WORD)", A_WORD);
v4_text_constant(tx, "(A-LEFT)", A_LEFT);
v4_text_constant(tx, "(A-FOUND)", A_FOUND);
v4_text_constant(tx, "(REFUSED)", REFUSED);
v4_text_constant(tx, "(OWED#)", OWED_COUNT);
v4_text_constant(tx, "(OWED)", OWED);
v4_text_constant(tx, "-MQ-ROOM", -(v4_cell)(MQ_CELLS - 7)); /* cells taken + a text's words + this is below zero while the message fits */
v4_text_constant(tx, "(MQ-HEAD)", MQ_HEAD);
v4_text_constant(tx, "(MQ-TAIL)", MQ_TAIL);
v4_text_constant(tx, "(MQ#)", MQ_COUNT);
v4_text_constant(tx, "(MQ-HDR)", MQ_HDR);
v4_text_constant(tx, "(OUT^)", OUT_PTR);
v4_text_constant(tx, "(REPLY)", REPLY);
v4_text_constant(tx, "(MSG)", MSG);