/* 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 #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 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. */ #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 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 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 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 A_FOUND, 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) #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 messages waiting are above the dictionary */ typedef char host_map_queue_fits[(MQ_W >= DICT_END_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, "(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, "(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); 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 */