Files
LithosAnanake/v4/include/v4/opcode.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

65 lines
3.8 KiB
C

/* opcode.h -- the 32 core opcodes.
*
* DECOMPOSITION.md section 1.3. "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."
*
* Those two renames are load-bearing, not cosmetic: FORTH-79 has words named
* `-` and `OR`, and the DECOMPOSITION table would otherwise have two distinct
* meanings per name. The renames are therefore asserted against the FORTH
* name set in tests/test_iword.c, so a future edit that reintroduces a
* collision fails a test rather than silently producing an ambiguous table.
*
* Branch opcodes are marked because the instruction-word format depends on
* them: only these five take a target out of the low bits of their slot, and
* only they are legal outside the low four slots (section 1.2).
*/
#ifndef V4_OPCODE_H
#define V4_OPCODE_H
typedef enum {
V4_OP_SEMI = 0x00, /* ; return */
V4_OP_EX = 0x01, /* ex swap P and R */
V4_OP_JUMP = 0x02, /* jump a */
V4_OP_CALL = 0x03, /* call a */
V4_OP_UNEXT = 0x04, /* unext */
V4_OP_NEXT = 0x05, /* next a */
V4_OP_IF = 0x06, /* if a */
V4_OP_MINUS_IF = 0x07, /* -if a */
V4_OP_FETCH_P = 0x08, /* @p literal */
V4_OP_FETCH_INC= 0x09, /* @+ */
V4_OP_FETCH_B = 0x0A, /* @b */
V4_OP_FETCH_A = 0x0B, /* @ */
V4_OP_STORE_P = 0x0C, /* !p */
V4_OP_STORE_INC= 0x0D, /* !+ */
V4_OP_STORE_B = 0x0E, /* !b */
V4_OP_STORE_A = 0x0F, /* ! */
V4_OP_MUL_STEP = 0x10, /* +* multiply step, D-3 */
V4_OP_TWO_STAR = 0x11, /* 2* */
V4_OP_TWO_SLASH= 0x12, /* 2/ */
V4_OP_INV = 0x13, /* inv (F18 `-`) */
V4_OP_ADD = 0x14, /* + */
V4_OP_AND = 0x15, /* and */
V4_OP_XOR = 0x16, /* xor (F18 `or`) */
V4_OP_DROP = 0x17, /* drop */
V4_OP_DUP = 0x18, /* dup */
V4_OP_RPOP = 0x19, /* pop R to data stack */
V4_OP_OVER = 0x1A, /* over */
V4_OP_PUSH_A = 0x1B, /* a */
V4_OP_NOP = 0x1C, /* nop */
V4_OP_PUSH = 0x1D, /* push T to return stack */
V4_OP_BANG_B = 0x1E, /* b! B <- T */
V4_OP_BANG_A = 0x1F, /* a! A <- T */
V4_OPCODE_COUNT = 0x20
} v4_opcode;
/* True for the five opcodes that take a branch target from the low bits of
* their slot: jump, call, next, if, -if. Everything else ignores the low
* bits of its slot, which is what makes a non-branch slot's low bits
* free for the compiler to use as a compressed argument. */
int v4_op_is_branch(unsigned op);
#endif /* V4_OPCODE_H */