Files
LithosAnanake/v4/include/v4/iword.h
T
rajamesandClaude Opus 5.5 067f317c47 feat(v4.0.0): hosted golden model, single node
First code for StarForth v4 (JUSTIFICATION.md section 10, step 1): one node
of the 32-instruction core as a C99 model, with cell width as a build
parameter.

- Node: P, A, B, F18 circular stacks (10 and 9 deep, D-2), word-addressed
  memory (D-1), 5% guard bands on every bounded list.
- Instruction word: six 5-bit slots in 32 bits at every cell width.
- Executor: all 32 opcodes of DECOMPOSITION.md 1.3. Cell arithmetic wraps
  explicitly; no signed overflow or implementation-defined shift.
- Heat: per-opcode and per-call-target counters and the anti-clock, driven
  by instruction retirement (1.4, D-6 interim).
- Slot packer and runner for tests, and a reference unsigned multiply in
  plain C99 with no 128-bit type.

Tests run at 32- and 64-bit cells, and under ASan and UBSan. They cover
every opcode and execute the first section 4 definitions (NIP SWAP OR
NEGATE ROT 0< 0= 2DUP - U<) against the C operation each stands for.

UM* as written in section 4 is exact only while u1 <= 2^(n-2). Two known
failing cases are pinned in test_foundation.c until it is rewritten.

DECOMPOSITION.md: record D-9, the instruction word is 32 bits at every
cell width (ruled 2026-10-02).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 14:38:27 -04:00

102 lines
4.8 KiB
C

/* iword.h -- the 32-bit instruction word and its decode.
*
* DECOMPOSITION.md section 1.2:
*
* 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", with reach 27 / 22 / 17 / 12 bits.
*
* That reach column is not a separate rule, it falls out of the layout: slot k
* sits at bits [31-5k : 27-5k], so the bits to its right are [26-5k : 0],
* which is 27-5k bits -- 27, 22, 17, 12 for slots 0..3. This header derives
* the masks from that one formula rather than hard-coding four of them, so the
* decode cannot drift from the reach table.
*
* THE SPARE BITS ARE ADDRESS BITS. "Spare" means only that they are never
* *executed*: they are below every slot, so "all bits to the right of its
* slot" includes them, and they are the low bits of the address of a branch in
* any slot. They are inert for opcode decode and live in a branch target.
* This is easy to assume otherwise and get wrong -- an earlier revision of
* this header subtracted them from the branch width, which silently cost two
* address bits off every branch and was caught by tests/test_iword.c. They
* exist because 6*5 = 30 does not fill a 32-bit word, and on the F18 those low
* bits are simply the bottom of the address space.
*
* The consequence for the compiler is worth stating: a non-branch slot's low
* bits are free to carry a compressed argument, but a branch slot's are not,
* because they are address.
*
* NOTE ON WIDTH. The word format is 32 bits regardless of V4_CELL_BITS: the
* diagram is 32 bits wide and 6*5+2 = 32 exactly. D-5 makes the *cell* width
* a build parameter, but the instruction word is not a payload and does not
* follow the cell. At 32-bit cells a word is a cell. At 64-bit cells it is
* the low 32 bits of the cell and the high half is ignored (D-9), so compiled
* code is identical at both widths. The decode below operates on a distinct
* 32-bit type; the fetch in exec.c does the narrowing.
*/
#ifndef V4_IWORD_H
#define V4_IWORD_H
#include <stdint.h>
#include "v4/cell.h"
#include "v4/opcode.h"
/* The instruction word is 32 bits at every cell width. */
typedef uint32_t v4_iword;
#define V4_SLOT_COUNT 6u /* six 5-bit slots, DECOMPOSITION.md 1.1 */
#define V4_SPARE_BITS 2u /* "plus 2 spare bits" */
/* C99 has no _Static_assert, so the "6*5+2 == 32" identity is enforced with
* the negative-array-size idiom. If the slot count, the spare-bit count or the
* word width ever stop adding up to 32, this fails to compile. */
typedef char v4_iword_layout_is_exact
[((V4_SLOT_COUNT * 5u + V4_SPARE_BITS) == 32u) ? 1 : -1];
/* Bit range of slot k: high bit 31-5k, low bit 27-5k. */
#define V4_SLOT_HIGH_BIT(k) (31u - 5u * (k))
#define V4_SLOT_LOW_BIT(k) (27u - 5u * (k))
/* Number of address bits a branch in slot k carries: all bits to the right of
* the slot. Slot k's low bit is 27-5k, so the bits below it are 0..(26-5k),
* which is 27-5k bits -- equal to the slot's own low bit. This is the single
* source of the reach column, and it is why the spare bits are *not* subtracted
* here: see the note on the spare bits below. */
#define V4_BRANCH_ADDR_BITS(k) (V4_SLOT_LOW_BIT(k))
/* Mask of the low address bits a branch in slot k replaces in P. */
uint32_t v4_iword_slot_mask(unsigned slot);
/* The 5-bit opcode in slot k, 0..31. */
unsigned v4_iword_op(v4_iword w, unsigned slot);
/* The 2 spare low bits. Never executed. */
unsigned v4_iword_spare(v4_iword w);
/* The branch target carried by a branch in slot k: all bits to the right of
* the slot, zero-extended. Meaningful only for the five branch opcodes. */
v4_iword v4_iword_target(v4_iword w, unsigned slot);
/* Assemble a word from six 5-bit opcodes and the 2 spare bits. Opcode values
* above 31 or spare bits above 3 are rejected, because a golden model must not
* paper over an out-of-range encoding. */
v4_iword v4_iword_assemble(const unsigned op[V4_SLOT_COUNT], unsigned spare);
/* Apply a branch: replace the low V4_BRANCH_ADDR_BITS(slot) bits of P with the
* target, preserving the bits above (page-relative, F18-style). */
v4_cell v4_iword_branch(v4_cell p, v4_iword w, unsigned slot);
/* Branches are legal in slots 0-3 only (section 1.2). Slots 4 and 5 have 7 and
* 2 address bits respectively, which is not a useful reach and is not
* sanctioned by the table. */
int v4_iword_branch_legal(unsigned slot);
#endif /* V4_IWORD_H */