Repository navigation
Deliver ARM9 IPC FIFO words to the ARM7 at their send time (fixes boot-time white screens with a generated firmware) - #34
Merged
Conversation
The ARM9 runs each slice first and the ARM7 catches up afterwards, so a word the ARM9 wrote to IPCFIFOSEND mid-slice was pushed into the FIFO at once and the ARM7 could see it up to a slice (2048 cycles) before it was sent. That exposes a boot-time race in the NitroSDK ARM7 SPI_Init (PXI callbacks are registered before the message queue exists): a title that reads the firmware user area through PXI NVRAM right after boot can have its request lost and wait forever on a white screen, seen with Picross DS (Korean release) and a generated firmware. When the running ARM9 (not a DMA) sends a word, hold it in Io::ipc9_pending, end the ARM9 slice there (Scheduler::yield), and push it from Scheduler::fire_due() once the ARM7 has caught up (Io::ipc_deliver), raising the IRQ then. The ARM9's own view of its send FIFO (empty/full flags, send-empty IRQ) counts the held words. ARM7 to ARM9 traffic, IPCSYNC and DSi mode are unchanged, and so is the state format (held words are flushed before saving). DS_IPC_DEFER=0 restores the old behaviour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The ARM9 runs each scheduling slice first and the ARM7 catches up afterwards, so a word the ARM9 writes to
IPCFIFOSENDin the middle of a slice is pushed into the FIFO at once and the ARM7 sees it up to a slice (2048 cycles) before the ARM9 actually sent it. This exposes a boot-time race in the NitroSDK and can leave some titles on a white screen.Symptom
With the generated firmware (no firmware dump), some titles hang on a white screen right after boot; we saw it with Picross DS (Korean release). Stock v3.0.3 reproduces it headlessly (real BIOS, generated firmware,
--rtc-host, JIT). It is a cycle-level timing race: JIT vs. interpreter, moving vs. fixed RTC, fast vs. exact and similar choices decide which runs hang (8 of 48 combinations hung in a sweep before this fix), so it is easy to miss when a firmware dump is present.Cause
Korean titles read the firmware user area from the ARM9 through PXI NVRAM (tag 4) right after boot. In the NitroSDK ARM7
SPI_Init, the PXI receive callbacks are registered before the message queue and its entry ring exist. When the ARM7 sees the word early it handles it before the queue exists:SendMessagefails with EXCLUSIVE, the ARM9 retries, the retry lands in the queue but is then wiped by the ring clearing and answered as a touch-panel result (wrong tag), so the ARM9 waits forever.Fix
When the ARM9 (running, not a DMA) writes
IPCFIFOSEND, hold the word inIo::ipc9_pending, end the ARM9 slice there (Scheduler::yield), and push it into the FIFO fromScheduler::fire_due()once the ARM7 has caught up (Io::ipc_deliver()), raising the IRQ then. The ARM9's own view of its send FIFO (empty/full flags, send-empty IRQ) counts the held words. ARM7→ARM9 traffic, IPCSYNC and DSi are unchanged. The save-state format is unchanged (held words are flushed before saving; a slice boundary never has any).DS_IPC_DEFER=0restores the old behaviour.Results
These were measured on v3.0.3 with the same change:
DS_IPC_DEFER=0brings them back. Super Mario 64 DS (Korean) also booted in all 48 conditions.On current
main(e04b806) I rebased it and compile-checked the changed files with the project's own build flags (macOS, clang); I have not repeated the sweep onmain.🤖 Generated with Claude Code