mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-27 18:52:11 -04:00
Two root causes: preserve mod state across rebuilds; never save a fabricated PC
STAGING (runtime.cmake): the framework catalog staging ran rm -rf on the whole build-dir mods/ tree before recopying. But both catalogs own only a packages/ subtree -- mods/state.toml is USER STATE written at runtime, recording which mods are enabled with which options. Every rebuild therefore silently disabled every mod: 8 MB, widescreen, framerate reverting off again and again, which presented as "the mods regressed" (aspect ratios stopped working, the game fail-fasted on 0xB0 without its 8 MB). Scope the clear to mods/packages; the deleted-mods-don't-survive guarantee is intact because that is all the catalogs ship. SAVESTATE (savestate.c): a save polled with resume_pc hint 0 substituted a candidate from a chain ending in sticky-BB latches and $ra -- values that pass the sanity check while being the wrong place to resume. The first save of a session (hint not yet published) wrote such a state; it loaded, ran minutes off the rails, and died at PC=0. Poison that looks valid at save time. hint==0 now routes into the existing defer machinery: the save completes at the next poll with a published block-leader PC, or fails loudly after the timeout. Verified: first save of a fresh session now records pc=0x8015FAEC, no fallback line. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1282,8 +1282,15 @@ function(psxrecomp_add_runtime_target target)
|
||||
# appearing on the Mods page (and inflate the release packagers'
|
||||
# catalog assertions). This runs before the game's own staging, so
|
||||
# both catalogs land on a clean slate.
|
||||
#
|
||||
# Scoped to mods/packages, NOT mods/: both catalogs own only a
|
||||
# packages/ subtree, while mods/state.toml is USER STATE written at
|
||||
# runtime (which mods are enabled, with which options). Wiping the
|
||||
# whole tree silently disabled every enabled mod on every rebuild --
|
||||
# 8 MB, widescreen, framerate all reverting off, repeatedly misread
|
||||
# as the mods themselves regressing.
|
||||
COMMAND ${CMAKE_COMMAND} -E rm -rf
|
||||
"$<TARGET_FILE_DIR:${target}>/mods"
|
||||
"$<TARGET_FILE_DIR:${target}>/mods/packages"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
"${PSXRECOMP_ROOT}/mods/builtin"
|
||||
"$<TARGET_FILE_DIR:${target}>/mods"
|
||||
|
||||
+10
-1
@@ -687,7 +687,16 @@ void savestate_poll(CPUState* cpu, uint32_t resume_pc) {
|
||||
int slot = s_save_pending;
|
||||
char path[600];
|
||||
uint32_t pc = savestate_resolve_resume_pc(cpu, resume_pc);
|
||||
if (!savestate_resume_pc_ok(pc)) {
|
||||
/* hint==0 ALSO defers, even when the resolver found a plausible-looking
|
||||
* substitute. The substitute chain ends in sticky-BB latches and $ra,
|
||||
* which pass the sanity check while being the wrong place to resume:
|
||||
* the first F7 of a session saved such a state, it loaded, ran for
|
||||
* ~150M instructions off the rails, and died at PC=0 -- poison that
|
||||
* looks valid at save time and only fails minutes later. Deferring
|
||||
* reuses the existing retry: the save completes at the next poll where
|
||||
* a real block-leader PC is published, or fails LOUDLY after the
|
||||
* timeout instead of writing a corrupt state silently. */
|
||||
if (resume_pc == 0u || !savestate_resume_pc_ok(pc)) {
|
||||
/* FMV/present edges often poll with hint=0; wait briefly for a
|
||||
* sticky BB / IRQ latch rather than writing pc=0 poison. */
|
||||
const double now = savestate_mono_ms();
|
||||
|
||||
Reference in New Issue
Block a user