From 534dcd5df3bbfe4585f8024b0032615d962f843a Mon Sep 17 00:00:00 2001 From: Matthew Stanley <1379tech@gmail.com> Date: Fri, 2 Oct 2026 12:00:42 -0700 Subject: [PATCH] PGXP: always-on ring of refused perspective-depth lookups (TCP pgxp_miss_ring) Co-Authored-By: Claude Opus 5.5 (1M context) --- runtime/include/pgxp.h | 20 +++++++++++++++++ runtime/src/debug_server.c | 35 +++++++++++++++++++++++++++++ runtime/src/pgxp.cpp | 45 +++++++++++++++++++++++++++++++++++--- 3 files changed, 97 insertions(+), 3 deletions(-) diff --git a/runtime/include/pgxp.h b/runtime/include/pgxp.h index 25e8e90a..291d90cd 100644 --- a/runtime/include/pgxp.h +++ b/runtime/include/pgxp.h @@ -127,6 +127,26 @@ void pgxp_store_gte_reg(uint32_t addr, uint8_t reg); int pgxp_load_precise_word(uint32_t addr, uint32_t packed, int32_t *x16, int32_t *y16, uint16_t *z); +/* Refused precise-word lookups, newest at (seq - 1) % cap (TCP pgxp_miss_ring). */ +enum { + PGXP_MISS_UNTRACKED = 1, + PGXP_MISS_MISMATCH = 2, + PGXP_MISS_PARTIAL = 3, + PGXP_MISS_NO_Z = 4 +}; +#define PGXP_MISS_RING_CAP 8192u +typedef struct PGXPWordMiss { + uint64_t seq; + uint32_t addr; /* packet word address (canonical RAM offset) */ + uint32_t packet; /* the word the GPU consumed */ + uint32_t shadow_value; /* the word the shadow describes */ + uint8_t shadow_flags; /* 1 = X, 2 = Y, 4 = Z */ + uint8_t live; /* shadow belongs to the current generation */ + uint8_t reason; /* PGXP_MISS_* */ +} PGXPWordMiss; +/* Returns the total number of misses ever recorded. */ +uint64_t pgxp_word_miss_ring(const PGXPWordMiss **ring, uint32_t *cap); + /* Debug read of one shadow slot (TCP pgxp_shadow). `space`: 0 = guest * address (RAM / scratchpad), 1 = GPR index (32 = HI, 33 = LO), 2 = GTE data * register. Returns 0 when the slot does not exist; *live says whether it diff --git a/runtime/src/debug_server.c b/runtime/src/debug_server.c index ee6898ec..573f66d1 100644 --- a/runtime/src/debug_server.c +++ b/runtime/src/debug_server.c @@ -5353,6 +5353,40 @@ static void handle_pgxp_shadow(int id, const char *json) send_fmt("%s", buf); } +/* pgxp_miss_ring — the newest refused perspective-depth lookups (always-on + * ring, PGXP_MISS_RING_CAP deep): {"cmd":"pgxp_miss_ring","count":N}. Each + * entry: packet word address (canonical RAM offset), the word the GPU + * consumed, the word/flags the shadow held, and the reason (untracked, + * mismatch, partial, no_z). Join addr with wtrace_dump to name the writer. */ +static void handle_pgxp_miss_ring(int id, const char *json) +{ + static const char *const reasons[] = { "?", "untracked", "mismatch", + "partial", "no_z" }; + const PGXPWordMiss *ring; uint32_t cap; + uint64_t total = pgxp_word_miss_ring(&ring, &cap); + int count = json_get_int(json, "count", 256); + uint64_t avail = total < cap ? total : cap; + if (count < 0) count = 0; + if ((uint64_t)count > avail) count = (int)avail; + size_t sz = (size_t)count * 160u + 256u; + char *buf = (char *)malloc(sz); + if (!buf) { send_err(id, "oom"); return; } + size_t n = (size_t)snprintf(buf, sz, "{\"id\":%d,\"ok\":true,\"total\":%llu,\"entries\":[", + id, (unsigned long long)total); + for (int i = 0; i < count; i++) { + const PGXPWordMiss *m = &ring[(total - (uint64_t)count + (uint64_t)i) % cap]; + n += (size_t)snprintf(buf + n, sz - n, + "%s{\"seq\":%llu,\"addr\":\"0x%08X\",\"packet\":\"0x%08X\"," + "\"shadow\":\"0x%08X\",\"flags\":%u,\"live\":%u,\"reason\":\"%s\"}", + i ? "," : "", (unsigned long long)m->seq, m->addr, m->packet, + m->shadow_value, m->shadow_flags, m->live, + reasons[m->reason < 5 ? m->reason : 0]); + } + snprintf(buf + n, sz - n, "]}"); + send_fmt("%s", buf); + free(buf); +} + /* pgxp — live-tune the value-propagation engine for one-toggle isolation runs * without a rebuild: {"cmd":"pgxp","cpu_mode":0|1,"tolerance":F}. Fields are * optional; the reply echoes the resulting state (same shape as @@ -14402,6 +14436,7 @@ static const CmdEntry s_commands[] = { { "geom_correction", handle_geom_correction }, { "pgxp", handle_pgxp }, { "pgxp_shadow", handle_pgxp_shadow }, + { "pgxp_miss_ring", handle_pgxp_miss_ring }, { "ws_aspect_cone_site", handle_ws_aspect_cone_site }, { "ws_margin", handle_ws_margin }, { "ws_hud_mode", handle_ws_hud_mode }, diff --git a/runtime/src/pgxp.cpp b/runtime/src/pgxp.cpp index 565f79d5..50a3f15b 100644 --- a/runtime/src/pgxp.cpp +++ b/runtime/src/pgxp.cpp @@ -823,21 +823,60 @@ extern "C" void pgxp_test_set_generation(uint32_t gen) { s_gen = gen; } /* Address-keyed depth lookup for the shipped perspective-texturing path * (gpu.c prepare_texture_triangle). Same contract as the retired hashed * table: hit only when the tracked word matches the packet word exactly. */ +/* Always-on ring of refused precise-word lookups: which packet word, what + * the shadow at its address held, and why it was refused. Join it with + * wtrace_dump (writer PC per address) to find the guest code path that drops + * provenance. */ +static PGXPWordMiss s_miss_ring[PGXP_MISS_RING_CAP]; +static uint64_t s_miss_seq = 0; + +static void note_word_miss(uint32_t addr, uint32_t packed, const PGXPValue *pv, + uint8_t reason) { + PGXPWordMiss *m = &s_miss_ring[s_miss_seq % PGXP_MISS_RING_CAP]; + m->seq = s_miss_seq++; + m->addr = addr; + m->packet = packed; + m->shadow_value = pv ? pv->value : 0; + m->shadow_flags = pv ? (uint8_t)pv->flags : 0; + m->live = (pv && pv->gen == s_gen) ? 1 : 0; + m->reason = reason; +} + +extern "C" uint64_t pgxp_word_miss_ring(const PGXPWordMiss **ring, + uint32_t *cap) { + *ring = s_miss_ring; + *cap = PGXP_MISS_RING_CAP; + return s_miss_seq; +} + extern "C" int pgxp_load_precise_word(uint32_t addr, uint32_t packed, int32_t *x16, int32_t *y16, uint16_t *z) { if (!s_enabled) return 0; s_stats.word_lookups++; PGXPValue *pv = pgxp_ptr(addr); - if (!pv || pv->gen != s_gen) { s_stats.word_untracked++; return 0; } - if (pv->value != packed) { s_stats.word_mismatch++; return 0; } + if (!pv || pv->gen != s_gen) { + s_stats.word_untracked++; + note_word_miss(addr, packed, pv, PGXP_MISS_UNTRACKED); + return 0; + } + if (pv->value != packed) { + s_stats.word_mismatch++; + note_word_miss(addr, packed, pv, PGXP_MISS_MISMATCH); + return 0; + } if ((pv->flags & PGXP_F_VXY) != PGXP_F_VXY) { s_stats.word_partial++; + note_word_miss(addr, packed, pv, PGXP_MISS_PARTIAL); return 0; } if (x16) *x16 = pv->x16; if (y16) *y16 = pv->y16; if (z) *z = (pv->flags & PGXP_F_VZ) ? pv->z : 0; - if (!(pv->flags & PGXP_F_VZ) || pv->z == 0) { s_stats.word_no_z++; return 0; } + if (!(pv->flags & PGXP_F_VZ) || pv->z == 0) { + s_stats.word_no_z++; + note_word_miss(addr, packed, pv, PGXP_MISS_NO_Z); + return 0; + } s_stats.word_hit++; return 1; }