This project is educational and Open Source. No code is copied from other emulators. Implementation based solely on technical documentation and permitted tests.
The LY Witness: Is the CPU blind?
Summary
Step 0225 autopsy confirmed that the CPU is stuck in the V-Blank wait loop (`LY=144`) with VRAM completely empty. To understand why the loop never ends, we instrument `MMU::read` to trace all reads to register `LY` (0xFF44). This will allow us to verify if the CPU is reading the register correctly and if the value is increased to 144, or if there is a desynchronization between the CPU and the PPU.
Hardware Concept
The recordLY (LCD Y-Coordinate)in the direction0xFF44contains the current scan line that the PPU is rendering. This record isread onlyand is automatically updated by the PPU every 456 CPU cycles (duration of one scan line).
The LY register has a range of values from 0 to 153:
- 0-143:Visible frame lines (mode 3: Pixel Transfer)
- 144:First line of V-Blank (mode 0: H-Blank/V-Blank)
- 145-153:V-Blank Rest
Game Boy games typically wait for LY to reach 144 before copying graphics data to VRAM, since during V-Blank the PPU is not accessing VRAM and it is safe to write to. The typical wait loop is:
.wait_vblank:
LDH A, (LY) ; Lee LY (0xFF44)
CP 144; Compare with 144
JR NZ, .wait_vblank ; If not 144, repeat
If the CPU never sees `LY=144`, the loop runs indefinitely and the game does not progress. This can occur if:
- PPU is not updating LY correctly
- CPU reads incorrect LY value (memory mapping issue)
- There is a desynchronization between the CPU and the PPU (incorrect timing)
Fountain:Pan Docs - "LCD Y-Coordinate (LY)"
Implementation
We added instrumentation in `MMU::read` to trace all LY register reads. The code is initially commented out to avoid cluttering the console, but can easily be activated by uncommenting a line.
Modified components
- MMU.cpp:Added debug block for LY (0xFF44) that prints the value read each time the CPU accesses the register.
Design decisions
The debug code iscommented by defaultto avoid flooding the console during normal execution. When the debug needs to be activated, the user must:
- Uncomment the line
printf - Redirect output to a file:
python main.py roms/tetris.gb > ly_log.txt 2>&1 - Run for a few seconds and then interrupt with Ctrl+C
- Search the log if the value 144 appears
This strategy allows forensic evidence to be obtained without affecting the emulator's performance during normal development.
Affected Files
src/core/cpp/MMU.cpp- Added debug block for LY (0xFF44) in the methodread()
Tests and Verification
To verify instrumentation:
- Recompile:Execute
.\rebuild_cpp.ps1eitherpython setup.py build_ext --inplace - Activate debug:Uncomment the line
printfinMMU.cpp - Run with redirection:
python main.py roms/tetris.gb > ly_log.txt 2>&1 - Interrupt:Wait 2-3 seconds and press Ctrl+C
- Analyze log:Search
ly_log.txtif the value 144 appears
Interpretation of results:
- If "Read LY: 144" appears:The CPU IS reading the correct value. The problem is somewhere else (perhaps the wait loop has a logical bug).
- If 144 never appears:The PPU is not updating LY correctly, or there is a synchronization problem.
- If the values are repeated a lot:The CPU is reading LY many times within the same line (expected behavior in a wait loop).
Compiled C++ module validation:The code runs directly in C++, without Python overhead, ensuring that readings are plotted in real time.
Sources consulted
- Bread Docs:LCD Y-Coordinate (LY) - 0xFF44
Educational Integrity
What I Understand Now
- LY is a read-only register:The CPU cannot write to 0xFF44, only the PPU updates it automatically.
- V-Blank's wait loop is critical:If the CPU never sees LY=144, the game cannot copy graphics data and the screen remains blank.
- Instrumentation must be non-intrusive:Massive logs can affect performance and distort emulator behavior.
What remains to be confirmed
- Does the CPU actually read LY=144?We need to run the debug and check if the value 144 appears in the log.
- Is there a timing desynchronization?If LY does reach 144 but the CPU does not see it, there may be a synchronization problem between the CPU and PPU.
- Does the wait loop have a logical bug?If the CPU sees LY=144 but the loop does not terminate, the problem is in the loop logic (perhaps the comparison is poorly implemented).
Hypotheses and Assumptions
Main hypothesis:The CPU is reading LY correctly, but the value never reaches 144 because the PPU is not updating LY correctly, or there is a timing desynchronization that causes the CPU to "miss" the exact moment when LY is worth 144.
Assumption:The memory mapping of 0xFF44 in MMU is correct. If it wasn't, the CPU would read an incorrect value or 0x00 constantly.
Next Steps
- [ ] Activate the LY debug and run the emulator for 2-3 seconds
- [ ] Analyze the log to verify if the value 144 appears
- [ ] If 144 appears: Investigate why the wait loop does not terminate (logical bug)
- [ ] If 144 does not appear: Investigate why the PPU does not update LY correctly (timing bug)
- [ ] Compare the pattern of LY values with the expected behavior (0→143→144→153→0)