This project is educational and Open Source. No code is copied from other emulators. Implementation based solely on technical documentation and permitted tests.
Pokémon Loop Analysis (0x0564)
Summary
This Step analyzes the wait loop in Pokémon Red using the disassembly tool `tools/dump_rom_zone.py`. Step 0265 implemented STAT interrupts by LYC, but the screen is still green and the TileMap shows `0x7F` (white). The GPS shows that the PC is stuck in a loop between `0x0564` and `0x056D`. This Step disassembles that region to understand what the game is waiting for and why it is not moving forward.
Hardware Concept
Wait Loops on Game Boy:Game Boy games use different techniques to wait for events:
- HALT:The CPU enters a low power state and waits for an interrupt. Efficient but requires active IME.
- Active Polling:The CPU runs a loop that constantly checks for a condition (e.g. register read, counter in RAM). Less efficient but works even with IME=0.
- V-Blank Manual Standby:The game reads the LY register (0xFF44) and waits until it is 144 (V-Blank). No interruptions required.
The case of Pokémon Red:The GPS displays `IME:0`, `IE:0D`, `IF:01`, indicating that a V-Blank interrupt is pending but IME is disabled. If the game is in a polling loop, it is checking for some condition that is never met because interrupts are not being processed.
Code Analysis:Disassembling the region where the PC is trapped allows us to see what instructions the game is executing and what condition it is waiting for. This helps us understand if the problem is:
- A loop waiting for an interrupt (but IME=0).
- A loop that waits for a variable in RAM that is updated in an ISR (but the ISR is never executed).
- A loop waiting for a hardware log that is not working correctly.
Fountain:Pan Docs - "Interrupts", "HALT Instruction", "LCD Y-Coordinate (LY)"
Implementation
Improved the `tools/dump_rom_zone.py` tool to correctly disassemble all instructions in a region of ROM, not just the first byte of each line.
Modified components
- tools/dump_rom_zone.py:
- Changed the default values for analyzing the `0x0560-0x0580` region of Pokémon Red.
- Added instruction-by-instruction disassembly that displays all instructions correctly with their operands.
- Improved the output format to show address, bytes and full mnemonic with decoded operands.
Analysis Results
Disassembly revealed the following code in the `0x0564-0x056D` region:
0564 | 21 60 CDs | LD HL, 0xCD60
0567 | CB D6 | SET 2, (HL) ; Set bit 2 of (0xCD60)
0569 | 21 4B CC | LD HL, 0xCC4B
056C | 35 | DEC (HL) ; Decrement byte in (0xCC4B)
056D | 20 F5 | JR NZ, 0x0564 ; If not zero, return to 0564
Loop Interpretation:
- 0x0564: Load `HL` with `0xCD60` (address in RAM).
- 0x0567: `CB D6` = `SET 2, (HL)` - Sets bit 2 of address `0xCD60`.
- 0x0569: Load `HL` with `0xCC4B` (address in RAM).
- 0x056C: Decrements the byte at address `0xCC4B`.
- 0x056D: If the result is not zero, jump back to `0x0564`.
Critical Observations:
- There is NO HALT:The loop is active (polling), it does not wait for interruptions.
- NO LY reading:You are not waiting for V-Blank to manually read `0xFF44`.
- NO DI/EI:Does not change IME in this area.
- There is a counter at 0xCC4B:The loop decrements a counter until it reaches 0.
Hypothesis:
The loop is waiting for the counter at `0xCC4B` to reach 0. This counter is probably initialized somewhere in the code and decremented in an ISR (Interrupt Service Routine). If `IME=0`, the ISR is never executed, the counter is never decremented, and the loop is stuck waiting for the counter to reach 0.
Important addresses:
- 0xCD60:Bit 2 is set. This could be a hardware register or a state variable.
- 0xCC4B:Decrementing counter. It is probably initialized somewhere else and decremented in an ISR.
Modified Files
tools/dump_rom_zone.py: Improved instruction-by-instruction disassembly and changed defaults for parsing the Pokémon Red loop.
Tests and Verification
Command executed:
python tools/dump_rom_zone.py
Result:The disassembly correctly displayed all instructions in the `0x0560-0x0580` region, revealing the active wait loop that decrements a counter at `0xCC4B`.
Code analysis:The loop is waiting for a counter in RAM (`0xCC4B`) to reach 0. This counter is probably updated on an ISR that is not running because `IME=0`.
References
- Pan Docs - "Interrupts"
- Pan Docs - "HALT Instruction"
- Pan Docs - "LCD Y-Coordinate (LY)"
- Game Boy CPU Manual - "Instruction Set"
Next Steps
- Instrument the read/write of `0xCC4B` to see what value it has and if it is being updated.
- Find where the counter is initialized to `0xCC4B` (probably before the loop).
- Look for where the counter is decremented (probably in a V-Blank or Timer ISR).
- Check what is in `0xCD60` and why bit 2 is set.
- Investigate if the problem is that `IME` never activates or if there is another problem with interrupts.