mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
interp: word-tag the ws site caches - stale verdicts corrupted the guest
MMX6 16:9 attract wedged (misaligned wild dispatch 0x21010001 -> fatal halt, stack-sampled at psx_unknown_dispatch under dirty_ram_dispatch). Mechanism: the enlarged site caches persist across overlay reloads, and the generation counter only sees page-marking hooks (kernel writes + DMA executable-range marks) - code replaced by plain CPU stores (loader memcpy) keeps the page dirty and never bumps the generation, so a cached backdrop verdict derived from the PREVIOUS overlay bytes could fire a GPR rewrite at the wrong instruction. The old 256-slot cache had the same hole but evicted within seconds; the 8192-slot cache widened the exposure to a real wedge. Each entry now also stores the site instruction word and revalidates it on lookup (one fetch_word) - any code change at the site forces re-derivation. Cost on the hot path: one load + compare per candidate instruction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -301,11 +301,17 @@ extern uint32_t g_dirty_ram_code_gen;
|
||||
|
||||
static int ws_cull_site(uint32_t pc) {
|
||||
enum { WIN = 128 }; /* +/- 128 words = +/- 512 bytes */
|
||||
static struct { uint32_t pc; uint32_t gen; int8_t flag; } cache[WS_SITE_CACHE_SLOTS];
|
||||
static struct { uint32_t pc; uint32_t gen; uint32_t word; int8_t flag; } cache[WS_SITE_CACHE_SLOTS];
|
||||
uint32_t slot = (pc >> 2) & (WS_SITE_CACHE_SLOTS - 1u);
|
||||
if (cache[slot].pc == pc && cache[slot].gen == g_dirty_ram_code_gen)
|
||||
return cache[slot].flag;
|
||||
uint32_t phys = pc & 0x1FFFFFFFu;
|
||||
/* Entry valid iff pc + generation + the SITE'S OWN INSTRUCTION WORD all
|
||||
* match. The word tag catches code replaced by plain CPU stores (loader
|
||||
* memcpy), which never routes through the page-marking hooks the
|
||||
* generation counter sees — a stale verdict here REWRITES a live GPR and
|
||||
* corrupts the guest (wild-jump fatal). */
|
||||
if (cache[slot].pc == pc && cache[slot].gen == g_dirty_ram_code_gen &&
|
||||
cache[slot].word == fetch_word(phys))
|
||||
return cache[slot].flag;
|
||||
uint32_t lo = (phys > (uint32_t)(WIN * 4)) ? phys - (uint32_t)(WIN * 4) : 0u;
|
||||
uint32_t hi = phys + (uint32_t)(WIN * 4);
|
||||
if (hi > 0x200000u) hi = 0x200000u; /* 2 MB main RAM */
|
||||
@@ -314,7 +320,8 @@ static int ws_cull_site(uint32_t pc) {
|
||||
for (uint32_t a = lo; a + 4u <= hi && n < (int)(2 * WIN + 1); a += 4u)
|
||||
words[n++] = fetch_word(a);
|
||||
int flag = psx_ws_func_has_screen_cull(words, n);
|
||||
cache[slot].pc = pc; cache[slot].gen = g_dirty_ram_code_gen; cache[slot].flag = (int8_t)flag;
|
||||
cache[slot].pc = pc; cache[slot].gen = g_dirty_ram_code_gen;
|
||||
cache[slot].word = fetch_word(phys); cache[slot].flag = (int8_t)flag;
|
||||
return flag;
|
||||
}
|
||||
|
||||
@@ -328,13 +335,18 @@ static int ws_cull_site(uint32_t pc) {
|
||||
* WS_BD_END_WIDEN. Single-threaded interp => static buffers are safe. */
|
||||
static int ws_backdrop_site_kind(uint32_t pc, int *out_cols) {
|
||||
enum { WIN = 128 }; /* +/- 128 words = +/- 512 bytes */
|
||||
static struct { uint32_t pc; uint32_t gen; int8_t kind; int16_t cols; } cache[WS_SITE_CACHE_SLOTS];
|
||||
static struct { uint32_t pc; uint32_t gen; uint32_t word; int8_t kind; int16_t cols; } cache[WS_SITE_CACHE_SLOTS];
|
||||
uint32_t slot = (pc >> 2) & (WS_SITE_CACHE_SLOTS - 1u);
|
||||
if (cache[slot].pc == pc && cache[slot].gen == g_dirty_ram_code_gen) {
|
||||
uint32_t phys = pc & 0x1FFFFFFFu;
|
||||
/* pc + generation + site instruction word — see ws_cull_site: the word tag
|
||||
* is what protects against CPU-store code reloads the generation counter
|
||||
* cannot see. A stale KIND here is worse than a stale cull flag: it
|
||||
* substitutes a GPR value and skips the real instruction. */
|
||||
if (cache[slot].pc == pc && cache[slot].gen == g_dirty_ram_code_gen &&
|
||||
cache[slot].word == fetch_word(phys)) {
|
||||
if (out_cols) *out_cols = cache[slot].cols;
|
||||
return cache[slot].kind;
|
||||
}
|
||||
uint32_t phys = pc & 0x1FFFFFFFu;
|
||||
uint32_t lo = (phys > (uint32_t)(WIN * 4)) ? phys - (uint32_t)(WIN * 4) : 0u;
|
||||
uint32_t hi = phys + (uint32_t)(WIN * 4 + 4);
|
||||
if (hi > 0x200000u) hi = 0x200000u; /* 2 MB main RAM */
|
||||
@@ -345,6 +357,7 @@ static int ws_backdrop_site_kind(uint32_t pc, int *out_cols) {
|
||||
int cols = 0;
|
||||
int kind = psx_ws_backdrop_kind_at(words, n, lo, phys, &cols); /* all physical-space */
|
||||
cache[slot].pc = pc; cache[slot].gen = g_dirty_ram_code_gen;
|
||||
cache[slot].word = fetch_word(phys);
|
||||
cache[slot].kind = (int8_t)kind; cache[slot].cols = (int16_t)cols;
|
||||
if (out_cols) *out_cols = cols;
|
||||
return kind;
|
||||
|
||||
Reference in New Issue
Block a user