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

80 lines
4.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* heat.h -- heat and anti-clock, not instructions themselves (1.4).
*
* DECOMPOSITION.md section 1.4 states: "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."
*
* D-6 is deferred to step 2, but the note immediately adds: "The golden model
* implements per-opcode and per-call-target heat in the meantime." The
* counters here are therefore a two-dimensional heat structure (op × target)
* on a per-call basis, with counts stored in 64-bit (because heat is
* accumulated and must not roll over at 32-bit). The "per-call-target"
* counter is indexed by the address of the called target -- on a word-addressed
* node, that is a cell value equal to the address `a` passed to `call a`.
*
* The anti-clock is a virtual tick driven by execution -- one tick per retired
* instruction -- and the rest of §7 refers to it via `ANTICLOCK`. It is not a
* wall-clock time, it is a function of the execution stream, as specified.
*
* The MM names in §7: `HEAT-OP[0..31]` (R), `HEAT-CALL[...]` (R/W) with a
* freeze bit (D-6). D-4 (memory map) is deferred, so the model does not
* materialize those MM addresses yet. This header defines the backing storage
* that a later MM layer will expose; it keeps the counts separate from the node
* itself because heat is physics data, not the instruction word stream, and it
* needs to be accessible to assertions such as K conservation tests later.
*
* Counts are 64-bit. Even for a short run a call-heavy word can heat up many
* times, and the golden model must run POST and remain monotonic and
* comparable. They are stored as `v4_uheat_t` (which is uint64_t by cell-width
* parameterisation) rather than cell-sized so that a 32-bit node's heat is not
* width-truncated in the model. (JUSTIFICATION.md §5 keeps heat arithmetic
* 64-bit regardless of cell width.)
*/
#ifndef V4_HEAT_H
#define V4_HEAT_H
#include "v4/cell.h"
#include "v4/opcode.h"
#define V4_HEAT_MAX_CALL_TARGETS 4096u
typedef struct {
v4_uheat_t op[V4_OPCODE_COUNT]; /* HEAT-OP[0..31] */
/* Per-call-target heat. Indexed by target address. The table is fixed-size
* for the golden model; the actual hardware table size is deferred with D-6,
* but "in the meantime" the model must have a per-call-target structure.
* 4096 entries is small (32KB if using 64-bit per entry), enough to cover a
* typical test program's call targets without needing to allocate on-the-fly
* -- and since the node has boundaries, over-indexing is caught. */
v4_uheat_t call[V4_HEAT_MAX_CALL_TARGETS];
v4_ucell call_freeze_mask[V4_HEAT_MAX_CALL_TARGETS / (sizeof(v4_ucell) * 8u)];
/* freeze bits: one per call-target entry (D-6). Stored as a bitmask. */
} v4_heat;
void v4_heat_reset(v4_heat *h);
/* Every retired instruction: +1 to the opcode's heat and +1 to ANTICLOCK. */
void v4_heat_on_retire(v4_heat *h, unsigned op, v4_uheat_t *anticlock);
/* Every call: +1 to the call-target's heat. The target is the address passed
* to call (word address). If the target is outside the table range, the model
* must not silently wrap -- a boundary-style check is the conservative choice
* here, because the table size is a model parameter. */
void v4_heat_on_call(v4_heat *h, v4_cell target);
/* Read/write helpers for per-call-target heat (R/W). Freeze bits are set per
* target when D-6's freeze bit is asserted; writes to a frozen target should be
* ignored in a real implementation, but the MM layer is not defined yet. The
* golden model stores freeze bits and the accessor can enforce them later. */
v4_uheat_t v4_heat_call_get(const v4_heat *h, v4_cell target);
int v4_heat_call_set(v4_heat *h, v4_cell target, v4_uheat_t val);
/* Freeze control (D-6). */
void v4_heat_call_freeze(v4_heat *h, v4_cell target);
void v4_heat_call_unfreeze(v4_heat *h, v4_cell target);
int v4_heat_call_is_frozen(const v4_heat *h, v4_cell target);
#endif /* V4_HEAT_H */