SM/REM as written in section 4 never returned correctly for a negative dividend. It holds three entries on the return stack and then calls DABS -> DNEGATE -> D+ -> U> -> SWAP/U<, which overflows the 9-deep circular return stack (D-2). DABS itself could not run: DNEGATE as written (inv SWAP inv SWAP 1 0 D+) left its caller no return entries. - DNEGATE: inv over if L1 drop push inv 1 + pop ; L1: drop 1 + ; i.e. ~d + 1, carrying into the high cell exactly when lo = 0. - SM/REM: sign tests are native -if (as in 0<) and NEGATE is in line; the only calls are DNEGATE and UM/MOD, both call-free inside. Executed on the golden model at 32- and 64-bit cells, optimised and under ASan+UBSan: - SM/REM on dividends built as q*n + r with |r| < |n| and r signed as d: every edge-vector q, n with r = 0 and r = +-(|n|-1), plus 20000 pseudo-random cases. - /MOD, U>, ABS, S>D, D+ and DABS as written in section 5, against C (D+ over all 50625 edge-vector quadruples). Mutations of DNEGATE's carry and of each SM/REM sign branch are caught. Headroom (data cells under args / return entries under return address): SM/REM 5/3, /MOD 5/2, DNEGATE 7/7, DABS 7/6, ABS 8/7, U> 6/5. D+ as written is exact but leaves only 1 return entry; recorded in DECOMPOSITION.md 5.7 as not yet revised. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
757 lines
34 KiB
Markdown
757 lines
34 KiB
Markdown
# StarForth v4.0.0 — Primitive Decomposition
|
||
|
||
This document assigns every C primitive in StarForth v3 (`admin/LithosAnanake` at `6302dcb`) a fate in
|
||
StarForth v4.0.0. v4 is built on a 32-instruction core derived from Chuck Moore's F18 (the GA144 node).
|
||
Everything that is not one of those 32 instructions becomes capsule code, a service message to another
|
||
node, a memory-mapped register, or is retired.
|
||
|
||
The rationale is in `JUSTIFICATION.md`. This document is the specification.
|
||
|
||
**Status.** Every colon definition below is written against the ISA in §1 and has been traced by hand,
|
||
but none has been executed. Each one becomes a POST test target: it is correct when the hosted v4 golden
|
||
model produces the same results as the v3 C primitive it replaces.
|
||
|
||
---
|
||
|
||
## Contents
|
||
|
||
0. [Fates](#0-fates)
|
||
1. [The v4 core ISA](#1-the-v4-core-isa)
|
||
2. [Compiler conventions](#2-compiler-conventions)
|
||
3. [Decisions](#3-decisions)
|
||
4. [Foundation layer (new words)](#4-foundation-layer-new-words)
|
||
5. [Fate of every v3 primitive](#5-fate-of-every-v3-primitive)
|
||
6. [Messaging between nodes](#6-messaging-between-nodes)
|
||
7. [Memory-mapped registers](#7-memory-mapped-registers)
|
||
|
||
---
|
||
|
||
## 0. Fates
|
||
|
||
| Code | Fate | Meaning |
|
||
| --- | --- | --- |
|
||
| **OP** | Instruction | One of the 32 core opcodes. |
|
||
| **IN** | Inline macro | A short opcode sequence the compiler places in-line. Never called. Required for anything that touches the return stack, since a call would bury the return address. |
|
||
| **CAP** | Core capsule | A colon definition in the core capsule, built only from OP, IN, and earlier CAP words. |
|
||
| **CC** | Compiler capsule | Part of the compiler/interpreter capsule, which runs on the host node only. Mesh nodes receive compiled code. |
|
||
| **DEV** | Device service | A message to a device node that owns real hardware (console, storage, display, keyboard, log). |
|
||
| **HERA** | Hera service | A message to the Hera node, which owns lifecycle, identity, capsules, ACLs, and Stadium admission. |
|
||
| **MM** | Memory-mapped | An `@` or `!` against a hardware register (heat counters, anti-clock, governor, stack pointer). |
|
||
| **RET** | Retired | A diagnostic of v3's software machine that has no equivalent in v4. |
|
||
|
||
---
|
||
|
||
## 1. The v4 core ISA
|
||
|
||
### 1.1 Machine model
|
||
|
||
| Item | v4 node |
|
||
| --- | --- |
|
||
| Cell | 32 bits (mesh node). The host node's width is a build parameter; see D-5. |
|
||
| Addressing | Word-addressed (D-1). |
|
||
| Registers | `T` (top of data stack), `S` (second), `R` (top of return stack), `P` (program counter), `A` and `B` (address registers). |
|
||
| Stacks | F18 circular hardware stacks, not visible to code (D-2): data stack `T`, `S` + 8 circular (10 deep), return stack `R` + 8 circular (9 deep). No overflow or underflow; pushing past the bottom silently overwrites the oldest entry. |
|
||
| Instruction word | Six 5-bit slots, plus 2 spare bits. |
|
||
|
||
### 1.2 Instruction word layout
|
||
|
||
```
|
||
31 27 26 22 21 17 16 12 11 7 6 2 1 0
|
||
+--------+--------+--------+--------+--------+--------+----+
|
||
| slot 0 | slot 1 | slot 2 | slot 3 | slot 4 | slot 5 | xx |
|
||
+--------+--------+--------+--------+--------+--------+----+
|
||
```
|
||
|
||
Slots execute left to right. A branch (`jump`, `call`, `next`, `if`, `-if`) takes its target from all
|
||
bits to the right of its slot, and that target replaces the same low bits of `P` (page-relative, as in
|
||
the F18). Branches are therefore legal in slots 0–3 only:
|
||
|
||
| Branch in slot | Address bits | Reach |
|
||
| --- | --- | --- |
|
||
| 0 | 27 | whole address space |
|
||
| 1 | 22 | 4M words |
|
||
| 2 | 17 | 128K words |
|
||
| 3 | 12 | 4K words (node-local) |
|
||
|
||
### 1.3 The 32 opcodes
|
||
|
||
Opcode numbering follows the F18. Two names differ from Moore's: F18 `-` is renamed `inv` and F18 `or`
|
||
(which is exclusive-or) is renamed `xor`, so instruction names never collide with FORTH-79 word names.
|
||
|
||
| Op | Name | Effect |
|
||
| --- | --- | --- |
|
||
| 00 | `;` | Return: `P ← R`, pop `R`. |
|
||
| 01 | `ex` | Swap `P` and `R` (co-routine / execute). |
|
||
| 02 | `jump a` | `P ← a`. |
|
||
| 03 | `call a` | Push `P` to `R`, `P ← a`. |
|
||
| 04 | `unext` | If `R ≠ 0`: decrement `R`, restart the current instruction word at slot 0. Else pop `R`. |
|
||
| 05 | `next a` | If `R ≠ 0`: decrement `R`, `P ← a`. Else pop `R`. |
|
||
| 06 | `if a` | If `T = 0`: `P ← a`. **Does not pop `T`.** |
|
||
| 07 | `-if a` | If `T ≥ 0` (sign bit clear): `P ← a`. **Does not pop `T`.** |
|
||
| 08 | `@p` | Push the word at `P`, `P ← P+1` (literal). |
|
||
| 09 | `@+` | Push the word at `A`, `A ← A+1`. |
|
||
| 0A | `@b` | Push the word at `B`. |
|
||
| 0B | `@` | Push the word at `A`. |
|
||
| 0C | `!p` | Store `T` at `P`, pop, `P ← P+1`. |
|
||
| 0D | `!+` | Store `T` at `A`, pop, `A ← A+1`. |
|
||
| 0E | `!b` | Store `T` at `B`, pop. |
|
||
| 0F | `!` | Store `T` at `A`, pop. |
|
||
| 10 | `+*` | Multiply step: if bit 0 of `A` is set, `T ← T+S`; then shift `T:A` right one bit. See D-3. |
|
||
| 11 | `2*` | `T ← T << 1`. |
|
||
| 12 | `2/` | `T ← T >> 1`, arithmetic. |
|
||
| 13 | `inv` | `T ← ~T`. |
|
||
| 14 | `+` | `T ← S + T`, pop. |
|
||
| 15 | `and` | `T ← S & T`, pop. |
|
||
| 16 | `xor` | `T ← S ^ T`, pop. |
|
||
| 17 | `drop` | Pop `T`. |
|
||
| 18 | `dup` | Push a copy of `T`. |
|
||
| 19 | `pop` | Pop `R` onto the data stack. |
|
||
| 1A | `over` | Push a copy of `S`. |
|
||
| 1B | `a` | Push `A`. |
|
||
| 1C | `nop` | Nothing. |
|
||
| 1D | `push` | Pop `T` onto the return stack. |
|
||
| 1E | `b!` | `B ← T`, pop. |
|
||
| 1F | `a!` | `A ← T`, pop. |
|
||
|
||
Note that `@` and `!` address through `A`, not through `T`. The FORTH words `@` and `!` therefore become
|
||
`a! @` and `a! !`.
|
||
|
||
### 1.4 Side effects that are not instructions
|
||
|
||
Execution itself drives the physics. Every retired instruction increments that opcode's heat counter and
|
||
advances the anti-clock; every `call` increments the heat counter of its target. None of this costs an
|
||
instruction. Capsule code reads it through the memory-mapped registers in §7.
|
||
|
||
---
|
||
|
||
## 2. Compiler conventions
|
||
|
||
**Literals.** A number in source compiles to `@p` followed by the value in the next word.
|
||
|
||
**Capsule `IF`.** Native `if` and `-if` leave the flag on the stack. The capsule-level `IF` consumes it,
|
||
so the compiler drops it on both paths:
|
||
|
||
```
|
||
IF body THEN → if L1 drop body jump L2
|
||
L1: drop
|
||
L2:
|
||
|
||
IF body1 ELSE body2 THEN → if L1 drop body1 jump L2
|
||
L1: drop body2
|
||
L2:
|
||
```
|
||
|
||
`BEGIN ... WHILE ... REPEAT` and `BEGIN ... UNTIL` expand the same way.
|
||
|
||
**`FOR ... NEXT`.** `n FOR ... NEXT` compiles `push` then the body then `next`. The body runs `n+1`
|
||
times, as on the F18. `FOR ... UNEXT` is the same but the body must fit in one instruction word.
|
||
|
||
**Register conventions.** `A` and `B` are caller-saved. A word that uses them says so. Words in this
|
||
document that clobber `A`: `@ ! +! -! 2@ 2! C@ C! UM* * UM/MOD SEND RECV`. Words that clobber `B`:
|
||
`SEND RECV`.
|
||
|
||
**Return-stack words** (`>R R> R@ 2>R 2R> 2R@ I J UNLOOP` and the loop runtimes) are always IN.
|
||
|
||
---
|
||
|
||
## 3. Decisions
|
||
|
||
Ruled by Captain Bob, 2026-10-01, except D-4 and D-6, which are deferred to development step 2 (the
|
||
hosted mesh, `JUSTIFICATION.md` §10) because only the mesh and the RTL depend on them. Where a
|
||
definition below depends on one, it says so.
|
||
|
||
| ID | Decision | Ruling |
|
||
| --- | --- | --- |
|
||
| **D-1** | Word addressing (pure Moore) or byte addressing. | **Word addressing.** `C@`/`C!` are CAP; `CELLS` is a no-op. |
|
||
| **D-2** | Stack depth, and whether the stacks are visible. | **F18 circular stacks, hidden.** Data stack 10 deep (`T`, `S` + 8 circular), return stack 9 deep (`R` + 8 circular), exactly as the F18. No stack pointer is visible to code, so `DEPTH`, `PICK`, `ROLL`, `.S`, `SP@` and `SP!` are **retired everywhere**, host node included. |
|
||
| **D-3** | Exact `+*` semantics at 32 bits: whether the add carries out of `T` into the shift. | **Plain F18 semantics.** The carry out of `T` is not kept. `UM*` in §4 is written for this and is exact over the full range (revised and proven on the golden model, 2026-10-02). |
|
||
| **D-4** | Node memory map, including port and register addresses. | **Deferred** to step 2. Symbolic names only for now (§6, §7). |
|
||
| **D-5** | Host node cell width. | **Match the host CPU:** 32 on a Zynq-7000 (Cortex-A9), 64 on an aarch64 host. The compiler capsule is written width-independent. |
|
||
| **D-6** | Which heat structures exist in hardware: per-opcode counters only, or also per-call-target and word-to-word transition counters. | **Deferred** to step 2. The golden model implements per-opcode and per-call-target heat in the meantime. |
|
||
| **D-7** | `ROLL` semantics. | **Moot.** `ROLL` is retired under D-2. |
|
||
| **D-8** | Q48.16 signedness. | **Signed.** v3's unsigned comparisons and `Q.FROM-INT` clamping are retired. |
|
||
| **D-9** | Instruction word width on a 64-bit-cell host (ruled 2026-10-02). | **32 bits at every cell width.** Six 5-bit slots plus 2 spare bits, as in §1.2. On a 64-bit host the instruction word is the low 32 bits of the cell and the high half is ignored, so compiled code is identical at both widths. Only data and `@p` literals are a full cell wide. |
|
||
|
||
**Consequences of D-2 that every definition must respect.** The data stack holds 10 items and the
|
||
return stack 9, and every `call`, `FOR`, `DO` loop frame and `push` uses return-stack slots. Nesting
|
||
is therefore shallow, and exceeding either depth corrupts silently rather than faulting. Every CAP
|
||
definition in §4 and §5 must be re-checked against these limits before it is accepted as a POST
|
||
target; the hand traces so far assumed unbounded stacks.
|
||
|
||
---
|
||
|
||
## 4. Foundation layer (new words)
|
||
|
||
These words do not exist as primitives in v3 but everything else is built on them. They are listed in
|
||
dependency order.
|
||
|
||
```forth
|
||
\ ---- helpers ------------------------------------------------------------
|
||
: NIP ( a b -- b ) push drop pop ;
|
||
: SWAP ( a b -- b a ) over push push drop pop pop ;
|
||
: OR ( a b -- a|b ) over inv and xor ;
|
||
: NEGATE ( n -- -n ) inv 1 + ;
|
||
: ROT ( a b c -- b c a ) push SWAP pop SWAP ;
|
||
|
||
\ ---- sign and zero tests (raw branches, labels shown) ------------------
|
||
: 0< ( n -- flag ) -if L1 drop -1 ; L1: drop 0 ;
|
||
: 0= ( n -- flag ) if L1 drop 0 ; L1: drop -1 ;
|
||
|
||
\ ---- unsigned compare ---------------------------------------------------
|
||
: U< ( u1 u2 -- flag ) 2DUP xor 0< IF NIP 0< ELSE - 0< THEN ;
|
||
|
||
\ ---- multiply (D-3) -----------------------------------------------------
|
||
\ Plain F18 +* loses the carry out of T, and its shift keeps T's sign bit, so
|
||
\ the loop is exact only while the multiplicand in S and the running T both
|
||
\ lie in [-2^(n-2), 2^(n-2)). UM* therefore multiplies by s = u1 2/, which
|
||
\ always does, starting T at t0 = u2 2/ when u1 is odd, and gets
|
||
\ hi:lo = t0 + s*u2. Then u1*u2 = 2*(hi:lo) + c_lo + c_hi*2^n, where
|
||
\ c_lo = u1 & u2 & 1
|
||
\ c_hi = (u1<0 ? u2 : 0) + (u1 odd and u2<0 ? 1 : 0)
|
||
\ restore the bits the two halvings dropped and the unsigned reading of
|
||
\ both top bits. Exact over the full range; proven on the golden model.
|
||
: UM* ( u1 u2 -- ulo uhi )
|
||
over 0< over and push \ R: u1<0 ? u2 : 0
|
||
over over 0< and 1 and pop + push \ R: c_hi
|
||
over over and 1 and push \ R: c_hi c_lo
|
||
over 1 and NEGATE over 2/ and push \ R: c_hi c_lo t0
|
||
a! 2/ pop \ s t0 A: u2
|
||
31 FOR +* UNEXT \ s hi A: lo
|
||
NIP a 2* pop + SWAP \ lo' hi
|
||
2* a 0< NEGATE + pop + ; \ lo' hi'
|
||
|
||
\ ---- divide: 32-step restoring division, divisor held in A --------------
|
||
\ Each step shifts hi:lo left one bit and, when the shifted-out bit of hi was
|
||
\ set or hi' >= d, subtracts d from hi' and sets the new low bit of lo. The
|
||
\ unsigned compare is done by sign tests in line (as U< does), and x - d is
|
||
\ `inv a + inv`, so the loop body makes no calls: it needs one return-stack
|
||
\ entry beyond its own count.
|
||
: UM/MOD ( ulo uhi ud -- urem uquot )
|
||
a! 31 FOR
|
||
-if L0 \ hi's top bit set:
|
||
2* over -if L1 drop 1 + jump L2 \ hi' = 2hi + top bit of lo
|
||
L1: drop L2: push 2* pop \ lo' = 2lo
|
||
jump SUB \ true hi' >= 2^n > d
|
||
L0:
|
||
2* over -if L3 drop 1 + jump L4
|
||
L3: drop L4: push 2* pop
|
||
dup a xor -if L5 \ top bits of hi' and d differ:
|
||
drop -if NOSUB jump SUB \ hi' >= d iff hi' has it
|
||
L5: drop dup inv a + inv -if L6 \ same: hi' >= d iff hi'-d >= 0
|
||
drop jump NOSUB
|
||
L6: push drop pop jump SETBIT
|
||
SUB: inv a + inv \ hi' - d
|
||
SETBIT: push 1 + pop \ lo' is even: + 1 sets bit 0
|
||
NOSUB:
|
||
NEXT
|
||
over push push drop pop pop ; \ SWAP in line
|
||
\ Executed on the golden model (2026-10-02): exact, q*d + r = uhi:ulo with
|
||
\ r < d, for every uhi < ud at 32- and 64-bit cells. Outside that range
|
||
\ (uhi >= ud, including ud = 0) the result is unspecified, as in FORTH-79; it
|
||
\ always terminates after 32 steps. Stack use (D-2): up to 6 data cells may
|
||
\ lie under the three arguments and up to 6 return-stack entries under its
|
||
\ return address. For UM* the same limits are 6 and 4. This replaces a
|
||
\ first version built on U<, 0<, SWAP and OR calls, which was also exact but
|
||
\ left only 3 and 3 (too few for SM/REM inside /MOD) and stepped about five
|
||
\ times as many instruction words.
|
||
|
||
\ ---- signed division, truncating toward zero (v3 semantics) -------------
|
||
\ The quotient takes the sign of d xor n, the remainder the sign of d. Sign
|
||
\ tests are native -if (as in 0<) and NEGATE is in line, so the only calls
|
||
\ are DNEGATE and UM/MOD, both call-free inside.
|
||
: SM/REM ( d n -- rem quot )
|
||
over over xor push \ R: quotient sign (top bit)
|
||
over push \ R: + remainder sign (top bit of d)
|
||
-if L0 inv 1 + L0: push \ R: + |n|
|
||
-if L1 DNEGATE L1: \ |d|
|
||
pop UM/MOD \ urem uquot
|
||
pop -if L2 drop push inv 1 + pop jump L3 L2: drop L3:
|
||
pop -if L4 drop inv 1 + ; L4: drop ;
|
||
\ Executed on the golden model (2026-10-02): exact whenever the truncated
|
||
\ quotient fits a signed cell, at 32- and 64-bit cells. Stack use (D-2): up
|
||
\ to 5 data cells under the three arguments and 3 return-stack entries under
|
||
\ its return address; /MOD, one call further out, leaves 2. The first
|
||
\ version, built on ABS, DABS, 0< and NEGATE calls, overflowed the return
|
||
\ stack inside DABS -> DNEGATE -> D+ -> U> and never returned correctly for
|
||
\ a negative dividend.
|
||
```
|
||
|
||
`2DUP`, `-`, and `DNEGATE` are defined in §5; the compiler resolves forward references within the
|
||
core capsule.
|
||
|
||
---
|
||
|
||
## 5. Fate of every v3 primitive
|
||
|
||
Section numbers match the v3 primitive reference.
|
||
|
||
### 5.1 Stack
|
||
|
||
| Word | Fate | v4 definition / notes |
|
||
| --- | --- | --- |
|
||
| `DROP` | OP | `drop` |
|
||
| `DUP` | OP | `dup` |
|
||
| `OVER` | OP | `over` |
|
||
| `SWAP` | CAP | §4 |
|
||
| `?DUP` | CAP | `dup IF dup THEN` |
|
||
| `ROT` | CAP | §4 |
|
||
| `-ROT` | CAP | `ROT ROT` |
|
||
| `DEPTH` | RET | No visible stack pointer (D-2). |
|
||
| `PICK` | RET | No visible stack pointer (D-2). |
|
||
| `ROLL` | RET | No visible stack pointer (D-2); D-7 is moot. |
|
||
|
||
### 5.2 Return stack
|
||
|
||
| Word | Fate | v4 definition |
|
||
| --- | --- | --- |
|
||
| `>R` | IN | `push` |
|
||
| `R>` | IN | `pop` |
|
||
| `R@` | IN | `pop dup push` |
|
||
|
||
### 5.3 Memory
|
||
|
||
| Word | Fate | v4 definition / notes |
|
||
| --- | --- | --- |
|
||
| `@` | IN | `a! @` |
|
||
| `!` | IN | `a! !` |
|
||
| `+!` | CAP | `a! @ + !` |
|
||
| `-!` | CAP | `a! NEGATE @ + !` |
|
||
| `2@` | CAP | `a! @+ @` (low cell at `addr`, high at `addr+1`, as in v3) |
|
||
| `2!` | CAP | `a! SWAP !+ !` |
|
||
| `C@` | CAP | See below (D-1). |
|
||
| `C!` | CAP | See below (D-1). |
|
||
| `FILL` | CAP | See below. |
|
||
| `MOVE` | CAP | `push 2DUP U< IF pop CMOVE> ELSE pop CMOVE THEN` |
|
||
| `ERASE` | CAP | `0 FILL` |
|
||
| `CELLS` | IN | Empty (word-addressed). Becomes `2* 2*` if D-1 chooses bytes. |
|
||
|
||
```forth
|
||
\ byte access on a word-addressed node, little-endian
|
||
: C@ ( baddr -- c )
|
||
dup 3 and 3 LSHIFT SWAP 2 RSHIFT a! @ SWAP RSHIFT 255 and ;
|
||
|
||
: C! ( c baddr -- )
|
||
dup 2 RSHIFT a! \ A = word address
|
||
3 and 3 LSHIFT \ c bits
|
||
SWAP 255 and over LSHIFT \ bits c'
|
||
SWAP 255 SWAP LSHIFT inv \ c' ~mask
|
||
@ and OR ! ;
|
||
|
||
: FILL ( baddr u c -- )
|
||
SWAP BEGIN dup WHILE 1- push 2DUP SWAP C! SWAP 1+ SWAP pop REPEAT 2DROP drop ;
|
||
```
|
||
|
||
### 5.4 Arithmetic
|
||
|
||
| Word | Fate | v4 definition / notes |
|
||
| --- | --- | --- |
|
||
| `+` | OP | `+` |
|
||
| `-` | CAP | `NEGATE +` |
|
||
| `*` | CAP | `UM* drop` |
|
||
| `/` | CAP | `/MOD NIP` |
|
||
| `MOD` `/MOD` `*/` `*/MOD` (§4 versions) | RET | Shadowed duplicates. Only the §6 versions survive. |
|
||
| `1+` `1-` `2+` `2-` | IN | `1 +`, `-1 +`, `2 +`, `-2 +` |
|
||
| `2*` | OP | `2*` |
|
||
| `2/` | OP | `2/` |
|
||
| `ABS` | CAP | `dup 0< IF NEGATE THEN` — executed on the golden model (2026-10-02). |
|
||
| `NEGATE` | CAP | §4 |
|
||
| `MIN` | CAP | `2DUP > IF SWAP THEN drop` |
|
||
| `MAX` | CAP | `2DUP < IF SWAP THEN drop` |
|
||
|
||
### 5.5 Logic and comparison
|
||
|
||
| Word | Fate | v4 definition / notes |
|
||
| --- | --- | --- |
|
||
| `AND` | OP | `and` |
|
||
| `XOR` | OP | `xor` |
|
||
| `OR` | CAP | §4 |
|
||
| `INVERT` | OP | `inv` |
|
||
| `NOT` | CAP | `0=` (FORTH-79 logical not, as in v3) |
|
||
| `LSHIFT` | CAP | `BEGIN dup WHILE 1- SWAP 2* SWAP REPEAT drop` |
|
||
| `RSHIFT` | CAP | `BEGIN dup WHILE 1- SWAP 2/ MSB inv and SWAP REPEAT drop` (clears the sign bit each step; `MSB` is the cell-width top-bit constant) |
|
||
| `0=` `0<` | CAP | §4 |
|
||
| `0<>` | CAP | `0= 0=` |
|
||
| `0>` | CAP | `dup 0< SWAP 0= OR 0=` (correct for the most negative number) |
|
||
| `=` | CAP | `xor 0=` |
|
||
| `<>` | CAP | `xor 0<>` |
|
||
| `<` | CAP | `2DUP xor 0< IF drop 0< ELSE - 0< THEN` (overflow-safe) |
|
||
| `>` | CAP | `SWAP <` |
|
||
| `<=` | CAP | `> 0=` |
|
||
| `>=` | CAP | `< 0=` |
|
||
| `U<` | CAP | §4 |
|
||
| `U>` | CAP | `SWAP U<` — executed on the golden model (2026-10-02). |
|
||
| `WITHIN` | CAP | `over - push - pop U<` |
|
||
| `TRUE` | IN | `-1` |
|
||
| `FALSE` | IN | `0` |
|
||
|
||
### 5.6 Mixed-precision arithmetic
|
||
|
||
A double is two 32-bit cells on a mesh node.
|
||
|
||
| Word | Fate | v4 definition |
|
||
| --- | --- | --- |
|
||
| `M+` | CAP | `S>D D+` |
|
||
| `M-` | CAP | `NEGATE M+` |
|
||
| `M*` | CAP | `2DUP xor push ABS SWAP ABS UM* pop 0< IF DNEGATE THEN` |
|
||
| `M/MOD` | CAP | `SM/REM` |
|
||
| `MOD` | CAP | `/MOD drop` |
|
||
| `/MOD` | CAP | `push S>D pop SM/REM` — executed on the golden model (2026-10-02). |
|
||
| `*/` | CAP | `*/MOD NIP` |
|
||
| `*/MOD` | CAP | `push M* pop SM/REM` |
|
||
|
||
### 5.7 Double-cell numbers
|
||
|
||
| Word | Fate | v4 definition |
|
||
| --- | --- | --- |
|
||
| `S>D` | CAP | `dup 0<` — executed on the golden model (2026-10-02). |
|
||
| `D+` | CAP | `push SWAP push over + 2DUP U> ROT drop NEGATE pop pop + +` — executed on the golden model and exact (2026-10-02), but leaves its caller only **1** return-stack entry (D-2): anything that calls a word that calls `D+` overwrites a return address. Not yet revised. |
|
||
| `DNEGATE` | CAP | `inv over if L1 drop push inv 1 + pop ; L1: drop 1 + ;` — call-free: `~d + 1`, carrying into the high cell exactly when the low cell is 0. Executed on the golden model (2026-10-02). Replaces `inv SWAP inv SWAP 1 0 D+`, which left a caller no return-stack room, so `DABS` could not run at all. |
|
||
| `D-` | CAP | `DNEGATE D+` |
|
||
| `DABS` | CAP | `dup 0< IF DNEGATE THEN` — executed on the golden model (2026-10-02). |
|
||
| `D0=` | CAP | `OR 0=` |
|
||
| `D0<` | CAP | `NIP 0<` |
|
||
| `D=` | CAP | `D- D0=` |
|
||
| `D<` | CAP | `ROT 2DUP = IF 2DROP U< ELSE SWAP < NIP NIP THEN` |
|
||
| `DMAX` | CAP | `2OVER 2OVER D< IF 2SWAP THEN 2DROP` |
|
||
| `DMIN` | CAP | `2OVER 2OVER D< 0= IF 2SWAP THEN 2DROP` |
|
||
| `D2*` | CAP | `2* over 0< NEGATE OR SWAP 2* SWAP` |
|
||
| `D2/` | CAP | `dup 1 and push 2/ SWAP 1 RSHIFT pop IF MSB OR THEN SWAP` |
|
||
| `2DROP` | IN | `drop drop` |
|
||
| `2DUP` | IN | `over over` |
|
||
| `2SWAP` | CAP | `ROT push ROT pop` |
|
||
| `2OVER` | CAP | `push push 2DUP pop pop 2SWAP` |
|
||
| `2ROT` | CAP | `2>R 2SWAP 2R> 2SWAP` |
|
||
| `2>R` | IN | `SWAP push push` |
|
||
| `2R>` | IN | `pop pop SWAP` |
|
||
| `2R@` | IN | `pop pop 2DUP push push SWAP` |
|
||
|
||
### 5.8 Number formatting and output
|
||
|
||
All output reaches the console through `EMIT` (DEV).
|
||
|
||
| Word | Fate | Notes |
|
||
| --- | --- | --- |
|
||
| `<#` `#` `#S` `HOLD` `SIGN` `#>` | CAP | Standard pictured-output definitions over `UM/MOD` and a hold buffer. v3's tolerant `#>` (pops `ud` only if present) is not kept; v4 follows the standard stack effect. |
|
||
| `.` `.R` `U.` `U.R` `D.` `D.R` | CAP | Built on pictured output and `TYPE`. |
|
||
| `.S` | RET | No visible stack pointer (D-2). |
|
||
| `?` | CAP | `@ .` |
|
||
| `DUMP` | CAP | Loop over `@`/`C@` with pictured output. |
|
||
| `BASE` | CAP | Variable. |
|
||
| `DECIMAL` `HEX` `OCTAL` | CAP | `10 BASE !` and so on. |
|
||
|
||
### 5.9 Strings, parsing, and input
|
||
|
||
| Word | Fate | Notes |
|
||
| --- | --- | --- |
|
||
| `COUNT` | CAP | `dup 1+ SWAP C@` |
|
||
| `CMOVE` | CAP | See below. |
|
||
| `CMOVE>` | CAP | See below. |
|
||
| `BLANK` | CAP | `32 FILL` |
|
||
| `-TRAILING` | CAP | Loop from the end while the character is a space. |
|
||
| `COMPARE` | CAP | Byte loop returning `-1`, `0`, or `1`. v3's counted-string auto-detection is not kept. |
|
||
| `SEARCH` | CAP | Nested loop over `COMPARE`. Same note. |
|
||
| `SCAN` `SKIP` | CAP | Byte loops. |
|
||
| `BL` | IN | `32` |
|
||
| `EXPECT` `QUERY` | CC | Built on `KEY` (DEV). |
|
||
| `SPAN` `TIB` `>IN` `SOURCE` | CC | Interpreter state on the host node. |
|
||
| `WORD` `ENCLOSE` | CC | Parser. |
|
||
| `NUMBER` `CONVERT` | CC | Rewritten to honour `BASE` (v3's `NUMBER` is base 10 only). |
|
||
| `S"` `(s")` `[']` | CC | Compiler words. |
|
||
| `LITERAL` `[LITERAL]` (placeholders) | RET | The working `LITERAL` is in §5.17. |
|
||
|
||
```forth
|
||
: CMOVE ( src dst u -- )
|
||
BEGIN dup WHILE 1- push over C@ over C! 1+ SWAP 1+ SWAP pop REPEAT drop 2DROP ;
|
||
|
||
: CMOVE> ( src dst u -- )
|
||
BEGIN dup WHILE 1- push over R@ + C@ over R@ + C! pop REPEAT drop 2DROP ;
|
||
```
|
||
|
||
### 5.10 Terminal I/O
|
||
|
||
| Word | Fate | Notes |
|
||
| --- | --- | --- |
|
||
| `EMIT` | DEV | Console service: one-character message. |
|
||
| `KEY` | DEV | Console service: blocking receive. |
|
||
| `?TERMINAL` | DEV | Console service: non-blocking status. |
|
||
| `TYPE` | CAP | Loop of `C@ EMIT`, or one string message to the console node. |
|
||
| `CR` | CAP | `10 EMIT` |
|
||
| `SPACE` | CAP | `BL EMIT` |
|
||
| `SPACES` | CAP | `BEGIN dup 0> WHILE SPACE 1- REPEAT drop` |
|
||
| `."` `(do-string)` | CC | Compiler words. |
|
||
|
||
### 5.11 Blocks and mass storage
|
||
|
||
The storage service belongs to the Artemis role, now a device node.
|
||
|
||
| Word | Fate | Notes |
|
||
| --- | --- | --- |
|
||
| `BLOCK` `BUFFER` `UPDATE` `SAVE-BUFFERS` `EMPTY-BUFFERS` `FLUSH` | DEV | Block-service messages. Buffers live in the requesting node's RAM or in DDR. |
|
||
| `LOAD` `THRU` `-->` | CC | The interpreter reads blocks through the service. |
|
||
| `LIST` | CAP | `BLOCK` plus `TYPE`. |
|
||
| `SCR` | CAP | Variable. |
|
||
| `BLK-CONFIRM-FORMAT` `RELOCATE-BLOCK` | DEV | Owner-only storage messages. |
|
||
| `BLK-ACL-ALLOW@` `BLK-ACL-ALLOW!` `BLK-ACL-TTL@` `BLK-ACL-TTL!` | HERA | ACL state is held by Hera. |
|
||
| `BLK-OWNER@` | HERA | Read-only, as in v3. |
|
||
| `BLK-ATTACH` | RET | Took a raw host pointer. Replaced by an attach message from the device node. |
|
||
|
||
### 5.12 Dictionary space
|
||
|
||
| Word | Fate | Notes |
|
||
| --- | --- | --- |
|
||
| `HERE` `ALIGN` `ALLOT` `,` `C,` `2,` `PAD` `LATEST` | CC | The dictionary lives on the host node. |
|
||
| `SP@` `SP!` | RET | No visible stack pointer (D-2). |
|
||
|
||
### 5.13 Dictionary manipulation
|
||
|
||
| Word | Fate |
|
||
| --- | --- |
|
||
| `'` `FIND` `SMUDGE` `HIDDEN` `>BODY` `>NAME` `NAME>` `>LINK` `LINK>` `CFA` `LFA` `NFA` `PFA` `TRAVERSE` `INTERPRET` | CC |
|
||
|
||
### 5.14 Vocabularies
|
||
|
||
| Word | Fate |
|
||
| --- | --- |
|
||
| `VOCABULARY` `DEFINITIONS` `CONTEXT` `CURRENT` `FORTH` `ORDER` `(FIND)` | CC |
|
||
|
||
### 5.15 System
|
||
|
||
| Word | Fate | Notes |
|
||
| --- | --- | --- |
|
||
| `(` `\` | CC | |
|
||
| `EXECUTE` | CAP | `push ;` (tail-jumps to the xt; the xt returns to `EXECUTE`'s caller) |
|
||
| `NOP` | OP | `nop` |
|
||
| `QUIT` `ABORT` `ABORT"` `(ABORT")` `COLD` `WARM` | CC | |
|
||
| `BYE` `REBOOT` | HERA | |
|
||
| `SAVE-SYSTEM` | HERA | Snapshot becomes a capsule-image request. |
|
||
| `WORDS` `VLIST` `SEE` | CC | |
|
||
| `PAGE` | DEV | |
|
||
| `79-STANDARD` | CC | |
|
||
|
||
### 5.16 Line editor
|
||
|
||
| Word | Fate |
|
||
| --- | --- |
|
||
| `L` `S` `SHOW` `EDIT` | CC |
|
||
|
||
### 5.17 Defining words and the compiler
|
||
|
||
| Word | Fate | Notes |
|
||
| --- | --- | --- |
|
||
| `:` `;` `CREATE` `VARIABLE` `CONSTANT` `DOES>` `IMMEDIATE` `STATE` `[` `]` `LITERAL` `COMPILE` `[COMPILE]` `FORGET` `FENCE` | CC | |
|
||
| `LIT` | OP | `@p` |
|
||
| `does_rt` | RET | Internal helper; `DOES>` is implemented by the compiler capsule. |
|
||
|
||
### 5.18 Control flow
|
||
|
||
| Word | Fate | v4 definition / notes |
|
||
| --- | --- | --- |
|
||
| `IF` `ELSE` `THEN` `BEGIN` `UNTIL` `AGAIN` `WHILE` `REPEAT` `DO` `?DO` `LOOP` `+LOOP` `LEAVE` `CASE` `OF` `ENDOF` `ENDCASE` | CC | Compile-time structure words. Expansions per §2 and below. |
|
||
| `EXIT` | OP | `;` |
|
||
| `(BRANCH)` | OP | `jump` |
|
||
| `(0BRANCH)` | IN | `if L … drop` (§2) |
|
||
| `(DO)` | IN | `SWAP push push` (R: limit index) |
|
||
| `(?DO)` | IN | `2DUP = IF 2DROP jump past-loop THEN SWAP push push` |
|
||
| `(LOOP)` | IN | See below. |
|
||
| `(+LOOP)` | IN | Sign-aware boundary-crossing test; specified in the compiler capsule. |
|
||
| `(LEAVE)` | IN | `pop drop pop dup push push jump loop-test` (sets index to limit) |
|
||
| `I` | IN | `pop dup push` |
|
||
| `J` | IN | `pop pop pop dup push SWAP push SWAP push` |
|
||
| `UNLOOP` | IN | `pop pop drop drop` |
|
||
|
||
```
|
||
(LOOP) expansion:
|
||
pop 1 + pop \ index' limit
|
||
2DUP xor \ index' limit flag (0 when equal)
|
||
if Lexit
|
||
drop push push \ R: limit index'
|
||
jump Lbody
|
||
Lexit: drop drop drop
|
||
```
|
||
|
||
`(LOOP)` terminates when the index reaches the limit, which matches v3 for every loop where
|
||
`start < limit`.
|
||
|
||
**New in v4:** `FOR`, `NEXT`, and `UNEXT` are native (§2). Counted loops that don't need an ascending
|
||
index should use them; they cost one instruction per iteration.
|
||
|
||
### 5.19 StarForth extensions
|
||
|
||
| Word | Fate | Notes |
|
||
| --- | --- | --- |
|
||
| `ENTROPY@` `ENTROPY!` | MM | Per-call-target heat table (D-6). |
|
||
| `WORD-ENTROPY` `RESET-ENTROPY` `TOP-WORDS` | CC | Reports over the heat registers. |
|
||
| `(-` `INIT` | CC | |
|
||
| `VERSION` | CC | |
|
||
| `SEED` `RANDOM` | CAP | Deterministic PRNG (xorshift) in capsule code, reproducible from the seed. |
|
||
| `WAIT` | CAP | Loop until the `ANTICLOCK` register has advanced `n`. |
|
||
| `HEARTBEAT-TICKS@` | MM | `HEARTBEAT` register. |
|
||
| `ZUSE-AUTHENTICATE` `ZUSE-SESSION?` `ZUSE-PUBKEY@` `ZUSE-CERT-INSTALLED?` | HERA | |
|
||
|
||
### 5.20 Word-level ACL
|
||
|
||
| Word | Fate | Notes |
|
||
| --- | --- | --- |
|
||
| `ACL-MODE@` `ACL-MODE!` `ACL-TTL@` `ACL-TTL!` `ACL-ALLOW@` `ACL-ALLOW!` `ACL-PINNED?` `ACL-PIN` `ACL-INHERIT` `ACL-INIT-PRIMITIVES` | HERA | Hera holds the ACL table. In the fabric, per-message ACL checks happen in the router (§6). |
|
||
| `ACL-HEAT@` | MM | |
|
||
| `ACL-WORD-ID` | CC | |
|
||
|
||
### 5.21 Physics: benchmark and diagnostics
|
||
|
||
| Word | Fate | Notes |
|
||
| --- | --- | --- |
|
||
| `BENCH-DICT-LOOKUP` `PHYSICS-CACHE-STATS` `PHYSICS-TOGGLE-CACHE` `PHYSICS-RESET-STATS` `PHYSICS-BUILD-INFO` | RET | Measure v3's software dictionary and hot-words cache, which do not exist on a node. |
|
||
| `PHYSICS-BAYESIAN-REPORT` | CAP | Host node only; kept as an analysis tool. |
|
||
| `PHYSICS-WORD-METRICS` `PHYSICS-CALC-KNOBS` `PHYSICS-BURN` `PHYSICS-SHOW-FEEDBACK` | RET | Never registered in v3. |
|
||
|
||
### 5.22 Physics: pipelining diagnostics
|
||
|
||
| Word | Fate | Notes |
|
||
| --- | --- | --- |
|
||
| `PIPELINING-*` (all six) | RET | Return as MM reports if D-6 adds transition counters. |
|
||
|
||
### 5.23 Physics: freeze, heat, and decay
|
||
|
||
| Word | Fate | Notes |
|
||
| --- | --- | --- |
|
||
| `FREEZE-WORD` `UNFREEZE-WORD` `FROZEN?` | MM | Freeze bit in the heat table. |
|
||
| `HEAT@` `HEAT!` | MM | Test-only write retained. |
|
||
| `SHOW-HEAT` `ALL-HEATS` | CC | |
|
||
| `DECAY-RATE@` | MM | Governor parameter register. |
|
||
| `FREEZE-CRITICAL` | CAP | Freezes the core set; the list is rewritten for v4 names. |
|
||
|
||
### 5.24 Dictionary heat optimisation
|
||
|
||
| Word | Fate | Notes |
|
||
| --- | --- | --- |
|
||
| `HEAT-PERCENTILES` `LOOKUP-STRATEGY@` `LOOKUP-STRATEGY!` `REORG-BUCKETS` `SHOW-HEAT-OPTIMIZATION` `COMPARE-LOOKUPS` | RET | Lookup strategy is a software-dictionary concern. The host compiler may keep a heat-ordered dictionary internally, but these words are not carried forward. |
|
||
|
||
### 5.25 Logging
|
||
|
||
| Word | Fate | Notes |
|
||
| --- | --- | --- |
|
||
| `LOG-ERROR` … `LOG-DEBUG` (levels) | IN | Constants. |
|
||
| `LOG-LEVEL!` `LOG-LEVEL@` | CAP | Variable. |
|
||
| `LOG-ERROR"` … `LOG-DEBUG"` | CC | |
|
||
| `LOG-*-STR` | DEV | Log-ring service on the recorder (the ARM). |
|
||
| `(do-log-*)` | CC | |
|
||
| `(LOG-APPEND-RAW)` | DEV | |
|
||
|
||
### 5.26 Q48.16 fixed-point math
|
||
|
||
A Q48.16 value is 64 bits, so on a 32-bit node it occupies **two cells** and every Q word is a double
|
||
word. Per D-8, v4 Q values are signed.
|
||
|
||
| Word | Fate | Notes |
|
||
| --- | --- | --- |
|
||
| `Q.+` `Q.-` | CAP | `D+`, `D-` |
|
||
| `Q.*` | CAP | 64×64 product from four `UM*` partial products, shifted right 16. |
|
||
| `Q./` | CAP | Shifted long division. **Division by zero sets an error** (v3 returned 0 silently). |
|
||
| `Q.ABS` `Q.NEG` | CAP | `DABS`, `DNEGATE` |
|
||
| `Q.LOG` `Q.EXP` `Q.SQRT` `Q.SIN` `Q.COS` | CAP | Algorithms ported from `q48_words.c`; the hosted C versions are the golden model. |
|
||
| `Q.FROM-INT` | CAP | `S>D` shifted left 16. Negative values are no longer clamped to 0. |
|
||
| `Q.TO-INT` | CAP | Shift right 16, take the low cell. |
|
||
| `Q.1` `Q.0` `Q.SCALE` | IN | Double-cell constants. |
|
||
| `Q.=` `Q.<` `Q.>` `Q.0=` `Q.MAX` `Q.MIN` | CAP | `D=`, `D<`, `SWAP D<` (for `Q.>`), `D0=`, `DMAX`, `DMIN`. Signed. |
|
||
| `Q.PRINT` | CAP | Pictured output, five fractional digits. |
|
||
|
||
### 5.27 Inference engine
|
||
|
||
The runtime governor moves into hardware as the multi-level Rolling Window of Truth (see
|
||
`JUSTIFICATION.md`). These words survive on the host node as analysis tools.
|
||
|
||
| Word | Fate | Notes |
|
||
| --- | --- | --- |
|
||
| `INFER-RUN` `INFER-WINDOW@` `INFER-DECAY@` `INFER-VARIANCE@` `INFER-FIT@` `INFER-EARLY-EXIT@` | CAP | Host node only. Ported from `inference_words.c`. |
|
||
| `Q.VARIANCE` `INFER-DECAY-SLOPE` `INFER-WINDOW-WIDTH` `WINDOW-DIVERSITY` | CAP | Host node only. |
|
||
| `L8-MODE` `L8-UPDATE` `L8-APPLY` `L8-TABLE-FORCE` | MM | Jacquard selector state becomes governor registers. `L8-TABLE-FORCE` remains the DoE override. |
|
||
| `BAYES-*` (all six) | RET | Model the v3 hot-words cache and bucket search. |
|
||
|
||
### 5.28 DEFER and IS
|
||
|
||
| Word | Fate | Notes |
|
||
| --- | --- | --- |
|
||
| `DEFER` `IS` `DEFER@` | CC | A deferred word's runtime is `@p push ;` followed by the stored xt. |
|
||
|
||
### 5.29 – 5.32 Framebuffer, keyboard, TrueType, scrollback
|
||
|
||
| Word | Fate |
|
||
| --- | --- |
|
||
| `PLOT` `FB-WIDTH` `FB-HEIGHT` | DEV |
|
||
| `KBD-SCAN` `KBD-DEBUG` `VKBD-EVENT` `VKBD-DEBUG` `KEY-EVENT` `ALT+TAB` | DEV |
|
||
| `TTF-TEXT` | DEV |
|
||
| `SCROLL-BACK` `SCROLL-FWD` | DEV |
|
||
|
||
### 5.33 Kernel REPL and DoE hooks
|
||
|
||
| Word | Fate | Notes |
|
||
| --- | --- | --- |
|
||
| `HB-ON` `HB-OFF` | MM | Recorder-enable register. The fabric pushes DoE rows into a FIFO; the ARM drains it to storage. |
|
||
| `BLK-ATTACH-ACK` `KH-BLK-ATTACH-SEND` `KH-ELEVATE-SEND` | RET | Kernel-Hermes calls. Hermes is now the fabric; these become ordinary packets (§6). |
|
||
|
||
### 5.34 Hera and child-VM words
|
||
|
||
| Word | Fate | Notes |
|
||
| --- | --- | --- |
|
||
| `BIRTH` `KILL` `START` `STOP` `USE` `EXEC` `EJECT` `CONNECT-HERMES` `CONNECT-ARTEMIS` `BYE` | HERA | A VM becomes a node (or a group of nodes). `BIRTH` loads a capsule into a node and releases it. |
|
||
| `VM-EXEC` `VM-CALL` `VM-STEP` | CAP | Built on `SEND` and `RECV` (§6). |
|
||
| `VM-HEAT` `VM-ERROR?` `VM-COUNT` `VM-CONSERVED?` `VM-PHYSICS-STATUS` | MM + HERA | Per-node heat is a register; fleet totals are Hera's. |
|
||
| `SWITCH-MARK-WORK` | RET | Nodes run concurrently; there is no context switch to mark. |
|
||
| `MAMA-VM-ID` `NAME>XT` | HERA, CC | |
|
||
| `CAPSULE-*` `WORKER-BIRTH` `UNATTENDED-BIRTH` `CONSOLE-ATTACH` | HERA | |
|
||
| `MINT` `MINT-SCRATCH` `MINT-SCRATCH-EMIT` `ZUSE-ELIGIBILITY-ADD` `ZUSE-ELIGIBLE?` `ELEVATE-PUBKEY-UNPACK` | HERA | |
|
||
| `RUNCAP-TEST` `PAIR-TEST` | HERA | Diagnostics, kept. |
|
||
| `STADIUM-ADMIT` `STADIUM-EVICT` `STADIUM-RES-PULL` `STADIUM-RES-PUSH` | HERA | Admission and reservoir are Hera's. |
|
||
| `STADIUM-HEAT@` `STADIUM-HEAT!` `STADIUM-RES@` `STADIUM-WORD-HEAT` | MM | |
|
||
|
||
### 5.35 Hosted lifecycle stubs
|
||
|
||
| Word | Fate |
|
||
| --- | --- |
|
||
| `BIRTH` `KILL` `PAUSE` `RESUME` `USE` (hosted) | RET — the hosted v4 golden model implements the real HERA messages. |
|
||
|
||
---
|
||
|
||
## 6. Messaging between nodes
|
||
|
||
Each node has four neighbour ports (`PORT-UP`, `PORT-DOWN`, `PORT-LEFT`, `PORT-RIGHT`) mapped into its
|
||
address space. A read from a port blocks until the neighbour writes; a write blocks until the neighbour
|
||
reads. This is the GA144 model. No instruction is added: a port is an address.
|
||
|
||
### 6.1 Packet format (proposal)
|
||
|
||
| Word | Contents |
|
||
| --- | --- |
|
||
| 0 | Header: destination node (8 bits), type (8), TTL/heat (8), payload length in words (8). |
|
||
| 1 | ACL tag: sender identity fingerprint, checked by the router on every packet. |
|
||
| 2 … | Payload. |
|
||
|
||
The router in each node forwards packets not addressed to it, decrements TTL, and drops a packet whose
|
||
TTL reaches zero or whose ACL tag fails. This is v3 Hermes's per-message ACL check and unconditional TTL
|
||
expiry, moved into logic. A packet type `SOS` is reserved for any node to emit.
|
||
|
||
### 6.2 Send and receive
|
||
|
||
```forth
|
||
: SEND ( addr u port -- ) b! SWAP a! BEGIN dup WHILE 1- @+ !b REPEAT drop ;
|
||
: RECV ( addr u port -- ) b! SWAP a! BEGIN dup WHILE 1- @b !+ REPEAT drop ;
|
||
```
|
||
|
||
`A` walks the buffer and `B` holds the port, so each word moved costs one fetch and one store.
|
||
|
||
---
|
||
|
||
## 7. Memory-mapped registers
|
||
|
||
Addresses are assigned in the node memory map (D-4). Names only here.
|
||
|
||
| Register | Access | Contents |
|
||
| --- | --- | --- |
|
||
| `HEAT-OP[0..31]` | R | Per-opcode retirement heat. |
|
||
| `HEAT-CALL[...]` | R/W | Per-call-target heat, with freeze bit (D-6). |
|
||
| `ANTICLOCK` | R | Virtual tick: a pure function of the execution stream. |
|
||
| `HEARTBEAT` | R | Adaptive heartbeat count. |
|
||
| `GOV-*` | R/W | Governor parameters and Jacquard selector state (`L8-*`, decay rate). |
|
||
| `REC-ENABLE` | R/W | DoE recorder on/off (`HB-ON` / `HB-OFF`). |
|
||
| `PORT-STATUS` | R | Per-port ready flags, for non-blocking polls. |
|