ENGINE.md 3b, the node's side of ruling A (a word's code is the node's, its
accounts the kernel's).
- dict.v4, system.v4: (WORD-DEFINED) ( xt -- ) is run when an entry is
made, (WORD-FORGOTTEN) ( w -- ) when FORGET or COLD removes entries; with
0 there no one is told, as on the hosted product
- test_host_quit.c: a kernel that keeps the list of words and is checked to
hold exactly the node's dictionary after definitions, a vocabulary, an
abandoned definition, FORGET, a refused FORGET and COLD; KERNEL-WORD
called from the prompt and from a definition
Fixed, found while writing that test: since the capsules moved from build
time to boot time (294e6946), what COLD returns to and FORGET protects was
still the nucleus alone, so COLD lost U*, U/MOD and BYE and FORGET U* was
allowed. The boot now seals the system when it has loaded it
(v4_image_seal), and hosted-check checks COLD, the capsule word after it,
the refused FORGET and BYE.
Verified: make -C v4 test passes at both widths (1283 checks in
test_host_quit.c); hosted-check passes on three ISAs; clean qemu with
STARFORTH_V4=1 on amd64, aarch64 and riscv64 passes POST, and COLD, U*
after it, FORGET U* (refused), an unserved kernel word and BYE typed at
each prompt are answered correctly (logs/20261005-193045, -193307, -193636).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
108 lines
4.9 KiB
C
108 lines
4.9 KiB
C
/* image.h -- a capsule image: the host node's memory with the vocabulary in
|
|
* it, and what a loader needs to know to start it.
|
|
*
|
|
* The compiler capsule is text (capsule/ *.v4) and FORTH source (capsule/
|
|
* *.fth). tools/mkimage.c assembles the one and has a node compile the
|
|
* other, on the build machine, and writes what the node's memory then holds
|
|
* as a C file. A system that is to run the vocabulary -- the hosted binary,
|
|
* the bare-metal kernel -- links that file and calls v4_image_boot: it needs
|
|
* no assembler, no files and no C library.
|
|
*
|
|
* An image is for one cell width, one node size and one pair of stack sizes;
|
|
* v4_image_boot refuses an image the engine was not built for.
|
|
*/
|
|
#ifndef V4_IMAGE_H
|
|
#define V4_IMAGE_H
|
|
|
|
#include "v4/exec.h"
|
|
|
|
/* one word of memory that is not zero */
|
|
typedef struct {
|
|
v4_cell addr;
|
|
v4_cell value;
|
|
} v4_image_cell;
|
|
|
|
typedef struct {
|
|
const v4_image_cell *cells; /* every non-zero word of memory, in address order */
|
|
unsigned count;
|
|
|
|
/* what the image was built for */
|
|
unsigned cell_bits, node_words, data_ring, ret_ring;
|
|
|
|
/* The node is handed a line (docs/v4.0.0/ENGINE.md 3.1). Its host puts
|
|
* text in the input buffer and starts it at `line`; it stops at `idle`,
|
|
* with how the line ended in the cell `line_status`. At switch-on it
|
|
* is at `idle`. */
|
|
v4_cell line; /* (LINE) */
|
|
v4_cell idle; /* (IDLE) */
|
|
v4_cell line_status; /* word address of the variable (LINE-STATUS) */
|
|
v4_cell tib; /* byte address of the input buffer */
|
|
unsigned tib_bytes; /* its size: a line may be one less */
|
|
v4_cell span; /* word address of the variable SPAN */
|
|
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 image was built with) */
|
|
v4_cell console_tx, console_rx, console_status;
|
|
v4_cell dstack_reg, rstack_reg;
|
|
v4_cell node_error;
|
|
v4_cell storage_reg;
|
|
|
|
/* 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 image has them as the nucleus alone; a system
|
|
* that loads capsules when it boots sets them again when it has
|
|
* (v4_image_seal). */
|
|
v4_cell boot_cells, fence;
|
|
} v4_image;
|
|
|
|
/* The image built from v4/capsule (the generated file defines it). */
|
|
extern const v4_image v4_capsule_image;
|
|
|
|
/* 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);
|
|
|
|
/* How a line ended. */
|
|
#define V4_LINE_QUIT 0 /* QUIT: nothing is to be said */
|
|
#define V4_LINE_COMPLETED 1 /* the host says " ok" */
|
|
#define V4_LINE_ERROR 2 /* the message is printed; the host says " ERROR" */
|
|
|
|
/* Reset `n`, load the image into it, attach its registers -- with `disk`,
|
|
* `blocks` blocks of 1024 bytes, as its block storage, or none if `disk` is
|
|
* 0 -- and leave it idle, waiting to be handed a line. Returns 1, or 0 if
|
|
* the image is not for this build of the engine (nothing is then done). */
|
|
int v4_image_boot(v4_node *n, v4_exec_state *es, v4_heat *h, const v4_image *im,
|
|
unsigned char *disk, unsigned blocks);
|
|
|
|
/* Hand the node `len` characters of text to interpret. Returns 1, or 0 if
|
|
* the text is longer than the node's input buffer holds (nothing is then
|
|
* done). After it the host runs the node -- v4_exec_step_word again and
|
|
* again, taking what the node prints from n->console and setting
|
|
* n->console_len back to 0 -- until v4_line_done; if v4_image_waiting comes
|
|
* first, the line is reading the keyboard, and the host gives it characters
|
|
* with v4_node_console_feed. */
|
|
int v4_line_begin(v4_node *n, const v4_image *im, const char *text, unsigned len);
|
|
|
|
/* 1 when the node has finished the line it was handed and is idle again. */
|
|
int v4_line_done(const v4_node *n, const v4_image *im);
|
|
|
|
/* How the line just finished ended: V4_LINE_QUIT, _COMPLETED or _ERROR. */
|
|
int v4_line_status(const v4_node *n, 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 */
|