⚠️ Clean-Room / Educational

This project is educational and Open Source. No code is copied from other emulators. Implementation based solely on technical documentation and permitted tests.

Zero Zone Dump (ROM Disassembler)

Date:2025-12-23 StepID:0249 State: draft

Summary

Step 0248 revealed that the game runs `EI` (Enable Interrupts) at `0x033A`, but the GPS shows `IME:0` permanently. Forensics identified an infinite loop at `0x2B24` and HRAM writes at `0x2BA3`. This Step creates a ROM dump tool to disassemble the critical region (`0x2B20` - `0x2BC0`) and understand exactly what the game code is doing in that region.

Hardware Concept

The Game Boy stores the game code in the cartridge's ROM. CPU (LR35902) reads instructions from ROM and executes them sequentially. When an emulator gets stuck in an infinite loop, it is crucial to be able to examine the machine code (opcodes) in that area to understand the logic of the program.

Disassembled:The process of converting machine code (bytes) into readable instructions (mnemonics) It's called disassembly. Each opcode has a specific meaning according to the LR35902 processor specification.

Flow Analysis:By examining a sequence of opcodes, we can reconstruct the control flow of the program: conditional jumps, loops, calls to subroutines, etc. This is essential to understand why a program gets stuck.

Implementation

The script was createdtools/dump_rom_zone.pythat:

  • Read a specific area of ​​the ROM (default: `0x2B20` - `0x2BC0`)
  • Displays bytes in hexadecimal format with addresses
  • Try disassembling the instructions using a Game Boy opcode dictionary
  • Display operands and calculate destination addresses for relative jumps

Created components

  • tools/dump_rom_zone.py: Main dump script with basic disassembly
  • tools/analyze_critical_zone.py: Analysis script that interprets the dump results

Disassembler Features

  • Opcode Dictionary:Complete mapping of the 256 possible opcodes of the LR35902
  • Length detection:Automatically identifies whether an instruction is 1, 2, or 3 bytes
  • Jump calculation:For relative jumps (`JR r8`), calculate the destination address
  • Readable format:Displays address, hexadecimal bytes, ASCII representation and mnemonic

Affected Files

  • tools/dump_rom_zone.py- ROM dump script with basic disassembly (new)
  • tools/analyze_critical_zone.py- Critical zone analysis script (new)

Tests and Verification

The script ran successfully on the Tetris ROM:

$ python tools/dump_rom_zone.py roms/tetris.gb 0x2B20 0x2BC0

==================================================================================
📦 ROM Dump: tetris.gb
📍 Zone: 0x2b20 - 0x2bc0 (160 bytes)
==================================================================================

2B20 | 23 F0 8C E0 94 7E FE FF 28 C7 FE FD 20 0E F0 8C | #....~..(... ... | INC HL
2B30 | EE 20 E0 94 23 7E 18 08 13 13 18 E4 FE FE 28 F8 | . ..#~........(. | XOR d8
2B40 | E0 89 F0 87 47 1A 4F F0 8B CB 77 20 06 F0 90 80 | ....G.O...w .... | LDH (a8),A
2B50 | 89 18 0A 78 F5 F0 90 47 F1 90 99 DE 08 E0 93 F0 | ...x...G........ | ADC A,C
2B60 | 88 47 13 1A 13 4F F0 8B CB 6F 20 06 F0 91 80 89 | .G...O...o ..... | ADC A,B
2B70 | 18 0A 78 F5 F0 91 47 F1 90 99 DE 08 E0 92 E5 F0 | ..x...G......... | JR r8
2B80 | 8D 67 F0 8E 6F F0 95 A7 28 04 3E FF 18 02 F0 93 | .g..o...(.>..... | ADC A,L
2B90 | 22 F0 92 22 F0 89 22 F0 94 47 F0 8B B0 47 F0 8A | "...""...G...G.. | LD (HL+),A
2BA0 | B0 22 7C E0 8D 7D E0 8E E1 C3 20 2B 68 2C 6C 2C | "|..}.... +h,l, | OR B
2BB0 | 70 2C 74 2C 78 2C 7C 2C 80 2C 84 2C 88 2C 8C 2C | p,t,x,|,.,.,.,., | RH (HL),B

==================================================================================
✅ Dump completed: 160 bytes
==================================================================================

Key Findings from the Dump

  • 0x2B20: INC HL- Start of loop, increment HL pointer
  • 0x2B24: LD A,(HL)followed byCP 0xFF- Compare the byte in (HL) with 0xFF
  • 0x2B96: LD (HL+),A- Write A to (HL) and increment HL (copy routine part)
  • 0x2BA3: LDH (FF8D),A- Write to HRAM[0xFF8D] (configuration)
  • 0x2BA9: JP 2B20 - ⚠️ UNCONDITIONAL JUMP TO THE START (INFINITE LOOP)

Sources consulted

Educational Integrity

What I Understand Now

  • Confirmed Infinity Loop:The code at `0x2BA9` executes `JP 2B20`, unconditionally jumping to the start of the loop at `0x2B20`. This confirms that the game is stuck in a loop.
  • Output Condition:The code in `0x2B24` compares the byte in (HL) with `0xFF`. If it encounters `0xFF`, it probably exits the loop (there is a backward `JR Z`). If `0xFF` is never found, the loop continues indefinitely.
  • Copy Routine:The code in `0x2B96` uses `LD (HL+),A` to copy data. This suggests that the game is trying to copy data from a source to a destination.
  • Configuration in HRAM:The code writes to `HRAM[0xFF8D]` and other HRAM registers, suggesting that it is setting parameters for some operation.

What remains to be confirmed

  • What data does the loop read?We need to check what address HL is pointing to when the loop starts and what data it expects to find.
  • Why does it never find 0xFF?If the loop expects to find `0xFF` as a terminator, why does it never find it? Is the data incorrectly initialized?
  • Does it depend on DMA or interrupts?The game could be waiting for DMA or an interrupt to modify the data the loop is reading.
  • Is there a flag that is never activated?The code could be waiting for some flag in memory to change, but if that flag never changes, the loop never ends.

Hypotheses and Assumptions

Main Hypothesis:The game is in a loop that reads data from an address (pointed by HL) and expects to find `0xFF` as the terminator. If `0xFF` is never found, the loop continues indefinitely. The game probably waits for DMA or an interrupt to modify that data or set a flag, but since those operations don't work correctly in the emulator, the loop never ends.

Assumption:The code at `0x2B96` (LD (HL+),A) is part of a copy routine that should run from HRAM (as is common in OAM DMA routines). If that routine is never executed, the data is never copied and the loop never finds the `0xFF` terminator.

Next Steps

  • [ ] Check which address HL points to when the loop starts (register tracking)
  • [ ] Check what data is at that address and if it contains the `0xFF` terminator
  • [ ] Check if the game expects DMA to modify that data
  • [ ] Check if the game waits for an interruption that modifies a flag
  • [ ] Compare the behavior with a reference emulator to confirm the hypothesis
  • [ ] Implement HL tracking during the loop to see what data it is reading