Repository navigation
Access-exact APU port timing, per-clock S-DSP, hardware DMA alignment - #241
Conversation
mstan
left a comment
There was a problem hiding this comment.
I pushed two objective repairs to this branch: complete current-build timing snapshots (RTLS v11, with invalid-index preflight) and restoration of existing DAC voice-mask/echo controls on the clocked DSP. The new regression runs audible BRR continuation at every DSP phase; the full Python suite passes 877 tests with 2 skips. The PR body records the exact scope. Representative combined built-game gameplay/save-load/runtime checks are still underway, so this is not an approval yet.
For the main SoE correctness result, please add the reproducible replay recipe: ROM revision/hash, consumer source/config head, MesenCE source/build identity and relevant settings, input replay (or deterministic input-generation instructions), and the commands/checkpoint comparison used for the 9,227-NMI / attract runs. I found the result in the description but no replay recipe in the changed files or PR conversation. Please keep ROMs and generated game C out of the repository. That will let us verify the intended timing contract independently; representative unrelated games alone cannot establish the SoE fix.
|
This is close to what I had to fix for Secret of Mana in my fork, measured against bsnes and Mesen2. Two things from that work that may matter here:
Once this is merged I can run my Secret of Mana scripts on it: AOT and interpreter runs, plus state comparison against bsnes. I will report anything that differs. |
|
thanks for the quick feedback. I managed to perfectly sync SoE to the MesenCE replays with a couple of changes to my snesrecomp fork, after a hard fight. I'll start to clean up the repo now and prepare everything so it can be reproduced. Reporting back once I have everything and raised all PRs. |
|
Sorry for the wait, I had to clean up my repos a lot to make them standalone. All of my evermore research gravitated to a mono repo, which was hard to work with.
Repositories
Recipe
git clone --recursive https://github.com/r-bin/SecretOfEvermoreRecomp && cd SecretOfEvermoreRecomp
bash tools/regen.sh --rom /path/to/rom.sfc
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build -j
node tools/compare/compare.mts mesen recomp /path/to/rom.sfc --replay tools/compare/replays/01-no-inputs-1-loop.mmo --regions wram,vram,cgram,oam --verboseExpected: |
810d438 to
c1f84f6
Compare
|
Follow-up on my note from the 4th, now that this is merged. (The overrun in
For now my fork keeps its own SPC model when cycle parity is on and uses yours otherwise. Per-clock S-DSP and DMA alignment stay on as you set them. |
|
Follow-up on the pre-sync difference from my last comment. Short version: I couldn't pin it on a specific handshake. It comes from two effects that don't point clearly at #241. Separately, there is one port-timing difference in the IPL upload that may be worth a look, and it lines up with the input delay I mentioned on the 4th. Setup: WRAM and APU state every frame from power-on, native with both SPC models on the same CPU side, against bsnes (Mesen2 2.1.1 only for a few WRAM ranges; I have no MesenCE runs for SoM).
I can't publish the SoM setup, but if you want a switch or one of your follow-up branches checked on SoM, I can run it here and report back. |
|
@r-bin, a follow-up on your resume branches. (Edited: I first wrote this against My fork has the same goal for Secret of Mana: compiled code and the interpreter at the same clock at every instruction. I haven't run the game on No rush on any of this. These are just notes in case they help, so skip whatever doesn't fit your plan.
Once you open the PR, I'm happy to run my game on it and post the result here, whenever it suits you. |
this slightly concerns me, since I don't know the differences between the emulators. Do you think we optimize into different directions? I feel like there should either be only one primarily supported emulator, or all of them should be support (however much work that might be) The only reason I chose mesenCE is because they are open source, cycle accurate (to my knowledge) and easily moddable. If there is a officially supported emulator I'll gladly port all of my work to that emulator. |
|
@r-bin, I don't think we are, at least not on the APU side. MesenCE is a fork of Mesen2, and the input delay I meant is the same code in both: I used bsnes as the reference for full-state comparisons (WRAM and APU state every frame) only because that's what my tooling was built around, not because I prefer its rules. Your question was a good reason to change that, so I've moved my checks over: the per-frame state comparisons and all my other emulator runs now use MesenCE 2.2.1, and bsnes is no longer part of my setup. The results matched what I had against bsnes. The one place I know of where we did follow different emulators is brightness: my #257 rounds like bsnes, and your #281 adds MesenCE's truncation as an option, which seems like the right way to handle it until someone settles what the hardware does. Which emulator should be the reference is the maintainers' call. From my side there is now only one, MesenCE, which is also what your SPC timing is measured against, so I'd be glad to see it become the official one. |
hey, I'm new here, so feel free to point out problems in the PR.
My goal was a minimal invasive and generic change to allow SoE to sync with MesenCE (cycle accurate).
The main complaint why this is required was that accessing the sound processor took either too long or not long enough.
The SPC700 handles all of an opcode's bus accesses on its first cycle, and the CPU and DMA are charged per block. So the timing of
$2140–$2143handshakes, timer reads and$420Bdrifts away from hardware. In Secret of Evermore, WRAM diverges from MesenCE 2.2.1 at NMI 319.What changes:
SPC700 port, timer and
$F3accesses happen on their own cycle.CPU port accesses sync the SPC up to their exact clock.
The S-DSP runs per clock.
DMA start and end are aligned as on hardware.
The
$2137latch is gated by WRIO, and$4212H-blank is taken at the read's own clock.Each change has a
SNESRECOMP_*=0switch to turn it off.Result, all interpreted: WRAM matches MesenCE at every NMI of a 9,227-NMI new-game replay, and through NMI 5997 of the attract replay. Before, both stopped matching at NMI 319. The original implementation retained the old savestate layout; the maintainer repairs below update that layout to include the new timing state. The C tests pass.
Limits: the exact per-access clocks apply only in the interpreter, and I haven't measured the CPU cost of the per-clock DSP.
Maintainer validation and repairs (2026-11-03)
Tested head:
3147cba94a9a7501478c102ab5da500e7ba365ed.Fixed current-build save/load: serialize the per-clock DSP phase, KON/rate/END pipeline, APU timing debt and SPC access cursor. Runtime states now use version 11 and reject older layouts. Invalid clock indices are rejected before changing live state.
Restored existing DAC voice-mask controls for the per-clock DSP, including echo, without changing canonical synthesis state or APU RAM.
Added audible BRR snapshot/continuation checks at all 32 DSP phases, both timing models, muted dry/echo output, canonical-state equivalence and invalid-state transaction coverage.
Python suite: 877 passed, 2 skipped. Existing mixer checks pass all 256 voice masks; focused snapshot/producer/capture tests also pass. The final follow-up commit only makes a Python import explicit.
Combined regression passed on
ed0334b78150d325cd10750725c17157cb668c57: 880 Python tests passed (2 skipped), seven production PPU harnesses passed, and MMX, ALttP, SMW and Super Metroid passed representative gameplay, current-build save/load and matched runtime checks. The owner cleared the built games on 2026-11-03 (MMX okay, then all pass), completing this batch's regression/merge handoff. Runtime samples showed no demonstrated per-game regression; shared-host variation is not an optimization claim. The separate request for a reproducible Secret of Evermore replay recipe remains unresolved, so this PR stays open pending author evidence. The original interpreter replay result above remains the author's reported evidence; it has not been independently replayed here.Boundary repair during review (2026-11-04)
Current head:
3856deb1a66f4f238286071c162acc6ab4bdcff2. The queued-write boundary overrun raised in the new discussion also exists in main; its default-model repair is #258. This branch now drains already-due writes before testing the target, while retaining access-exact hold/cleanup behavior. The added boundary regression passes all four portable/native APU and instruction-start/access-exact combinations. All four focused DSP snapshot and producer-pacing checks pass. The earlier full-suite/built-game evidence above remains identified with its original tested heads; it is not relabeled as a new SoE replay or hardware-input-delay qualification. The author replay recipe remains the outstanding acceptance item.Strict C11 portability follow-up (2026-11-04)
Current head:
aa2f09fa416f8d1a43e0dddc587e03953e1e67c2. Approving the previously waiting Linux CI exposed the new snapshot fixture compilingaudio_trace.cin strict C11 without visible POSIX clock declarations. Reproduced the exact failure locally under native Ubuntu/GCC13.3, then exposed the POSIX declarations before system headers on non-Windows builds. The identical strict-C11 compile and all DSP snapshot cases now pass on Linux; all four focused Windows checks also pass. Fresh full CI is approved/running; no new full-suite pass is claimed yet for this follow-up. This does not supply the outstanding SoE replay recipe.Digest stream boundary repair and fresh full CI (2026-11-04)
Current head:
810d438a5a6af0cb01f989d1f5d8c9e6f1dd0d9d. The full Linux C gate exposed the APU digest ring exclusion still using the pre-debt stream offset: serializing timer/DSP advance debt moved the ring four bytes and caused the last FIR field to be excluded. The skip offsets now include both debt blocks. Regression coverage also verifies every timer debt, DSP debt, KON/rate/END pipeline and clocked voice continuation state is included while all host ring data/cursors remain excluded.The Linux negative control fails at the original final-FIR-field assertion; the repaired digest harness passes on native Linux and Windows, including both DSP timing models. Full Native analyzer CI on this exact head passes Linux, Windows and macOS, including the Linux Python, C runtime and optional content-pack gates. The prior built-game approval remains attached to its original tested head; this is not a new SoE replay claim.
The author's reproducible Secret of Evermore replay recipe remains required, so this PR remains open. TechnicallyComputers is assigned for the netplay digest change.