- The result of every take is looked at: a wire cut between the look and the take leaves nothing acted on (the text before run again, a refusal counted, a wait ended by an old answer, a way forgotten). - A node with no room to pass on what another printed, or its word of how text ended, leaves it on the wire it came by and moves it when there is room; what is behind it for the same port waits too. Sleep for room (9) is woken by room on any of the node's wires (engine; MESH.md 7d.3). - The lone node's host keeps no queue for the kernel's port: a message to it is error 18. The step limit is counted while the node waits for room. - A text waiting for room to print is not interrupted by console text; AWAIT is, as before. (BREAK?) is gone. - A GONE is believed only by the centre's port; unawaited answers let go are counted; nothing past a message's last character goes on a wire; AWAIT sets (AWAIT-FROM) only once the stack has been tried. - test_host_depth.c: ten paths, each run works or ends in one named stack error; it fails with (ROOM) or (ROOM-SERVE) taken out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
301 lines
18 KiB
C
301 lines
18 KiB
C
/* host_map.h -- the memory map the host-node tests give the compiler capsule,
|
|
* and the loader that assembles it.
|
|
*
|
|
* The node's memory map is open (DECOMPOSITION.md D-4), so the tests choose
|
|
* one. Every test_host_*.c uses this one, so that the capsule's variables
|
|
* and buffers are in the same place in all of them:
|
|
*
|
|
* 16 .. the capsule's code, assembled from capsule/ *.v4
|
|
* DICT_W .. DICT_END_W dictionary space for what is defined at run time
|
|
* top of memory buffers, then variables, as below
|
|
*/
|
|
#ifndef V4_TESTS_HOST_MAP_H
|
|
#define V4_TESTS_HOST_MAP_H
|
|
|
|
#include "v4/blocks.h"
|
|
#include "v4/text.h"
|
|
#include <stdio.h>
|
|
|
|
#define TOP ((v4_cell)V4_NODE_WORDS)
|
|
|
|
/* registers and single variables */
|
|
#define NODE_ERROR (TOP - 2)
|
|
#define CONSOLE_TX (TOP - 4)
|
|
#define CONSOLE_RX (TOP - 6)
|
|
#define CONSOLE_ST (TOP - 7)
|
|
#define BASE (TOP - 8)
|
|
#define TO_IN (TOP - 9)
|
|
#define SPAN (TOP - 10)
|
|
#define DP (TOP - 11)
|
|
#define LATEST (TOP - 12)
|
|
#define STATE (TOP - 13)
|
|
#define CFP (TOP - 14) /* the control-flow stack's pointer */
|
|
#define DSTACK_REG (TOP - 15) /* DSTACK-DEPTH (D-16) */
|
|
#define RSTACK_REG (TOP - 16) /* RSTACK-DEPTH */
|
|
|
|
/* each capsule file's scratch cells */
|
|
#define PVARS (TOP - 24) /* (P): input.v4, 8 cells */
|
|
#define DVARS (TOP - 32) /* (D): dict.v4, 5 cells */
|
|
#define CGVARS (TOP - 48) /* (CG): codegen.v4, 14 cells */
|
|
#define CVARS (TOP - 62) /* (C): compile.v4, 10 cells */
|
|
#define FVARS (TOP - 105) /* (F): forth.v4, 7 cells */
|
|
#define SVARS (TOP - 540 - (v4_cell)V4_DATA_DEPTH) /* (S): where PICK and ROLL set stack values aside, one cell for each cell of the stack */
|
|
#define WVARS (TOP - 99) /* (W): numout.v4, 3 cells */
|
|
#define CONTEXT (TOP - 64) /* the vocabulary names are looked up in */
|
|
#define CURRENT (TOP - 63) /* the vocabulary new words go into */
|
|
#define VOC_LINK (TOP - 50) /* the newest vocabulary */
|
|
#define FENCE (TOP - 26) /* FORGET's lower limit */
|
|
#define HLD (TOP - 25) /* where the pictured number has got to */
|
|
|
|
/* buffers (word addresses; a byte address is four times this) */
|
|
#define CFS_W (TOP - 96) /* the control-flow stack, 32 cells */
|
|
#define CFS_CELLS 32
|
|
#define WBUF_W (TOP - 170) /* WORD's buffer: 65 cells = 260 bytes */
|
|
#define WBUF_CELLS 65
|
|
#define TIB_W (TOP - 440) /* the text input buffer: 260 cells = 1040 bytes; a line is at most 1024 */
|
|
#define PAD_W (TOP - 470) /* PAD: 21 cells = 84 bytes */
|
|
#define SBUF_W (TOP - 540) /* 64 cells for the tests' own strings */
|
|
#define HBUF_W (SVARS - 16) /* the hold buffer: 16 cells = 64 bytes */
|
|
#define HEND ((HBUF_W + 16) * 4)
|
|
#define XVARS (HBUF_W - 4) /* (X): words.v4, 4 cells */
|
|
#define QBASE (XVARS - 40) /* the Q words' and DUMP's scratch cells, 39 in all */
|
|
#define BVARS (QBASE - 16) /* blocks.v4: 6 cells not used now, then SCR BLK (SRC) (SRC-HOOK) */
|
|
#define SCR (BVARS + 6)
|
|
#define BLK (BVARS + 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 REFUSED (BUF0_W - 7) /* how many of this node's messages it has been told were refused */
|
|
#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. */
|
|
#define CONSOLE (BUF0_W - 16) /* the node what this one prints is sent to; 0: whoever sent the text being served */
|
|
#define ROUTE_COUNT (BUF0_W - 17) /* how many entries the table of ways holds */
|
|
#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 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 P_NEED (BUF0_W - 100) /* and the cells it needs there */
|
|
#define H_PORT (BUF0_W - 99) /* the port of the first message left on its wire for want of room on this pass; -1: none */
|
|
#define H_NEED (BUF0_W - 98) /* the cells it needs there */
|
|
#define H_MASK (BUF0_W - 97) /* and a bit for each port something was left for */
|
|
#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; - 122 .. - 113; BUF0_W - 144 .. - 141 (what a flush makes zero after
|
|
* a full output buffer); 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 NEAR (BUF0_W - 64) /* for each port, the number of the node on the other end; 0: not told */
|
|
#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 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
|
|
#define WORD_DEFINED (BUF0_W - 11) /* the xt of the word that is told of each new entry, or 0 */
|
|
#define WORD_FORGOTTEN (BUF0_W - 12) /* the xt of the word that is told when entries go, or 0 */
|
|
#define LOG_LEVEL (BUF0_W - 5) /* the level at or below which a message is printed */
|
|
#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 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 < 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)
|
|
#define PAD (PAD_W * 4)
|
|
#define SBUF (SBUF_W * 4)
|
|
|
|
/* dictionary space */
|
|
#ifndef DICT_W
|
|
#define DICT_W ((v4_cell)8192)
|
|
#endif
|
|
#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 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. */
|
|
static unsigned host_branch_slots(void)
|
|
{
|
|
unsigned k, slots = 0;
|
|
for (k = 0; k < 4; k++) if ((v4_ucell)v4_iword_slot_mask(k) >= (v4_ucell)(V4_NODE_WORDS - 1u)) slots = k + 1;
|
|
return slots;
|
|
}
|
|
|
|
/* Reset `n`, give the assembler every constant the capsule files ask for, and
|
|
* assemble the `count` files named. Returns 1 if all assembled; otherwise
|
|
* prints which did not and why. The caller may assemble more text and must
|
|
* call v4_text_finish. */
|
|
static int host_load(v4_text *tx, v4_node *n, const char *const *files, unsigned count)
|
|
{
|
|
char path[512];
|
|
unsigned i;
|
|
|
|
v4_node_reset(n);
|
|
HOST_MESSAGES_EMPTY(n); /* nothing has been printed and no message waits (core.v4) */
|
|
v4_text_begin(tx, n, 16);
|
|
v4_text_constant(tx, "N-1", V4_CELL_BITS - 1);
|
|
v4_text_constant(tx, "NODE-ERROR", NODE_ERROR);
|
|
v4_text_constant(tx, "CONSOLE-TX", CONSOLE_TX);
|
|
v4_text_constant(tx, "CONSOLE-RX", CONSOLE_RX);
|
|
v4_text_constant(tx, "CONSOLE-STATUS", CONSOLE_ST);
|
|
v4_text_constant(tx, "BASE", BASE);
|
|
v4_text_constant(tx, "TIB", TIB);
|
|
v4_text_constant(tx, ">IN", TO_IN);
|
|
v4_text_constant(tx, "SPAN", SPAN);
|
|
v4_text_constant(tx, "WBUF", WBUF);
|
|
v4_text_constant(tx, "(P)", PVARS);
|
|
v4_text_constant(tx, "DP", DP);
|
|
v4_text_constant(tx, "(LATEST)", LATEST);
|
|
v4_text_constant(tx, "DBASE", DICT_W * 4);
|
|
v4_text_constant(tx, "DLIMIT", DICT_END_W * 4);
|
|
v4_text_constant(tx, "PAD", PAD);
|
|
v4_text_constant(tx, "(D)", DVARS);
|
|
v4_text_constant(tx, "(CG)", CGVARS);
|
|
v4_text_constant(tx, "CG-BSLOTS", (v4_cell)host_branch_slots());
|
|
v4_text_constant(tx, "STATE", STATE);
|
|
v4_text_constant(tx, "(C)", CVARS);
|
|
v4_text_constant(tx, "(CFP)", CFP);
|
|
v4_text_constant(tx, "(Q)", QVARS);
|
|
v4_text_constant(tx, "(F)", FVARS);
|
|
v4_text_constant(tx, "(S)", SVARS);
|
|
v4_text_constant(tx, "(W)", WVARS);
|
|
v4_text_constant(tx, "(X)", XVARS);
|
|
v4_text_constant(tx, "(BOOT)", BOOT_CELLS);
|
|
v4_text_constant(tx, "(LOG-LEVEL)", LOG_LEVEL);
|
|
v4_text_constant(tx, "(ACL-HOOK)", ACL_HOOK);
|
|
v4_text_constant(tx, "SCR", SCR);
|
|
v4_text_constant(tx, "BLK", BLK);
|
|
v4_text_constant(tx, "(SRC)", SRC);
|
|
v4_text_constant(tx, "(SRC-HOOK)", SRC_HOOK);
|
|
v4_text_constant(tx, "(LINE-STATUS)", LINE_STATUS);
|
|
v4_text_constant(tx, "(PORT)", PORT);
|
|
v4_text_constant(tx, "(ME)", ME);
|
|
v4_text_constant(tx, "(CONSOLE)", CONSOLE);
|
|
v4_text_constant(tx, "(ROUTE#)", ROUTE_COUNT);
|
|
v4_text_constant(tx, "(ROUTE-DEFAULT)", ROUTE_DEFAULT);
|
|
v4_text_constant(tx, "(LOST)", LOST);
|
|
v4_text_constant(tx, "(PRINT-TO)", PRINT_TO);
|
|
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, "-PORTS", -(v4_cell)V4_PORTS);
|
|
v4_text_constant(tx, "(NEAR)", NEAR);
|
|
v4_text_constant(tx, "(AWAIT-FROM)", AWAIT_FROM);
|
|
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, "(P-NEED)", P_NEED);
|
|
v4_text_constant(tx, "(H-PORT)", H_PORT);
|
|
v4_text_constant(tx, "(H-NEED)", H_NEED);
|
|
v4_text_constant(tx, "(H-MASK)", H_MASK);
|
|
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, "(REFUSED)", REFUSED);
|
|
v4_text_constant(tx, "(OUT^)", OUT_PTR);
|
|
v4_text_constant(tx, "(REPLY)", REPLY);
|
|
v4_text_constant(tx, "(MSG)", MSG);
|
|
v4_text_constant(tx, "(OUT)", OUT_W);
|
|
v4_text_constant(tx, "(WORD-DEFINED)", WORD_DEFINED);
|
|
v4_text_constant(tx, "(WORD-FORGOTTEN)", WORD_FORGOTTEN);
|
|
v4_text_constant(tx, "BLOCK#", V4_REQ_BLOCK); /* the kernel's block requests (v4/blocks.h) */
|
|
v4_text_constant(tx, "BUFFER#", V4_REQ_BUFFER);
|
|
v4_text_constant(tx, "UPDATE#", V4_REQ_UPDATE);
|
|
v4_text_constant(tx, "SAVE-BUFFERS#", V4_REQ_SAVE_BUFFERS);
|
|
v4_text_constant(tx, "EMPTY-BUFFERS#", V4_REQ_EMPTY_BUFFERS);
|
|
v4_text_constant(tx, "(Q/)", QBASE); /* 5 cells */
|
|
v4_text_constant(tx, "(QE)", QBASE + 5); /* 8 */
|
|
v4_text_constant(tx, "(QR)", QBASE + 13); /* 5 */
|
|
v4_text_constant(tx, "(QL)", QBASE + 18); /* 7 */
|
|
v4_text_constant(tx, "(QT)", QBASE + 25); /* 6 */
|
|
v4_text_constant(tx, "(QP)", QBASE + 31); /* 4 */
|
|
v4_text_constant(tx, "(DP)", QBASE + 35); /* 4 */
|
|
v4_text_constant(tx, "ADDR-DIGITS", V4_CELL_BITS / 4);
|
|
v4_text_constant(tx, "MSB", (v4_cell)V4_MSB);
|
|
v4_text_constant(tx, "MAXHI", (v4_cell)(V4_MSB - 1u));
|
|
v4_text_constant(tx, "HIMASK", (v4_cell)(((v4_ucell)1 << (V4_CELL_BITS - 16)) - 1u));
|
|
v4_text_constant(tx, "2N+15", 2 * V4_CELL_BITS + 15);
|
|
v4_text_constant(tx, "N-18", V4_CELL_BITS - 18);
|
|
v4_text_constant(tx, "N-17", V4_CELL_BITS - 17);
|
|
v4_text_constant(tx, "MAX-INT", (v4_cell)(V4_MSB - 1u));
|
|
v4_text_constant(tx, "HLD", HLD);
|
|
v4_text_constant(tx, "FENCE", FENCE);
|
|
v4_text_constant(tx, "CONTEXT", CONTEXT);
|
|
v4_text_constant(tx, "CURRENT", CURRENT);
|
|
v4_text_constant(tx, "VOC-LINK", VOC_LINK);
|
|
v4_text_constant(tx, "HEND", HEND);
|
|
v4_text_constant(tx, "-HFLOOR", -(HEND - 62));
|
|
v4_text_constant(tx, "DSTACK-DEPTH", DSTACK_REG);
|
|
v4_text_constant(tx, "RSTACK-DEPTH", RSTACK_REG);
|
|
v4_node_stack_regs_attach(n, DSTACK_REG, RSTACK_REG);
|
|
v4_text_constant(tx, "CFBASE", CFS_W);
|
|
v4_text_constant(tx, "CFEND", CFS_W + CFS_CELLS);
|
|
for (i = 0; i < count; i++) {
|
|
snprintf(path, sizeof path, "%s/%s", V4_CAPSULE_DIR, files[i]);
|
|
if (!v4_text_assemble_file(tx, path)) {
|
|
printf(" %s does not assemble: %s\n", files[i], v4_text_error(tx));
|
|
return 0;
|
|
}
|
|
}
|
|
/* one vocabulary, FORTH, whose head cell is LATEST */
|
|
n->mem[CONTEXT] = LATEST;
|
|
n->mem[CURRENT] = LATEST;
|
|
n->mem[VOC_LINK] = 0;
|
|
/* and the text interpreted is the terminal's */
|
|
n->mem[SRC] = TIB;
|
|
return 1;
|
|
}
|
|
|
|
#endif /* V4_TESTS_HOST_MAP_H */
|