Runtime: writes to D_ENABLEW (0x1000F590) are never visible at D_ENABLER (0x1000F520), hanging any game that suspends the DMAC

Open Beginner friendly
#257 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 5 days

Nobody has claimed this yet.

  • #284 by @luisbraganca — closed without merging

Assessment

Difficulty
1/5
Estimated time
Under an hour
Newbie friendliness
88/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
cpp

Research direction

Open PS2Memory::Store32 where generic MMIO stores land. After a store to address 0x1000F590, also write the same value into m_ioRegisters at 0x1000F520 so D_ENABLEW and D_ENABLER share one register. Done when a DMAC-suspend spin (Ridge Racer V guest loop at 0x0021FDD8) sees bit 0x00010000 on the read port and continues.

Written by the indexing model from the issue text.

Description

What happens

On the EE, D_ENABLEW (0x1000F590) and D_ENABLER (0x1000F520) are the write port and the read port of one single register: the global DMAC suspend bit. You write to one, you read it back from the other.

PS2Memory keeps them as two independent slots of m_ioRegisters, so a write to 0x1000F590 is never observable at 0x1000F520, which keeps returning 0 forever.

Why it hangs

Any code that suspends the DMAC through the normal path and then waits for confirmation spins forever. In Ridge Racer V the guest routine at 0x0021FDD8 (reached from 0x0021FE84 and 0x00220470) does exactly this:

lw   $v1, 0x1000F520      ; already suspended?
and  $v1, 0x00010000
bne  -> return if set
loop:
sw   $a1, 0x1000F590      ; request suspend
lw   $v0, 0x1000F520      ; read it back
and  $v0, 0x00010000
beq  -> retry while the bit stays clear

The bit never comes back. The game froze there, after loading its five IOP modules, starting its audio driver and clearing both framebuffers.

Suggested fix

Mirror the write, where the generic MMIO store lands in PS2Memory::Store32:

// D_ENABLEW (0x1000F590) and D_ENABLER (0x1000F520) are the write and read
// ports of the same DMAC suspend register.
if (address == 0x1000F590u)
{
    m_ioRegisters[0x1000F520u] = value;
}

Two lines. With the mirror in place the spin disappears and the game proceeds.


Found while statically recompiling Ridge Racer V (NTSC-U, SLUS_200.02) with PS2Recomp.
Tested on commit 75d729ce; main was c5a9d02 at the time of writing, one README-only commit ahead.
Host: Windows 11 x64, clang-cl 22.1.3 + Ninja, MSVC toolset 14.51.36231, Windows SDK 10.0.26100.0, CMake 4.2.3.
None of these are specific to this game.

Dominant language
C++
Stars
3.3k
Forks
149
Avg merge
8h 46m
Merged PRs (30d)
1

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from ran-j/PS2Recomp

All issues in ran-j/PS2Recomp

Similar issues

More C++ issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.