/* SPDX-License-Identifier: LicenseRef-Starship-1.0 * Copyright (c) 2023-2026 Robert A. James */ /* image.h -- the StarForth system, as its host knows it: where things are * in a node that holds it, and how a line is handed to that node. * * The system is text, the .f18 blobs of capsules/v4/sys, and the machine's * ROM assembles it when the machine starts (docs/v4.0.0/MACHINE.md; v4/ * system/boot.c). Its host knows two things of it: * * - the memory map, before it is built: v4_map_image, a C file that * tools/mkmap.c writes from the map (`mkmap image`); * - what only the assembled system knows -- where it waits, its fault * table, KEY -- from the image record, a fixed block of RAM whose * address is a constant of the map and which the system's source * stores (capsules/v4/sys/end.f18): v4_image_from_node. * * A node that holds the system is sent text as messages and sends back * what it prints (v4/include/v4/message.h); nothing here hands it a line. * * A description is for one cell width, one node size and one pair of stack * sizes; v4_image_born refuses one the engine was not built for. */ #ifndef V4_IMAGE_H #define V4_IMAGE_H #include "v4/exec.h" typedef struct { /* what the image was built for */ unsigned cell_bits, node_words, data_ring, ret_ring; /* Where the system waits for a message (capsules/v4/sys/quit.f18, * (IDLE)): a node that holds the system begins there, and with nothing * to do it is asleep at a wire inside it (operation 8, MESH.md 7d.3). * This, fault_table, key_start and key_end are -1 until the system is * built (v4_image_from_node). */ v4_cell idle; v4_cell fault_table; /* (FAULTS): where a fault goes */ v4_cell port; /* word address of the node's port (node.h) */ /* KEY's code: a node whose P is in key_start .. key_end - 1 with no * character pending is waiting for one */ v4_cell key_start, key_end; /* the memory-mapped registers (DECOMPOSITION.md section 7; D-4 leaves * the map to the loader, and this is the map the system is built with) */ v4_cell console_tx, console_rx, console_status; v4_cell dstack_reg, rstack_reg; v4_cell node_error; /* the dictionary's two variables: DP holds HERE, a byte address, and * LATEST the newest word of FORTH. What lies below HERE, and LATEST, * is what the dictionary hash covers (v4/include/v4/boot.h). */ v4_cell dp, latest; /* What COLD returns the system to and FORGET will not go below: two * cells, DP and LATEST as they were when the system was complete, and * the variable FENCE. The system's source sets them; a system that * loads capsules when it boots sets them again when it has * (v4_image_seal). */ v4_cell boot_cells, fence; /* the block window: the word address of the slots the kernel copies * blocks into (v4/blocks.h) */ v4_cell block_window; /* the image record (capsules/v4/sys/end.f18): four cells, where the * system waits, its fault table, KEY and the word after KEY; and the * ROM's two cells that say why it stopped, if it did: the code of its * error (0 if none) and the line it was on, counting from 0 */ v4_cell record, rom_failed, rom_errline; } v4_image; /* The system's error for a node blocked at a port with no one on it * (capsules/v4/sys/core.f18's list; node.h, v4_node_port_gone): "No one on * that port". */ #define V4_ERROR_NO_ONE 18 /* The memory map's description of the system (the generated file defines * it): what is known of it before it is built. */ extern const v4_image v4_map_image; /* What only the assembled system knows, read from the image record of the * node `n` that holds it into `im`, which the map's description is in. * Returns 1, or 0 if the record does not name addresses of the node's * memory (nothing is then changed). */ int v4_image_from_node(const v4_node *n, v4_image *im); /* The system is complete: what is in the dictionary now is what COLD comes * back to, and FORGET will not go below it. */ void v4_image_seal(v4_node *n, const v4_image *im); /* The dictionary hash of a node started from `im`: FNV-1a over its memory * below HERE, a cell at a time, low byte first, and then LATEST. It does * not depend on the machine: every build of one commit, with one cell * width, gives the same hash for the same dictionary. */ uint64_t v4_image_dict_hash(const v4_node *n, const v4_image *im); /* A node newly born (node.h), with the registers the system expects of the * node it runs on. Its memory is empty and it is blocked * reading its ports: its code is yet to be sent to it, or assembled on it. Returns 1, or 0 * if the description is not for this build of the engine (nothing is then * done). */ int v4_image_born(v4_node *n, v4_exec_state *es, v4_heat *h, const v4_image *im); /* 1 if the node is waiting for a character: it is inside KEY and none is * pending. */ int v4_image_waiting(const v4_node *n, const v4_image *im); #endif /* V4_IMAGE_H */