Skip to content

Simulate ARM9 RAM starvation to fix DSi PictoChat - #2744

Open
puhitaku wants to merge 2 commits into
melonDS-emu:masterfrom
puhitaku:puhitaku/arm9-starve-sim
Open

Simulate ARM9 RAM starvation to fix DSi PictoChat#2744
puhitaku wants to merge 2 commits into
melonDS-emu:masterfrom
puhitaku:puhitaku/arm9-starve-sim

Conversation

@puhitaku

@puhitaku puhitaku commented Sep 7, 2026

Copy link
Copy Markdown

Fixes #707

After some investigation, it turns out the data race between ARM7 and ARM9 was the cause of "Communication Error" in DSi PictoChat.

photo_6120577969219637592_w

Chain of events

  1. After starting PictoChat, ARM9 OS init sets EXMEMCNT bit 15 (so ARM7 has main RAM priority). After that, ARM7 startup code waits for ARM9's "go" bit and zero-fills main RAM with CpuFastSet call, one 192 KB chunk per VBlank.
  2. Meanwhile, ARM9 creates its heap about 50 ms after the first chunk and allocates buffers. The following analysis has big inference though, in the actual hardware, ARM9 will be starved of - or gets heavily arbitrated to access, at least - main RAM every time ARM7 zero-fills a chunk. In melonDS, ARM9 seems able to access it regardless of priority. So ARM9 inits the heap while ARM7 is zero-filling the same region.
  3. ARM7 reaches the heap's free list block header after ARM9 prepared it. And then ARM7 overwrites it.
  4. PictoChat allocates the wireless system buffer (size 0xf00). The allocator walks the free list, finds the broken header, and returns NULL as a failure.
  5. PictoChat shows the failure dialog and then exits.

Fix

Instead of emulating bus arbitration, I implemented a simulation of starvation. When ARM7 issues a BIOS CpuSet/CpuFastSet of 4 KB or more into main RAM while EXMEMCNT gives it priority, UpdateARM9Starve() stops the ARM9. ARM7 consumes the bytes counter ARM7BytesToWrite, and the ARM9 resumes when the transfer's bytes are written.

Caveats

  • The ARM9 is stopped completely for the transfer, not getting arbitrated.
  • 4 KB threshold is a judgement call to skip stopping ARM9 for small transfers, so a regression may be expected
  • Works only in interpreter mode
  • The second commit saves ARM7BytesToWrite alongside CPUStop; since that changes the NDS section layout, SAVESTATE_MAJOR is bumped to 15.

Testing

  • PictoChat now reaches the room chooser and hosts a room, from both the DSi Menu and Unlaunch
  • Savestates taken mid-starvation reload correctly
  • Brief play test passed: Animal Crossing: Wild World [J], Saeki Chizu Shiki - Yumemihada [J]

Refs

I've reviewed and modified every line myself after coding agent figures it out, and this PR is hand-written, but I'm pretty new to GBA/NDS world so things may appear strange. I'm eager to fixup those after a review. Thanks!

With ARM7 main RAM priority (EXMEMCNT bit 15), a BIOS CpuSet/CpuFastSet from the ARM7
into main RAM keeps the bus busy for the whole transfer and the ARM9 is starved. melonDS
has no bus arbitration, so the ARM9 kept running at full speed.

The TWL SDK relies on the starvation: its ARM7 startup zero-fills 0x02000000-0x022A0000
in 192KB chunks (one per VBlank) after the ARM9 title has started. Without it the ARM9
builds its heap inside the region being cleared and loses heap metadata. DSi PictoChat
then fails WM_Init with a NULL buffer and shuts down with "Communication error".

UpdateBusStarve() stops the ARM9 (CPUStop_ARM9BusStarve) when the ARM7 starts such a
transfer of at least 4KB, and DecreaseARM7BytesToWrite() releases it once the transfer's
bytes have been written. Interpreter mode only, at present.
CPUStop_ARM9BusStarve is saved with CPUStop, but ARM7BytesToWrite, the write count
that releases it, was not. A state saved while the ARM9 is starved would leave it
stopped forever after loading. Save the count too. This changes the layout of the NDS
section, so bump the savestate major version.
@RSDuck

RSDuck commented Sep 7, 2026

Copy link
Copy Markdown
Member

This is a hack hack specific to a single software, not sure whether we want to merge this.

@puhitaku

puhitaku commented Sep 9, 2026

Copy link
Copy Markdown
Author

Per-app hack switch may be a viable option I guess, like other emulators do, while I'm not sure that kind of feature is present in melonDS though. @RSDuck does it sound good to you?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pictochat on dsi wont load

2 participants