/* heat.c -- heat and anti-clock. See heat.h. */ #include "v4/heat.h" #include void v4_heat_reset(v4_heat *h) { memset(h->op, 0, sizeof(h->op)); memset(h->call, 0, sizeof(h->call)); memset(h->call_freeze_mask, 0, sizeof(h->call_freeze_mask)); } void v4_heat_on_retire(v4_heat *h, unsigned op, v4_uheat_t *anticlock) { if (op < V4_OPCODE_COUNT) { h->op[op]++; } if (anticlock) (*anticlock)++; } static unsigned call_index(v4_cell target) { /* Index by target address. The table is a fixed-size cache for the model. * A real hardware table is deferred; here we hash-mod or just take low bits? * Or simply if in range use it. The spec says "per-call-target heat table" * indexed by target. For golden model, targets are small (node memory). */ unsigned idx = (unsigned)(v4_ucell)target; if (idx >= V4_HEAT_MAX_CALL_TARGETS) { /* Out of range: ignore for now? Or clamp? D-6 deferred; but heat must * be recorded for actual call targets exercised. Many tests will have * targets < 4096. This is a conservative model choice: if target is * outside the modeled table, we do not increment a modeled slot (and * we could log, but not specified). The boundary philosophy says detect * rather than corrupt: for the model, we just don't record in the fixed * table -- acceptable until D-4/D-6 pin sizes. */ return (unsigned)-1; /* invalid */ } return idx; } void v4_heat_on_call(v4_heat *h, v4_cell target) { unsigned idx = call_index(target); if (idx == (unsigned)-1) return; if (v4_heat_call_is_frozen(h, target)) return; h->call[idx]++; } v4_uheat_t v4_heat_call_get(const v4_heat *h, v4_cell target) { unsigned idx = call_index(target); if (idx == (unsigned)-1) return 0; return h->call[idx]; } int v4_heat_call_set(v4_heat *h, v4_cell target, v4_uheat_t val) { unsigned idx = call_index(target); if (idx == (unsigned)-1) return 0; if (v4_heat_call_is_frozen(h, target)) return 0; h->call[idx] = val; return 1; } void v4_heat_call_freeze(v4_heat *h, v4_cell target) { unsigned idx = call_index(target); if (idx == (unsigned)-1) return; unsigned word = idx / (8u * sizeof(v4_ucell)); unsigned bit = idx % (8u * sizeof(v4_ucell)); h->call_freeze_mask[word] |= ((v4_ucell)1u << bit); } void v4_heat_call_unfreeze(v4_heat *h, v4_cell target) { unsigned idx = call_index(target); if (idx == (unsigned)-1) return; unsigned word = idx / (8u * sizeof(v4_ucell)); unsigned bit = idx % (8u * sizeof(v4_ucell)); h->call_freeze_mask[word] &= ~((v4_ucell)1u << bit); } int v4_heat_call_is_frozen(const v4_heat *h, v4_cell target) { unsigned idx = call_index(target); if (idx == (unsigned)-1) return 0; unsigned word = idx / (8u * sizeof(v4_ucell)); unsigned bit = idx % (8u * sizeof(v4_ucell)); return (h->call_freeze_mask[word] & ((v4_ucell)1u << bit)) != 0; }