# StarForth Primitive Word Reference This reference covers every **C-implemented primitive** word that StarForth registers. It was built from `admin/LithosAnanake` at commit `6302dcb` (2026-09-23). It lists only words registered in C through `register_word()` or `vm_create_word()`. Words defined in FORTH inside capsules (`*.4th`) are out of scope. Sources: - `src/word_registry.c`: `register_forth79_words()` registers the core set in every VM. - `src/word_source/*.c`: one file per module. - `src/starkernel/capsule/mama_forth_words.c`: kernel-only Hera (Mama) and child-VM words. - `src/starkernel/repl.c` and `src/starkernel/doe_log.c`: kernel-only REPL and DoE words. --- ## Conventions | Item | Meaning | |---|---| | Cell | `cell_t` is `int64_t`, so every cell is 64 bits and signed. | | Flag | TRUE is `-1` (all bits set) and FALSE is `0`. Words that take a flag treat any non-zero value as true. | | `addr` | A **VM address**: a byte offset into the VM's 5 MB linear memory (`VM_MEMORY_SIZE`), not a host pointer. | | `c-addr u` | A string given as its address and length. | | `d`, `ud` | A double-cell number made of two cells, with the **high cell on top**. | | `xt` | An execution token. In StarForth this is the `DictEntry*` of the word. | | `q` | A Q48.16 fixed-point value in one cell (`1.0` = `65536`). | | `"name"` | The word parses a name from the input stream after it. | | `( R: ... )` | The effect on the return stack. | | **IMM** | The word is IMMEDIATE, so it runs even while compiling. | | **CO** | The word is compile-only and sets `vm->error` if used outside a definition. | | **K** | The word is registered only in the kernel build (`__STARKERNEL__`). | | **H** | The word is registered only in the hosted build (the Linux or macOS binary). | Errors: a primitive does not throw. On stack underflow or overflow, a bad address, or division by zero it sets `vm->error = 1` and logs a message. Stack limits: the data stack and return stack hold 1024 cells each (`STACK_SIZE`). A word name can be at most 31 characters (`WORD_NAME_MAX`). Shadowing: when a later module registers a name again, the newer entry wins lookups. For example, `MOD`, `/MOD`, `*/` and `*/MOD` are registered by the arithmetic module and again by the mixed-arithmetic module, so the mixed-arithmetic versions are the active ones. --- ## Contents 1. [Stack](#1-stack) 2. [Return stack](#2-return-stack) 3. [Memory](#3-memory) 4. [Arithmetic](#4-arithmetic) 5. [Logic and comparison](#5-logic-and-comparison) 6. [Mixed-precision arithmetic](#6-mixed-precision-arithmetic) 7. [Double-cell numbers](#7-double-cell-numbers) 8. [Number formatting and output](#8-number-formatting-and-output) 9. [Strings, parsing, and input](#9-strings-parsing-and-input) 10. [Terminal I/O](#10-terminal-io) 11. [Blocks and mass storage](#11-blocks-and-mass-storage) 12. [Dictionary space](#12-dictionary-space) 13. [Dictionary manipulation](#13-dictionary-manipulation) 14. [Vocabularies](#14-vocabularies) 15. [System](#15-system) 16. [Line editor](#16-line-editor) 17. [Defining words and the compiler](#17-defining-words-and-the-compiler) 18. [Control flow](#18-control-flow) 19. [StarForth extensions](#19-starforth-extensions) 20. [Word-level ACL](#20-word-level-acl) 21. [Physics: benchmark and diagnostics](#21-physics-benchmark-and-diagnostics) 22. [Physics: pipelining diagnostics](#22-physics-pipelining-diagnostics) 23. [Physics: freeze, heat, and decay](#23-physics-freeze-heat-and-decay) 24. [Dictionary heat optimisation](#24-dictionary-heat-optimisation) 25. [Logging](#25-logging) 26. [Q48.16 fixed-point math](#26-q4816-fixed-point-math) 27. [Inference engine (SSM, L8, and Bayes)](#27-inference-engine-ssm-l8-and-bayes) 28. [DEFER and IS](#28-defer-and-is) 29. [Framebuffer (Hestia only)](#29-framebuffer-hestia-only) 30. [Keyboard](#30-keyboard) 31. [TrueType text](#31-truetype-text) 32. [REPL scrollback](#32-repl-scrollback) 33. [Kernel REPL and DoE hooks](#33-kernel-repl-and-doe-hooks) 34. [Hera (Mama) and child-VM words](#34-hera-mama-and-child-vm-words) 35. [Hosted lifecycle stubs](#35-hosted-lifecycle-stubs) 36. [Implementation quirks to know](#36-implementation-quirks-to-know) --- ## 1. Stack `src/word_source/stack_words.c` | Word | Stack | Description | |---|---|---| | `DROP` | `( x -- )` | Discards the top cell. | | `DUP` | `( x -- x x )` | Copies the top cell. | | `?DUP` | `( x -- x x \| 0 -- 0 )` | Copies the top cell only when it is non-zero. The usual idiom is `?DUP IF ... THEN`. | | `SWAP` | `( x1 x2 -- x2 x1 )` | Swaps the top two cells. | | `OVER` | `( x1 x2 -- x1 x2 x1 )` | Copies the second cell to the top. | | `ROT` | `( x1 x2 x3 -- x2 x3 x1 )` | Moves the third cell to the top. | | `-ROT` | `( x1 x2 x3 -- x3 x1 x2 )` | Moves the top cell down to third place. This is the reverse of `ROT`. | | `DEPTH` | `( -- n )` | Pushes the number of cells that were on the data stack before `DEPTH` ran. | | `PICK` | `( xn … x0 n -- xn … x0 xn )` | Copies the n-th cell to the top. **0-based:** `0 PICK` is `DUP` and `1 PICK` is `OVER`. An error occurs if `n < 0` or `n ≥ depth`. | | `ROLL` | `( … n -- … )` | Moves a cell to the top and closes the gap. **Non-standard:** `n` counts from the *bottom* of the stack (1-based), so `1 ROLL` moves the deepest cell to the top. `0 ROLL` does nothing. See [§36](#36-implementation-quirks-to-know). | ## 2. Return stack `src/word_source/return_stack_words.c` | Word | Stack | Description | |---|---|---| | `>R` | `( x -- ) ( R: -- x )` | Moves a cell from the data stack to the return stack. Inside a definition, balance it with `R>` before `;` or `EXIT`. | | `R>` | `( -- x ) ( R: x -- )` | Moves a cell from the return stack back to the data stack. | | `R@` | `( -- x ) ( R: x -- x )` | Copies the top of the return stack without removing it. | ## 3. Memory `src/word_source/memory_words.c`. Every address is a VM byte offset and is checked against the VM's memory bounds. | Word | Stack | Description | |---|---|---| | `@` | `( addr -- x )` | Fetches the cell at `addr`. | | `!` | `( x addr -- )` | Stores `x` at `addr`. | | `C@` | `( addr -- c )` | Fetches the byte at `addr`, zero-extended. | | `C!` | `( c addr -- )` | Stores the low 8 bits of `c` at `addr`. | | `+!` | `( n addr -- )` | Adds `n` to the cell at `addr`. | | `-!` | `( n addr -- )` | Subtracts `n` from the cell at `addr`. | | `2@` | `( addr -- x-lo x-hi )` | Fetches two cells: the low cell from `addr` and the high cell from `addr+8`, leaving the high cell on top. | | `2!` | `( x-lo x-hi addr -- )` | Stores two cells: the low cell at `addr` and the high cell at `addr+8`. | | `FILL` | `( addr u c -- )` | Fills `u` bytes starting at `addr` with the byte `c`. | | `MOVE` | `( src dst u -- )` | Copies `u` bytes from `src` to `dst`. It is safe when the ranges overlap because it uses memmove semantics. | | `ERASE` | `( addr u -- )` | Sets `u` bytes to zero. | | `CELLS` | `( n -- n*8 )` | Scales a cell count to a byte count. | ## 4. Arithmetic `src/word_source/arithmetic_words.c`. All arithmetic is signed 64-bit, and division truncates toward zero as in C. | Word | Stack | Description | |---|---|---| | `+` | `( n1 n2 -- n1+n2 )` | Adds the two cells. | | `-` | `( n1 n2 -- n1-n2 )` | Subtracts `n2` from `n1`. | | `*` | `( n1 n2 -- n1*n2 )` | Multiplies the two cells. The result wraps modulo 2⁶⁴. | | `/` | `( n1 n2 -- n1/n2 )` | Divides, truncating toward zero. Division by zero sets an error. | | `MOD` | `( n1 n2 -- rem )` | Pushes the remainder of `n1 / n2`, which has the sign of `n1`. This name is shadowed by §6. | | `/MOD` | `( n1 n2 -- rem quot )` | Pushes the remainder and the quotient, with the quotient on top. This name is shadowed by §6. | | `*/` | `( n1 n2 n3 -- n1*n2/n3 )` | Multiplies and then divides using a wide intermediate. This name is shadowed by §6. | | `*/MOD` | `( n1 n2 n3 -- rem quot )` | Like `*/`, but also leaves the remainder. This name is shadowed by §6. | | `1+` `1-` | `( n -- n±1 )` | Increments or decrements by 1. | | `2+` `2-` | `( n -- n±2 )` | Adds or subtracts 2. | | `2*` | `( n -- n*2 )` | Shifts left by one bit. | | `2/` | `( n -- n/2 )` | Shifts right by one bit, keeping the sign (arithmetic shift). | | `ABS` | `( n -- \|n\| )` | Pushes the absolute value. | | `NEGATE` | `( n -- -n )` | Pushes the two's-complement negation. | | `MIN` `MAX` | `( n1 n2 -- n3 )` | Pushes the smaller or the larger value, compared as signed numbers. | ## 5. Logic and comparison `src/word_source/logical_words.c`. Comparison words return a proper flag of `-1` or `0`. | Word | Stack | Description | |---|---|---| | `AND` `OR` `XOR` | `( x1 x2 -- x3 )` | Bitwise AND, OR, and XOR. | | `NOT` | `( x -- flag )` | **FORTH-79 logical NOT:** `0` gives `TRUE` and any other value gives `FALSE`. This is *not* a bitwise complement; use `INVERT` for that. | | `INVERT` | `( x -- ~x )` | Bitwise complement (from FORTH-83). | | `LSHIFT` | `( x u -- x<>u )` | Logical (unsigned) shift right by `u` bits. | | `0=` | `( n -- flag )` | True if `n` is 0. | | `0<` | `( n -- flag )` | True if `n` is negative. | | `0>` | `( n -- flag )` | True if `n` is positive. | | `0<>` | `( n -- flag )` | True if `n` is not 0. | | `=` `<>` | `( n1 n2 -- flag )` | Tests for equality or inequality. | | `<` `>` `<=` `>=` | `( n1 n2 -- flag )` | Signed comparisons of `n1` against `n2`. | | `U<` `U>` | `( u1 u2 -- flag )` | Unsigned comparisons. | | `WITHIN` | `( n lo hi -- flag )` | True if `lo ≤ n < hi`, using the standard half-open range. | | `TRUE` | `( -- -1 )` | Pushes the canonical true flag. | | `FALSE` | `( -- 0 )` | Pushes the canonical false flag. | ## 6. Mixed-precision arithmetic `src/word_source/mixed_arithmetic_words.c`. A double here means two full 64-bit cells (128 bits). | Word | Stack | Description | |---|---|---| | `M+` | `( d n -- d' )` | Adds a signed single to a double and propagates the carry into the high cell. | | `M-` | `( d n -- d' )` | Subtracts a signed single from a double and propagates the borrow. | | `M*` | `( n1 n2 -- d )` | Multiplies 64×64 into a full 128-bit signed product, using `__int128` internally. The result can be printed with `D.`. | | `M/MOD` | `( d n -- rem quot )` | Divides a 128-bit double by a single, leaving the quotient on top. It uses bit-serial long division, so it works in the freestanding kernel without libgcc. | | `MOD` | `( n1 n2 -- rem )` | **Active version.** Computes `n1 % n2`. Division by zero sets an error. | | `/MOD` | `( n1 n2 -- rem quot )` | **Active version.** Leaves the remainder under the quotient. Division by zero sets an error. | | `*/` | `( n1 n2 n3 -- n4 )` | **Active version.** Computes `(n1*n2)/n3` with a wide intermediate, so `n1*n2` does not overflow. Division by zero sets an error. Typical use is scaling, for example `x 355 113 */`. | | `*/MOD` | `( n1 n2 n3 -- rem quot )` | **Active version.** Like `*/`, but also leaves the remainder under the quotient. | ## 7. Double-cell numbers `src/word_source/double_words.c`. In every stack picture, `d` stands for the pair `( lo hi )` with the high cell on top. | Word | Stack | Description | |---|---|---| | `S>D` | `( n -- d )` | Sign-extends a single to a double. | | `D+` `D-` | `( d1 d2 -- d3 )` | Double add and subtract, with carry or borrow. | | `DNEGATE` | `( d -- -d )` | Negates a double. | | `DABS` | `( d -- \|d\| )` | Pushes the absolute value of a double. | | `DMAX` `DMIN` | `( d1 d2 -- d3 )` | Pushes the larger or smaller double, compared as signed values. | | `D<` | `( d1 d2 -- flag )` | Signed less-than on doubles. | | `D=` | `( d1 d2 -- flag )` | Equality on doubles. | | `D0=` | `( d -- flag )` | True if the double is zero. | | `D0<` | `( d -- flag )` | True if the double is negative. | | `D2*` | `( d -- d*2 )` | Shifts a double left by one bit across both cells. | | `D2/` | `( d -- d/2 )` | Shifts a double right by one bit (arithmetic shift) across both cells. | | `2DROP` | `( x1 x2 -- )` | Drops a cell pair. | | `2DUP` | `( x1 x2 -- x1 x2 x1 x2 )` | Duplicates a cell pair. | | `2SWAP` | `( p1 p2 -- p2 p1 )` | Swaps two cell pairs. | | `2OVER` | `( p1 p2 -- p1 p2 p1 )` | Copies the second pair to the top. | | `2ROT` | `( p1 p2 p3 -- p2 p3 p1 )` | Rotates three cell pairs. | | `2>R` | `( x1 x2 -- ) ( R: -- x1 x2 )` | Moves a pair to the return stack. | | `2R>` | `( -- x1 x2 ) ( R: x1 x2 -- )` | Moves a pair back from the return stack. | | `2R@` | `( -- x1 x2 ) ( R: x1 x2 -- x1 x2 )` | Copies a pair from the return stack. | ## 8. Number formatting and output `src/word_source/format_words.c` | Word | Stack | Description | |---|---|---| | `.` | `( n -- )` | Prints a signed number in the current `BASE`, followed by a space. | | `.R` | `( n width -- )` | Prints a signed number right-aligned in a field `width` characters wide. | | `U.` | `( u -- )` | Prints an unsigned number followed by a space. | | `U.R` | `( u width -- )` | Prints an unsigned number right-aligned. | | `D.` | `( d -- )` | Prints a signed double. | | `D.R` | `( d width -- )` | Prints a signed double right-aligned. | | `.S` | `( -- )` | Prints the data stack without changing it. This is the main debugging aid. | | `?` | `( addr -- )` | Prints the cell at `addr`; it is the same as `@ .`. | | `DUMP` | `( addr u -- )` | Prints a hex and ASCII dump of `u` bytes starting at `addr`. | | `<#` | `( -- )` | Starts pictured numeric output by resetting the conversion buffer. | | `#` | `( ud -- ud' )` | Converts one digit (`ud mod BASE`) into the buffer. It also accepts a single signed cell and converts its magnitude. | | `#S` | `( ud -- 0 0 )` | Converts digits until the value is zero, always producing at least one digit. It accepts a single cell the same way `#` does. | | `HOLD` | `( c -- )` | Inserts the character `c` into the pictured output buffer. | | `SIGN` | `( n -- )` | Inserts `-` if `n` is negative. | | `#>` | `( ud -- c-addr u )` | Ends conversion and leaves the string. It is tolerant: it pops `ud` only if one is present. | | `BASE` | `( -- addr )` | Pushes the address of the number-conversion radix variable. | | `DECIMAL` `HEX` `OCTAL` | `( -- )` | Sets `BASE` to 10, 16, or 8. | Example: `: .$ ( n -- ) <# # # 46 HOLD #S #> TYPE ;` prints `1234` as `12.34`. ## 9. Strings, parsing, and input `src/word_source/string_words.c`. The comparison and search words below also accept a counted string in place of an `addr u` pair; they detect it when the first byte at `addr` equals `u`. | Word | Stack | Description | |---|---|---| | `COUNT` | `( c-addr1 -- c-addr2 u )` | Converts a counted string (length byte followed by characters) into an address and length. | | `EXPECT` | `( addr u -- )` | Reads up to `u` characters from the terminal into `addr` and stores the count read in `SPAN`. | | `SPAN` | `( -- addr )` | Pushes the address of the variable that holds the count from the last `EXPECT`. | | `QUERY` | `( -- )` | Reads a line into `TIB` and resets `>IN`. | | `TIB` | `( -- addr )` | Pushes the address of the terminal input buffer. | | `>IN` | `( -- addr )` | Pushes the address of the offset into the current input source. | | `SOURCE` | `( -- addr u )` | Pushes the current input buffer and its length. | | `WORD` | `( c -- c-addr )` | Skips leading `c` characters, parses up to the next `c`, and returns a counted string. The usual form is `BL WORD`. | | `BL` | `( -- 32 )` | Pushes the ASCII space character. | | `S"` **IMM** | `( "ccc<">" -- c-addr u )` | In interpret mode, stores the string at `HERE` and pushes it. When compiling, it compiles `(s")` followed by the inline text. | | `(s")` | `( -- c-addr u )` | Runtime for a compiled `S"`: reads the inline `[len][chars][pad]` block and skips the IP past it. The compiler inserts it; you do not call it directly. | | `[']` **IMM** | `( "name" -- xt )` | While compiling, compiles the xt of `name` as a literal. In interpret mode it behaves like `'`. | | `LITERAL` `[LITERAL]` | – | Placeholders that do nothing. `LITERAL` is re-registered in §17 (the working version); `[LITERAL]` has no replacement and still does nothing. | | `CONVERT` | `( d1 addr1 -- d2 addr2 )` | Accumulates the digits at `addr1+1…` into `d1` and stops at the first non-digit. This is a simplified version. | | `NUMBER` | `( c-addr -- n flag )` | Converts a counted string to a number. Only base 10 is supported, and `flag` shows whether it succeeded. | | `ENCLOSE` | `( addr c -- addr n1 n2 n3 )` | The classic FIG parser: gives the offsets of the start of the token, the delimiter after it, and the next character. | | `-TRAILING` | `( addr u -- addr u' )` | Removes trailing spaces from the length. | | `CMOVE` | `( src dst u -- )` | Copies bytes upward from low to high addresses. It is safe for overlapping ranges when `dst ≤ src`. | | `CMOVE>` | `( src dst u -- )` | Copies bytes downward from high to low addresses. It is safe for overlapping ranges when `dst > src`. | | `COMPARE` | `( a1 u1 a2 u2 -- n )` | Compares two strings case-sensitively and returns `-1`, `0`, or `1`. | | `SEARCH` | `( a1 u1 a2 u2 -- a3 u3 flag )` | Finds string 2 inside string 1. If found, it returns the tail starting at the match and `-1`. If not, it returns string 1 unchanged and `0`. | | `SCAN` | `( addr u c -- addr' u' )` | Advances to the first occurrence of `c`. If there is none, it returns the end of the string and `0`. | | `SKIP` | `( addr u c -- addr' u' )` | Skips leading occurrences of `c`. | | `BLANK` | `( addr u -- )` | Fills `u` bytes with spaces. | ## 10. Terminal I/O `src/word_source/io_words.c` | Word | Stack | Description | |---|---|---| | `EMIT` | `( c -- )` | Prints one character. | | `CR` | `( -- )` | Prints a newline. | | `KEY` | `( -- c )` | Waits for a character and pushes it. | | `?TERMINAL` | `( -- flag )` | True if a key is waiting. It does not block. | | `TYPE` | `( c-addr u -- )` | Prints `u` characters. | | `SPACE` | `( -- )` | Prints one space. | | `SPACES` | `( n -- )` | Prints `n` spaces. | | `."` **IMM** | `( "ccc<">" -- )` | In interpret mode, prints the string immediately. When compiling, it compiles `(do-string)` and the inline text. | | `(do-string)` | `( -- )` | Runtime for a compiled `."`: prints the inline string and skips the IP past it. The compiler inserts it; you do not call it directly. | ## 11. Blocks and mass storage `src/word_source/block_words.c`. A block is 1024 bytes, viewed as 16 lines of 64 characters. Block numbers are LBNs (logical block numbers) in one address space that spans every attached device. | Word | Stack | Description | |---|---|---| | `BLOCK` | `( u -- addr )` | Returns the VM address of the buffer holding block `u`, reading it from disk if needed. It does not mark the buffer dirty. | | `BUFFER` | `( u -- addr )` | Assigns a buffer to block `u` *without* reading from disk and marks it dirty. Use it when you will overwrite the whole block. | | `UPDATE` | `( -- )` | Marks the current (`SCR`) block dirty and syncs it to the C block layer. | | `SAVE-BUFFERS` | `( -- )` | Writes every dirty buffer to disk. | | `EMPTY-BUFFERS` | `( -- )` | Discards every buffer **without** writing it and zeroes the user block window. | | `FLUSH` | `( -- )` | Runs `SAVE-BUFFERS` and then invalidates all buffers. | | `LOAD` | `( u -- )` | Sets `SCR` to `u` and interprets the 1024 bytes of block `u` as FORTH source. Block 0 cannot be loaded. | | `THRU` | `( u1 u2 -- )` | Loads blocks `u1` through `u2`, including both ends. | | `-->` | `( -- )` | Inside a block being loaded, continues interpreting at the next block. | | `LIST` | `( u -- )` | Sets `SCR` to `u` and prints the block. | | `SCR` | `( -- addr )` | Pushes the address of the variable holding the block number last listed or loaded. | | `BLK-CONFIRM-FORMAT` | `( lbn -- )` | Commits the container format of the device that owns `lbn`. Until this has run, the block layer **refuses every write** to that device. Only the owner (for example Artemis) should call it, and only after checking the disk contents are safe to touch. | | `RELOCATE-BLOCK` | `( home target -- )` | Moves the contents of `home` to `target` and redirects all later access to `home` through `target`. It is a mechanical primitive: it does not check whether `target` is free or owned by the caller. | | `BLK-ACL-ALLOW@` | `( blk -- allow )` | Reads the cached allow/deny flag of a block's ACL. | | `BLK-ACL-ALLOW!` | `( allow blk -- )` | Sets a block's cached allow/deny flag. | | `BLK-ACL-TTL@` | `( blk -- ttl )` | Reads a block's ACL TTL countdown. | | `BLK-ACL-TTL!` | `( ttl blk -- )` | Sets a block's ACL TTL countdown. | | `BLK-OWNER@` | `( blk -- fp )` | Pushes the 8-byte owner fingerprint as the raw bits of one cell. There is no `BLK-OWNER!`: ownership is set only in C, during MINT or birth. | | `BLK-ATTACH` | `( dev-ptr -- ok? )` | Registers an already-open `blkio_dev_t*`, passed as a raw pointer cell, in the unified LBN space. The pointer is trusted without checks. Artemis's USB-attach handler uses it. | ## 12. Dictionary space `src/word_source/dictionary_words.c` | Word | Stack | Description | |---|---|---| | `HERE` | `( -- addr )` | Pushes the next free byte in the dictionary. | | `ALIGN` | `( -- )` | Rounds `HERE` up to the next 8-byte cell boundary. | | `ALLOT` | `( n -- )` | Reserves `n` bytes at `HERE`. A negative `n` gives space back. | | `,` | `( x -- )` | Compiles one cell at `HERE` and advances `HERE`. | | `C,` | `( c -- )` | Compiles one byte. | | `2,` | `( x-lo x-hi -- )` | Compiles two cells, low cell first. | | `PAD` | `( -- addr )` | Pushes the address of a 512-byte scratch buffer near the top of memory. It is safe for temporary strings. | | `SP@` | `( -- n )` | Pushes the data stack pointer *index* (`dsp`). An empty stack gives `-1` and one item gives `0`. | | `SP!` | `( n -- )` | Restores the stack pointer index. It can only shrink the stack, never grow it. | | `LATEST` | `( -- addr )` | Pushes the address of the most recent definition. | ## 13. Dictionary manipulation `src/word_source/dictionary_manipulation_words.c`. Header-field words work on raw header addresses. They exist for FIG and FORTH-79 compatibility; take care with them. | Word | Stack | Description | |---|---|---| | `'` | `( "name" -- xt )` | Parses `name` and pushes its xt. It is not IMMEDIATE; inside a definition, use `[']`. | | `FIND` | `( "name" -- xt \| 0 )` | **Parses from the input stream**, not from a counted string on the stack. It pushes the entry, or `0` if the word is not found (a miss is not an error). For a counted string already in memory, use `(FIND)` from §14. | | `SMUDGE` | `( -- )` | **CO.** Toggles the smudge (hidden) bit on the latest word. | | `HIDDEN` | `( -- )` | **CO.** Sets the latest word's hidden bit (unlike `SMUDGE`, it does not toggle). | | `>BODY` | `( xt -- addr )` | Pushes the address of the parameter (data) field. | | `>NAME` | `( xt -- nfa )` | Pushes the name field. | | `NAME>` | `( nfa -- xt )` | Goes from the name field to the xt. | | `>LINK` | `( xt -- lfa )` | Pushes the link field. | | `LINK>` | `( lfa -- xt )` | Follows the link to the next (older) word. | | `CFA` `LFA` `NFA` `PFA` | `( addr -- addr' )` | FIG-style field-address conversions (code, link, name, and parameter fields). | | `TRAVERSE` | `( addr n -- addr' )` | Moves across a name field forward (`n=1`) or backward (`n=-1`). | | `INTERPRET` | `( -- )` | Runs the text interpreter on the rest of the current input. | ## 14. Vocabularies `src/word_source/vocabulary_words.c` | Word | Stack | Description | |---|---|---| | `VOCABULARY` | `( "name" -- )` | Creates a vocabulary. Running `name` later makes it the `CONTEXT` (search) vocabulary. | | `DEFINITIONS` | `( -- )` | Sets `CURRENT` to `CONTEXT`, so new definitions go into the vocabulary being searched. | | `CONTEXT` | `( -- addr )` | Pushes the address of the search-vocabulary pointer. | | `CURRENT` | `( -- addr )` | Pushes the address of the definition-vocabulary pointer. | | `FORTH` | `( -- )` | Makes the root `FORTH` vocabulary the context. | | `ORDER` | `( -- )` | Prints the search order (`CONTEXT`, then `FORTH`) and `CURRENT`. | | `(FIND)` | `( c-addr -- c-addr 0 \| xt 1 \| xt -1 )` | Looks up a counted string in `CONTEXT` and then in `FORTH`. It returns `1` for an IMMEDIATE word, `-1` for a normal word, and `0` if not found. | Example: `VOCABULARY GRAPHICS GRAPHICS DEFINITIONS : BOX ... ; FORTH DEFINITIONS` ## 15. System `src/word_source/system_words.c` | Word | Stack | Description | |---|---|---| | `(` **IMM** | `( "ccc<)>" -- )` | Starts a comment that runs to the closing `)`. | | `\` **IMM** | `( "ccc" -- )` | Starts a comment that runs to the end of the line. | | `EXECUTE` | `( xt -- )` | Runs the word identified by `xt`. | | `NOP` | `( -- )` | Does nothing. | | `QUIT` **IMM** | `( -- ) ( R: … -- )` | Clears the return stack and the error flag and returns to the outer interpreter. The data stack is kept. It is refused (sets an error) inside a definition. | | `ABORT` | `( … -- )` | Clears both stacks and returns to the interpreter. It is **not** reported as an error. | | `ABORT"` **IMM** | `( flag "ccc<">" -- )` | If `flag` is non-zero, prints the message and runs `ABORT`. It works in both interpret and compile mode. | | `(ABORT")` | `( flag addr u -- )` | Runtime for a compiled `ABORT"`. The compiler inserts it; you do not call it directly. | | `COLD` | `( -- )` | Clears both stacks and the error flag, returns to interpret mode, and moves `HERE` back to 1024 if it is higher. Dictionary headers are **not** removed; this is a minimal cold start. | | `WARM` | `( -- )` | Clears both stacks and the error flag and returns to interpret mode. `HERE` and the dictionary are kept. | | `BYE` | `( -- )` | Leaves this VM. In a child VM it halts the VM and returns to the parent's REPL. On Hera, the kernel's `BYE` from §34 takes precedence. | | `REBOOT` | `( c-addr u -- )` | Sets the boot arguments and does a cold reset. Interpret mode only. | | `SAVE-SYSTEM` | `( -- )` | Takes a simple snapshot of the start of VM memory. | | `WORDS` | `( -- )` | Lists the words in the current vocabulary. | | `VLIST` | `( -- )` | Gives a detailed word listing. | | `SEE` | `( "name" -- )` | Decompiles and shows a definition. | | `PAGE` | `( -- )` | Clears the screen. | | `79-STANDARD` | `( -- flag )` | Pushes `-1` when FORTH-79 compliance mode is on. | ## 16. Line editor `src/word_source/editor_words.c`. The editor works on block `SCR` as 16 lines of 64 characters. | Word | Stack | Description | |---|---|---| | `L` | `( u -- )` | Prints line `u` (0–15) of the current screen. | | `S` | `( c-addr len u -- )` | Replaces line `u` with the string, padding with spaces or truncating to 64 characters. | | `SHOW` | `( -- )` | Prints the whole screen with line numbers. | | `EDIT` | `( u -- )` | Opens a minimal stdin/stdout line-editor shell on block `u`. | ## 17. Defining words and the compiler `src/word_source/defining_words.c` | Word | Stack | Description | |---|---|---| | `:` **IMM** | `( "name" -- )` | Starts a colon definition and switches to compile mode. The new word stays hidden until `;`. | | `;` **IMM** | `( -- )` | Compiles `EXIT`, ends the definition, reveals the word, and returns to interpret mode. | | `CREATE` | `( "name" -- )` | Makes a header whose runtime pushes its data-field address (`HERE` aligned to a cell). It allocates **no** space, so follow it with `ALLOT` or `,`. | | `VARIABLE` | `( "name" -- )` | Makes a word that pushes the address of one newly allocated cell. | | `CONSTANT` | `( x "name" -- )` | Makes a word that pushes `x`. | | `DOES>` **IMM** | `( -- )` | Inside a defining word, ends the create part. Words later made by that defining word run the code after `DOES>` with their body address on the stack. | | `IMMEDIATE` **IMM** | `( -- )` | Marks the latest definition IMMEDIATE. | | `STATE` | `( -- addr )` | Pushes the address of the compile-state cell (0 means interpreting). | | `[` **IMM** | `( -- )` | Switches to interpret mode inside a definition. | | `]` **IMM** | `( -- )` | Switches to compile mode. | | `LITERAL` **IMM** | `( x -- )` | Compiles `x` so that it is pushed at runtime. Typical use: `[ 6 7 * ] LITERAL`. | | `LIT` | `( -- x )` | Runtime for literals: pushes the next inline cell. The compiler inserts it; you do not call it directly. | | `COMPILE` **IMM** | `( "name" -- )` | Legacy form: compiles a call to `name`. | | `[COMPILE]` **IMM** | `( "name" -- )` | Compiles `name` even when it is IMMEDIATE. | | `FORGET` | `( "name" -- )` | Removes `name` and every newer word and moves `HERE` back. Words below `FENCE` cannot be forgotten. | | `FENCE` | `( -- )` | Moves the `FORGET` boundary up to the current top of the dictionary. A capsule calls it after loading to protect its own words. | | `does_rt` | – | Internal `DOES>` helper that switches the new child word to DODOES. It is registered only so the threaded code can refer to it; do not call it. | Example: `: ARRAY ( n "name" -- ) CREATE CELLS ALLOT DOES> ( i -- addr ) SWAP CELLS + ;` ## 18. Control flow `src/word_source/control_words.c`. Every structure word is **IMM** and **CO**. Branch offsets are in bytes. Up to 64 structures can be nested at compile time (`CF_STACK_MAX`). | Word | Stack | Description | |---|---|---| | `IF` | `( flag -- )` | Runs the following code only if `flag` is non-zero. It compiles `(0BRANCH)`. | | `ELSE` | `( -- )` | Starts the code that runs when the `IF` flag was zero. | | `THEN` | `( -- )` | Ends an `IF` or `IF … ELSE` structure. | | `BEGIN` | `( -- )` | Marks the start of a loop. | | `UNTIL` | `( flag -- )` | Loops back to `BEGIN` while `flag` is zero. | | `AGAIN` | `( -- )` | Loops back to `BEGIN` unconditionally. Leave with `EXIT` or `ABORT`. | | `WHILE` | `( flag -- )` | In `BEGIN … WHILE … REPEAT`, leaves the loop when `flag` is zero. | | `REPEAT` | `( -- )` | Jumps back to `BEGIN` and resolves the exit of `WHILE`. | | `DO` | `( limit start -- ) ( R: -- limit index )` | Starts a counted loop that always runs at least once. | | `?DO` | `( limit start -- )` | Like `DO`, but skips the loop body when `start = limit`. | | `LOOP` | `( -- )` | Adds 1 to the index and loops while `index < limit`. | | `+LOOP` | `( n -- )` | Adds `n` to the index. For `n ≥ 0` it continues while `index < limit`; for `n < 0` it continues while `index ≥ limit`. | | `LEAVE` | `( -- )` | Exits the innermost `DO` loop immediately: it sets the index to the limit and jumps past `LOOP`. | | `I` | `( -- index )` | Pushes the index of the innermost loop. It is not IMMEDIATE. | | `J` | `( -- index )` | Pushes the index of the next outer loop. | | `UNLOOP` | `( -- ) ( R: limit index -- )` | Drops the loop parameters. Use it before `EXIT` inside a `DO` loop. | | `EXIT` | `( -- )` | Returns from the current colon definition. Using it in interpret mode is an error. | | `CASE` | `( x -- x )` | Starts a case structure. | | `OF` | `( x v -- \| x )` | If `x = v`, drops both and runs the clause; otherwise keeps `x` and skips to the next `OF`. | | `ENDOF` | `( -- )` | Ends an `OF` clause and jumps to `ENDCASE`. | | `ENDCASE` | `( x -- )` | Drops the selector and resolves every `ENDOF` jump. | | `(BRANCH)` | `( -- )` | Runtime: unconditional relative branch. The compiler inserts it; you do not call it directly. | | `(0BRANCH)` | `( flag -- )` | Runtime: branches when `flag` is 0. The compiler inserts it; you do not call it directly. | | `(DO)` `(?DO)` | `( limit start -- )` | Runtime for loop entry. The compiler inserts them; you do not call them directly. | | `(LOOP)` `(+LOOP)` | `( -- )` / `( n -- )` | Runtime for loop increment and test. The compiler inserts them; you do not call them directly. | | `(LEAVE)` | `( -- )` | Runtime for `LEAVE`: sets index to limit. The compiler inserts it; you do not call it directly. | Examples: ```forth : COUNTDOWN ( n -- ) BEGIN DUP . 1- DUP 0= UNTIL DROP ; : TABLE ( -- ) 5 0 DO 5 0 DO I J * 4 .R LOOP CR LOOP ; : COLOR ( n -- ) CASE 0 OF ." red" ENDOF 1 OF ." green" ENDOF ." ?" ENDCASE ; ``` ## 19. StarForth extensions `src/word_source/starforth_words.c`. These words are registered in both `FORTH` and the `STARFORTH` vocabulary. | Word | Stack | Description | |---|---|---| | `ENTROPY@` | `( xt -- n )` | Pushes the `execution_heat` counter of a word. The name says "entropy", but the value is execution heat. Registered only in the `STARFORTH` vocabulary. | | `ENTROPY!` | `( n xt -- )` | Sets a word's `execution_heat` counter. Registered only in the `STARFORTH` vocabulary. | | `WORD-ENTROPY` | `( -- )` | Prints the execution heat of every word. | | `RESET-ENTROPY` | `( -- )` | Sets every heat counter to zero. | | `TOP-WORDS` | `( n -- )` | Prints the `n` hottest words. | | `(-` | `( "ccc<)>" -- )` | A comment that marks metadata blocks to extract into `init.4th`. It consumes input up to `)`. | | `INIT` | `( -- )` | Reads `./capsules/core/init.4th`, copies its blocks from block 1 onward, and runs them. | | `VERSION` | `( -- )` | Prints `StarForth v `. | | `SEED` | `( n -- )` | Seeds the PRNG so random sequences can be reproduced. | | `RANDOM` | `( lo hi -- n )` | Pushes a pseudo-random number in `[lo, hi]`, including both ends. | | `WAIT` | `( n -- )` | Waits `n` heartbeat ticks by calling `vm_tick()` `n` times. It counts heartbeats, not wall-clock time, so it behaves the same on amd64, aarch64, and riscv64. | | `HEARTBEAT-TICKS@` | `( -- n )` | Pushes the canonical heartbeat tick count (Loop #7). The project uses this as its clock. It is read-only. | | `ZUSE-AUTHENTICATE` | `( -- )` | Sets `zuse_session = 1`. The write happens only in C. | | `ZUSE-SESSION?` | `( -- flag )` | True if `ZUSE-AUTHENTICATE` has run during this boot. It is read-only. | | `ZUSE-PUBKEY@` | `( i -- u )` | Pushes 8-byte little-endian chunk `i` (0–3) of Zuse's Ed25519 **public** key. An out-of-range `i` pushes 0 and sets an error. The private seed is never exposed. | | `ZUSE-CERT-INSTALLED?` | `( -- flag )` | True once the one-time certificate fuse has been blown. | ## 20. Word-level ACL `src/word_source/acl_words.c`. Every word takes an `xt`, obtained with `'` or `[']`. Writes are silently ignored for a **pinned** word. | Word | Stack | Description | |---|---|---| | `ACL-MODE@` | `( xt -- mode )` | Pushes the enforcement mode: 0 is STRICT (the decision is permanent) and 1 is TTL (the decision is rechecked when the countdown expires). | | `ACL-MODE!` | `( mode xt -- )` | Sets the enforcement mode. | | `ACL-TTL@` | `( xt -- n )` | Pushes the TTL countdown. At 0 in TTL mode, the interpreter calls `acl_recheck()`. | | `ACL-TTL!` | `( n xt -- )` | Sets the TTL, clamped to `[0, UINT32_MAX]`. | | `ACL-ALLOW@` | `( xt -- flag )` | Pushes the cached decision: `-1` means allowed and `0` means denied. | | `ACL-ALLOW!` | `( flag xt -- )` | Sets the cached decision; any non-zero value means allowed. | | `ACL-PINNED?` | `( xt -- flag )` | True if the ACL fields are pinned and therefore immutable. | | `ACL-PIN` | `( xt -- )` | Pins the word. **This is one-way**: no FORTH word can unpin it. | | `ACL-HEAT@` | `( xt -- heat )` | Pushes the execution heat. `ACL.4th` uses it to calibrate TTLs. | | `ACL-WORD-ID` | `( xt -- id )` | Pushes the word's stable `word_id`. It never changes, so it is safe to use as a table index. | | `ACL-INHERIT` | `( src-xt dst-xt -- )` | Copies the mode from `src` to `dst` and resets `dst`: unpinned, TTL 0, allowed. It is written in C because only C may clear a pin. | | `ACL-INIT-PRIMITIVES` | `( -- )` | For every unpinned word, sets TTL to 0, allow to 1, and mode to TTL. `ACL-BOOT` calls it. | ## 21. Physics: benchmark and diagnostics `src/word_source/physics_benchmark_words.c`. These are interactive diagnostics that print to the console. | Word | Stack | Description | |---|---|---| | `BENCH-DICT-LOOKUP` | `( iterations -- )` | Benchmarks dictionary lookup and records Q48.16 latencies. Use at least 10,000 iterations; 100,000 is the standard run and 1,000,000 is a stress test. | | `PHYSICS-CACHE-STATS` | `( -- )` | Prints hot-words cache statistics. | | `PHYSICS-TOGGLE-CACHE` | `( -- )` | Turns the hot-words cache on or off, for A/B testing. | | `PHYSICS-RESET-STATS` | `( -- )` | Resets the cache statistics. | | `PHYSICS-BUILD-INFO` | `( -- )` | Prints the variant's build configuration. | | `PHYSICS-BAYESIAN-REPORT` | `( addr -- )` | Prints a Bayesian comparison of the current cache statistics against the baseline stored at `addr`. | > `physics_diagnostic_words.c` also defines `PHYSICS-WORD-METRICS`, `PHYSICS-CALC-KNOBS`, `PHYSICS-BURN ( n -- )` > and `PHYSICS-SHOW-FEEDBACK`, but nothing calls `register_physics_diagnostic_words()`, so **none of them are in > the dictionary** at this commit. ## 22. Physics: pipelining diagnostics `src/word_source/physics_pipelining_diagnostic_words.c` | Word | Stack | Description | |---|---|---| | `PIPELINING-SHOW-STATS` | `( "name" -- )` | Prints the word-to-word transition metrics of `name`. | | `PIPELINING-SHOW-TOP-TRANSITIONS` | `( "name" n -- )` | Prints the `n` words that most often follow `name`. | | `PIPELINING-ANALYZE-WORD` | `( "name" -- )` | Prints a full analysis of one word's transitions, with hints for reading them. | | `PIPELINING-STATS` | `( -- )` | Prints pipelining statistics aggregated across the whole dictionary. | | `PIPELINING-RESET-ALL` | `( -- )` | Clears all transition metrics. | | `PIPELINING-ENABLE` | `( -- )` | Placeholder. Pipelining is switched on or off at compile time. | ## 23. Physics: freeze, heat, and decay `src/word_source/physics_freeze_words.c`. Words are named by `c-addr u` strings, for example `S" DUP" HEAT@`. An unknown name is not an error. | Word | Stack | Description | |---|---|---| | `FREEZE-WORD` | `( c-addr u -- )` | Sets `WORD_FROZEN` on the word, so Loop #3 decay stops lowering its heat. | | `UNFREEZE-WORD` | `( c-addr u -- )` | Clears `WORD_FROZEN` and leaves `WORD_PINNED` alone. | | `FROZEN?` | `( c-addr u -- flag )` | True if the word is frozen. An unknown word gives `0`. | | `HEAT!` | `( heat c-addr u -- )` | Writes `execution_heat` directly, bypassing Loops #1 and #3. For testing only. | | `HEAT@` | `( c-addr u -- heat )` | Reads `execution_heat`. An unknown word gives `0`. | | `SHOW-HEAT` | `( c-addr u -- )` | Prints `NAME: HEAT (frozen) (pinned)`. | | `ALL-HEATS` | `( -- )` | Prints up to 1024 words sorted by heat, hottest first. | | `DECAY-RATE@` | `( -- q )` | Pushes the base decay rate per µs (`DECAY_RATE_PER_US_Q16`) in Q48.16. | | `FREEZE-CRITICAL` | `( -- )` | Freezes 21 core words: `DUP DROP SWAP OVER ROT @ ! C@ C! EXECUTE IF THEN ELSE DO LOOP BEGIN UNTIL REPEAT . EMIT CR`. | ## 24. Dictionary heat optimisation `src/word_source/dictionary_heat_diagnostic_words.c` | Word | Stack | Description | |---|---|---| | `HEAT-PERCENTILES` | `( -- p25 p50 p75 )` | Pushes the current heat percentile thresholds, with the 75th on top. | | `LOOKUP-STRATEGY@` | `( -- n )` | Pushes the lookup strategy: 0 is naive (newest-first linear scan) and 1 is heat-aware (hot bucket first). | | `LOOKUP-STRATEGY!` | `( n -- )` | Sets the strategy. Only 0 or 1 is accepted; other values are silently ignored. | | `REORG-BUCKETS` | `( -- )` | Re-sorts the lookup buckets by heat and refreshes the percentiles immediately, without waiting for the heartbeat. | | `SHOW-HEAT-OPTIMIZATION` | `( -- )` | Prints the strategy, the percentiles, and the hot, warm, and cool zones. | | `COMPARE-LOOKUPS` | `( iterations -- )` | Benchmarks naive against heat-aware lookup and prints the speedup. It restores the original strategy afterwards. | ## 25. Logging `src/word_source/log_words.c` | Word | Stack | Description | |---|---|---| | `LOG-ERROR` `LOG-WARN` `LOG-INFO` `LOG-TEST` `LOG-DEBUG` | `( -- level )` | Push the log level constants. | | `LOG-LEVEL!` | `( level -- )` | Sets the active log filter, clamped to `[LOG-ERROR, LOG-DEBUG]`. | | `LOG-LEVEL@` | `( -- level )` | Pushes the current log level. | | `LOG-ERROR"` `LOG-WARN"` `LOG-INFO"` `LOG-TEST"` `LOG-DEBUG"` **IMM** | `( "ccc<">" -- )` | Log a literal string at that level. In interpret mode the string is logged immediately; when compiling, a runtime word and the inline string are compiled. | | `LOG-ERROR-STR` `LOG-WARN-STR` `LOG-INFO-STR` `LOG-TEST-STR` `LOG-DEBUG-STR` | `( c-addr u -- )` | Log a string taken from the stack at that level. | | `(do-log-error)` `(do-log-warn)` `(do-log-info)` `(do-log-test)` `(do-log-debug)` | `( -- )` | Runtimes for the compiled `LOG-*"` words. The compiler inserts them; you do not call them directly. | | `(LOG-APPEND-RAW)` **K** | `( level timestamp c-addr u -- )` | Appends a raw entry to the kernel log ring, attributed to the calling VM (or `HADES`). It reports errors on the console, not through `log_message`, to avoid recursion. | Example: `: CHECK ( n -- ) 0< IF LOG-WARN" negative input" THEN ;` ## 26. Q48.16 fixed-point math `src/word_source/q48_words.c`. A value is `n × 65536`. The underlying type is **unsigned** `uint64_t`; see [§36](#36-implementation-quirks-to-know) for what that means for negative values. | Word | Stack | Description | |---|---|---| | `Q.+` `Q.-` | `( q1 q2 -- q3 )` | Add and subtract. | | `Q.*` | `( q1 q2 -- q3 )` | Multiplies, computing `(a*b) >> 16`. | | `Q./` | `( q1 q2 -- q3 )` | Divides, computing `(a << 16) / b`. **Division by zero returns 0** and sets no error. | | `Q.ABS` | `( q -- \|q\| )` | Absolute value, treating the top bit as a sign bit. | | `Q.NEG` | `( q -- -q )` | Two's-complement negation. | | `Q.LOG` | `( q -- ln q )` | Natural logarithm by Newton-Raphson. Requires `q > 0`. | | `Q.EXP` | `( q -- e^q )` | Exponential by Taylor series. | | `Q.SQRT` | `( q -- √q )` | Square root by Newton-Raphson. | | `Q.SIN` `Q.COS` | `( q -- q' )` | Sine and cosine of an angle in radians. The argument is reduced to [-π, π] and then a Taylor series is applied. | | `Q.FROM-INT` | `( n -- q )` | Converts an integer to Q48.16 as `n << 16`. **A negative `n` becomes 0.** | | `Q.TO-INT` | `( q -- n )` | Converts to an integer as `q >> 16`, truncating. | | `Q.1` | `( -- 65536 )` | Pushes 1.0. | | `Q.0` | `( -- 0 )` | Pushes 0.0. | | `Q.SCALE` | `( -- 65536 )` | Pushes the scale factor; the same value as `Q.1`. | | `Q.=` | `( q1 q2 -- flag )` | Equality. | | `Q.<` `Q.>` | `( q1 q2 -- flag )` | Comparison, done **unsigned**. | | `Q.0=` | `( q -- flag )` | True if the value is zero. | | `Q.MAX` `Q.MIN` | `( q1 q2 -- q3 )` | Maximum and minimum, compared **unsigned**. | | `Q.PRINT` | `( q -- )` | Prints the value as `int.fffff ` with five fractional digits. | Example: `3 Q.FROM-INT Q.SQRT Q.PRINT` prints approximately `1.732`. ## 27. Inference engine (SSM, L8, and Bayes) `src/word_source/inference_words.c` | Word | Stack | Description | |---|---|---| | `INFER-RUN` | `( -- )` | Runs the full inference engine on this VM's rolling window and dictionary heat, and caches the results. | | `INFER-WINDOW@` | `( -- u )` | Pushes the last inferred optimal window width. | | `INFER-DECAY@` | `( -- q )` | Pushes the last inferred decay slope. | | `INFER-VARIANCE@` | `( -- q )` | Pushes the last inferred variance. | | `INFER-FIT@` | `( -- q )` | Pushes the last fit quality. | | `INFER-EARLY-EXIT@` | `( -- flag )` | True if the last run exited early. | | `Q.VARIANCE` | `( addr u -- q )` | Pushes the variance of `u` uint64 cells at `addr`. | | `INFER-DECAY-SLOPE` | `( addr u -- q )` | Fits a decay slope to the array by linear regression. | | `INFER-WINDOW-WIDTH` | `( addr u -- n )` | Computes the optimal window width for the array. | | `WINDOW-DIVERSITY` | `( -- u )` | Pushes the number of distinct words in the rolling window. | | `L8-MODE` | `( -- n )` | Pushes the current L8 (legacy 16-mode) Jacquard selection. | | `L8-UPDATE` | `( entropy cv temporal stability -- )` | Feeds four Q48.16 metrics to `ssm_l8_update()`. `stability` is on top of the stack. | | `L8-APPLY` | `( -- )` | Applies the currently selected L8 mode. | | `L8-TABLE-FORCE` | `( idx -- )` | Forces the adaptive 128-config table to `idx & 127` as though the UCB bandit had picked it, and applies it. Unlike `L8-UPDATE` and `L8-APPLY`, this choice is not overwritten at the next heartbeat trial. Use it for DoE campaigns. | | `BAYES-CACHE-MEAN` `BAYES-CACHE-LOWER` `BAYES-CACHE-UPPER` | `( -- q )` | Push the posterior mean latency and the 95 % credible bounds for hot-words cache hits. | | `BAYES-BUCKET-MEAN` `BAYES-BUCKET-LOWER` `BAYES-BUCKET-UPPER` | `( -- q )` | Push the same three values for bucket searches. | ## 28. DEFER and IS `src/word_source/defer_words.c` | Word | Stack | Description | |---|---|---| | `DEFER` | `( "name" -- )` | Creates a vectored word. Running it before an action has been set with `IS` sets `vm->error`. | | `IS` | `( xt "name" -- )` | Sets the action of `name`. It is refused unless `name` was created by `DEFER`. | | `DEFER@` | `( "name" -- xt )` | Pushes the current action of a deferred word. | Example: `DEFER GREET : HI ." hi" ; ' HI IS GREET GREET` ## 29. Framebuffer (Hestia only) `src/word_source/framebuffer_words.c`. These words are registered only in the Hestia VM, by `capsule_birth_baby()`, and not by `register_forth79_words()`. | Word | Stack | Description | |---|---|---| | `PLOT` | `( x y color -- )` | Writes one raw pixel. The origin is top-left and Y increases downward. | | `FB-WIDTH` | `( -- n )` | Pushes the framebuffer width in pixels. | | `FB-HEIGHT` | `( -- n )` | Pushes the framebuffer height in pixels. | ## 30. Keyboard `src/word_source/keyboard_words.c`. These are diagnostics for the console fabric. On a platform without the device, each word pushes `0`. | Word | Stack | Description | |---|---|---| | `KBD-SCAN` | `( -- sc -1 \| 0 )` | amd64 i8042: pops one raw XT scancode from the queue, if there is one. | | `KBD-DEBUG` | `( -- isr spurious )` | amd64: pushes the i8042 interrupt count and the spurious-interrupt count. | | `VKBD-EVENT` | `( -- code value -1 \| 0 )` | riscv64 and aarch64 virtio-input: pops one Linux-style `EV_KEY` code and value. | | `VKBD-DEBUG` | `( -- isr )` | riscv64 and aarch64: pushes the virtio-input interrupt count. | | `KEY-EVENT` | `( -- keycode pressed -1 \| 0 )` | The unified event on every architecture: pops one keycode with its pressed (1) or released (0) state. | | `ALT+TAB` | `( -- )` | Switches the console between text and graphics, the same as the physical Alt+Tab. | ## 31. TrueType text `src/word_source/ttf_words.c` | Word | Stack | Description | |---|---|---| | `TTF-TEXT` **K** | `( c-addr u x y size color -- )` | Draws the string with the TrueType renderer at pixel `(x, y)` in the given size and color. | ## 32. REPL scrollback `src/word_source/scroll_words.c` | Word | Stack | Description | |---|---|---| | `SCROLL-BACK` **K** | `( n -- )` | Scrolls the REPL view back `n` lines. | | `SCROLL-FWD` **K** | `( n -- )` | Scrolls the REPL view forward `n` lines, toward the live output. | ## 33. Kernel REPL and DoE hooks `src/starkernel/repl.c` and `src/starkernel/doe_log.c` | Word | Stack | Description | |---|---|---| | `HB-ON` **K** | `( -- )` | Turns on per-tick DoE instrumentation. | | `HB-OFF` **K** | `( -- )` | Turns off per-tick DoE instrumentation. | | `BLK-ATTACH-ACK` **K** | `( dev-ptr ok? -- )` | The acknowledgement Artemis sends to Hera after `BLK-ATTACH`, delivered with `VM-EXEC`. On success, Hera runs the deferred Zuse or WIREBIND attach. | | `KH-BLK-ATTACH-SEND` **K** | `( c-addr u -- ok? )` | Sends a payload to Hera through kernel-Hermes. The sender and receiver are worked out in C, so the caller cannot spoof them. A refused send is logged. | | `KH-ELEVATE-SEND` **K** | `( c-addr u -- ok? )` | The same mechanism for elevation requests. Nothing calls it at present. | ## 34. Hera (Mama) and child-VM words `src/starkernel/capsule/mama_forth_words.c`. These are **K** only. Hera receives every word in this section, in both `FORTH` and the `MAMA` vocabulary. Child VMs receive only `STOP EXEC USE BIRTH CAPSULE-BIRTH VM-EXEC VM-CALL VM-HEAT VM-ERROR? SWITCH-MARK-WORK` and the `STADIUM-*` words. VM names are matched without regard to case. ### VM lifecycle | Word | Stack | Description | |---|---|---| | `BIRTH` | `( c-addr u -- )` | Births a VM from its capsule (`S" Artemis"` loads `artemis:init.4th`). If the VM is already live, nothing happens. `Hera` is rejected. | | `KILL` | `( c-addr u -- )` | Destroys a VM. Hera cannot be killed, and killing a dead VM does nothing. | | `START` | `( c-addr u -- )` | Enters the VM's REPL and blocks until it runs `STOP` or `BYE`. It refuses a VM that is LIVE, DEAD, or STILLBORN. | | `STOP` | `( -- )` | Halts the current VM, so its REPL loop returns. | | `USE` | `( c-addr u -- )` | Redirects console input to the named VM without nesting the C stack, and changes the prompt to `[Name]`. `S" Hera" USE` switches back to Hera. | | `EXEC` | `( c-addr u -- )` | Runs a named capsule inside the current VM. | | `EJECT` | `( -- )` | Cleanly detaches the identity attached through USB home blocks: it flushes the user VM and kills it, or logs Zuse out. | | `CONNECT-HERMES` | `( -- )` | Enters Hermes's REPL, birthing Hermes first if needed. | | `CONNECT-ARTEMIS` | `( -- )` | Enters Artemis's REPL, birthing Artemis first if needed. | | `BYE` | `( -- )` | **On Hera:** reaps every child and then cold-resets the machine. | ### Cross-VM execution (compudynamics) | Word | Stack | Description | |---|---|---| | `VM-EXEC` | `( cmd-a cmd-u name-a name-u -- )` | Injects a command into the named VM and runs it immediately without blocking. Example: `S" DOE-WORK" S" Hermes" VM-EXEC`. | | `VM-CALL` | `( cmd-a cmd-u name-a name-u -- n )` | Like `VM-EXEC`, then pops the target's top of stack onto the caller's stack. If the target left nothing, it pushes 0 and sets an error. | | `VM-STEP` | `( c-addr u -- )` | Gives the named VM one REPL turn: one prompt, one line, then it returns. | | `VM-HEAT` | `( c-addr u -- q )` | Pushes the VM's `execution_heat_q48`. An unknown VM gives 0 and prints nothing. | | `VM-ERROR?` | `( c-addr u -- flag )` | True if the VM has `vm->error` set. An unknown VM gives `0`. | | `VM-COUNT` | `( -- n )` | Pushes the number of registered VMs. | | `VM-CONSERVED?` | `( -- flag )` | True if the total fleet heat is within ε of `Q.1`. | | `VM-PHYSICS-STATUS` | `( -- )` | Prints the fleet physics report. | | `SWITCH-MARK-WORK` | `( c-addr u -- )` | Marks a VM as having work, which makes it eligible for a context switch. The message path calls it, and it ignores bad names silently. | | `MAMA-VM-ID` | `( -- 0 0 )` | Pushes Hera's 128-bit VM ID, which is all zeros. | | `NAME>XT` | `( c-addr u -- xt \| 0 )` | Looks up a name held in a data buffer. A miss gives `0`. | ### Capsules | Word | Stack | Description | |---|---|---| | `CAPSULE-COUNT` | `( -- n )` | Pushes the number of entries in the capsule directory. | | `CAPSULE@` | `( idx -- desc \| 0 )` | Pushes the descriptor for the capsule at `idx`. | | `CAPSULE-HASH@` | `( desc -- hash )` | Pushes the capsule's content hash. | | `CAPSULE-FLAGS@` | `( desc -- flags )` | Pushes the capsule's flags. | | `CAPSULE-LEN@` | `( desc -- len )` | Pushes the capsule's payload length. | | `CAPSULE-BIRTH` | `( id -- vmid-lo vmid-hi )` | Births an unnamed VM from a production (p) capsule and pushes its 128-bit ID. On failure both cells are all ones. | | `CAPSULE-RUN` | `( id -- )` | Runs an experiment (e) capsule on Hera. | | `CAPSULE-TEST` | `( -- )` | Prints a message confirming the capsule system is running. | | `WORKER-BIRTH` | `( cap-a cap-u name-a name-u -- ok? )` | Births a named, `VM-EXEC`-addressable worker from any p-capsule, with no identity attached. | | `UNATTENDED-BIRTH` | `( cap-a cap-u name-a name-u -- ok? )` | Births a VM and installs the verified identity whose `UNATTENDED-ID-UUID` and `UNATTENDED-ID-CERT` the capsule defined. | | `CONSOLE-ATTACH` | `( name-a name-u -- ok? )` | Pairs a new console VM with the live VM registered as `~user`. | ### Identity, Zuse, and diagnostics | Word | Stack | Description | |---|---|---| | `MINT` | `( fn-a fn-u un-a un-u em-a em-u ph-a ph-u restrict? -- ok? )` | Mints an identity onto the attached USB drive. The full name and username are required; pass an empty string for email or phone to leave them out. A non-zero `restrict?` selects the locked-down personality that allows only FORTH-79 and FORTH-83 words. | | `MINT-SCRATCH` | same as `MINT` | Mints onto the scratch device instead, prints the UUID, and pushes 1 or 0. | | `MINT-SCRATCH-EMIT` | `( -- ok? )` | Prints the last scratch mint as FORTH source (`CREATE UNATTENDED-ID-UUID` / `-CERT` byte lists) for copying by hand. It refuses (pushes 0) if no mint has succeeded. | | `ZUSE-ELIGIBILITY-ADD` | `( c-addr -- ok? )` | Adds the 32-byte Ed25519 public key at `c-addr` to Zuse's elevation list. | | `ZUSE-ELIGIBLE?` | `( c-addr -- flag )` | Checks whether a key is on the list. It fails closed. | | `ELEVATE-PUBKEY-UNPACK` | `( pk0 pk1 pk2 pk3 buf -- )` | Rebuilds a 32-byte public key from four cells. It is the inverse of `ZUSE-PUBKEY@`. | | `RUNCAP-TEST` | `( c-addr u -- ok? rc )` | Diagnostic: runs `capsule_runcap_birth()` against the current home-blocks drive. | | `PAIR-TEST` | `( c-addr u -- ok? )` | Diagnostic: births a console VM and a `~user` VM as a pair. | ### Stadium (heat accounting) Heat values are Q48.16. Each word works only on the calling VM's own quota. | Word | Stack | Description | |---|---|---| | `STADIUM-ADMIT` | `( identity heat behaviour -- cell \| -1 )` | Admits a patron. `behaviour` must be 0–3. | | `STADIUM-EVICT` | `( cell -- flag )` | Reaps the patron in `cell`. It is refused if the cell is out of range, not resident, pinned, or blocked by what it contains. | | `STADIUM-HEAT@` | `( cell -- heat )` | Reads a resident cell's heat. A cell that is not the caller's gives 0. | | `STADIUM-HEAT!` | `( heat cell -- )` | Writes a cell's heat, pulling the difference from the reservoir or pushing it back. An increase the reservoir cannot cover is silently refused. | | `STADIUM-RES@` | `( -- heat )` | Pushes the VM's reservoir balance. | | `STADIUM-RES-PULL` | `( qty -- got )` | Pulls up to `qty` from the reservoir and pushes the amount actually taken. | | `STADIUM-RES-PUSH` | `( heat -- )` | Credits heat back to the reservoir. | | `STADIUM-WORD-HEAT` | `( -- heat )` | Pushes the total heat held by this VM's word-execution residents. | ## 35. Hosted lifecycle stubs `src/word_source/lifecycle_words_hosted.c`. These are **H** only; `main.c` registers them. Each word only logs `" (hosted)"`. They exist so that capsule scripts also parse in hosted builds. | Word | Stack | Description | |---|---|---| | `BIRTH` `KILL` `PAUSE` `RESUME` `USE` | `( c-addr u -- )` | No-op stubs that only write a log line. | --- ## 36. Implementation quirks to know These behaviours differ from what a FORTH-79 or ANS programmer would expect. Each was checked against the C source. 1. **`ROLL` counts from the bottom of the stack.** With `1 2 3` on the stack, `1 ROLL` gives `2 3 1`; ANS gives `1 3 2`. The test suite (`stack_words_test.c`) asserts the current behaviour, so it looks intended. Portable code should use `SWAP` and `ROT`. 2. **`PICK` is 0-based,** as in ANS. FORTH-79's `PICK` was 1-based. 3. **`FIND` parses the input stream.** It does not take a counted string. Use `(FIND)` for a counted string or `NAME>XT` (kernel only) for a name in a buffer. 4. **The Q48.16 type is unsigned.** `Q.<`, `Q.>`, `Q.MIN`, `Q.MAX` and `Q.PRINT` treat a negative Q value as a huge positive one, and `Q.FROM-INT` turns a negative integer into 0. `Q.ABS` and `Q.NEG` do treat the top bit as a sign. 5. **`Q./` by zero returns 0 without setting an error,** while the integer `/`, `MOD`, and `*/` all set `vm->error`. 6. **`[LITERAL]` does nothing,** and `LITERAL` works only because §17 registers it again after the placeholder. 7. **`MOD`, `/MOD`, `*/`, and `*/MOD` are registered twice.** The mixed-arithmetic versions (§6) are the ones used. 8. **Four `PHYSICS-*` diagnostic words are not registered.** `PHYSICS-WORD-METRICS`, `PHYSICS-CALC-KNOBS`, `PHYSICS-BURN` and `PHYSICS-SHOW-FEEDBACK` are defined in C but never added to the dictionary. 9. **`does_rt` is a visible dictionary entry.** It is an internal helper; do not call it. 10. **The `STARFORTH` vocabulary registers its words twice** (once in `FORTH`, once in `STARFORTH`). Hera does the same with `MAMA`. As a result, those names appear twice in `WORDS` output.