⚠️ 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.

MMU-PPU Connection Verification and Debug Cleaning

Date:2025-12-18 StepID:0041 State: Verified

Summary

It was verified and confirmed that theconnection between MMU and PPUfor reading the registerL.Y.(0xFF44) is correctly implemented. The existing code already handled correctly reading LY from the PPU when the game accesses address 0xFF44. Prints were removed temporary debug files that had been added in the previous step (diagnostic probe) to clean code and improve performance. The testtest_ly_read_from_mmuconfirms that the functionality is operational.

Hardware Concept

The recordL.Y.(Current line) in the direction0xFF44it's a record ofread onlyindicating which scan line is currently being drawn (range 0-153). The games constantly read this log to sync and know when can safely refresh VRAM (during V-Blank, when LY >= 144).

In real hardware, the LY register is directly connected to the PPU (Pixel Processing Unit), not to RAM memory. When the software reads 0xFF44, the hardware returns the current value of LY from the PPU, not from a memory cell. If the game reads an incorrect value (for example, 0 constant), you can stay in an infinite loop waiting for LY to change.

Fountain:Pan Docs - LCD Timing, LY Register (0xFF44)

Implementation

It was verified that the existing implementation insrc/memory/mmu.pynow drives correctly LY reading:

# In read_byte(), lines 232-237
if addr == IO_LY:
    if self._ppu is not None:
        return self._ppu.get_ly() & 0xFF
    else:
        return 0

The PPU-MMU connection is successfully established onsrc/viboy.pythrough the methodset_ppu()after creating both instances (avoiding circular dependencies).

Debug code cleanup

The temporary debug prints that had been added in the previous step were removed:

  • Removed:Print "DEBUG PROBE" every 1000 iterations (lines 313-325)
  • Removed:Safety limit with emergency prints (lines 327-332)
  • Removed:Print of "V-BLANK DETECTED" (lines 348-354)
  • Kept:Heartbeat withlogger.info()every 60 frames (line 364)

These prints were slowing down execution and are no longer necessary now that it has been confirmed that the MMU-PPU connection is working correctly.

Affected Files

  • src/viboy.py- Removed temporary debug prints from the main loop

Tests and Verification

The existing test that verifies the LY reading from the MMU was executed:

  • Command executed: pytest tests/test_ppu_timing.py::TestPPUTiming::test_ly_read_from_mmu -v
  • Around:Windows, Python 3.13.5
  • Result: PASSED(1 passed in 0.25s)
  • What is valid:
    • The MMU can read LY from the PPU through register 0xFF44
    • The value returned by MMU matches the internal value of the PPU
    • The value changes correctly when the PPU advances lines

Test code:

def test_ly_read_from_mmu(self) -> None:
    """Test: The MMU can read LY from the PPU through register 0xFF44."""
    mmu = MMU(None)
    ppu = PPU(mmu)
    mmu.set_ppu(ppu)
    
    # Initially LY must be 0
    assert mmu.read_byte(0xFF44) == 0
    
    # Advance some lines
    ppu.step(456 * 5) # 5 lines
    
    #LY must be 5
    assert ppu.get_ly() == 5
    
    # The MMU must return the same value
    assert mmu.read_byte(0xFF44) == 5

Why this test demonstrates something about the hardware:This test verifies that when the software (game) reads address 0xFF44, gets current LY value from PPU, not from the RAM memory. This is critical because games depend on this value to sync and know when they can safely upgrade VRAM. If the MMU returned an incorrect value (e.g. always 0), the game would stay in an infinite loop waiting for LY to change.

Sources consulted

Educational Integrity

What I Understand Now

  • LY register (0xFF44):It is a read-only register connected directly to the PPU. When the software reads this address, the hardware returns the current value of LY from the PPU, not from RAM.
  • MMU-PPU connection:The MMU needs a reference to the PPU in order to return the correct value of LY when 0xFF44 is read. This connection is established after creating both instances to avoid circular dependencies.
  • Critical importance:If the game reads an incorrect value of LY (for example, always 0), it may sit in an infinite loop waiting for LY to change, causing the "eternal white screen" or "emulator frozen" symptom.

What remains to be confirmed

  • Behavior on real hardware:According to the documentation, LY is read-only and writing to it has no effect. This is already implemented correctly in the code (it is silently ignored).
  • Exact timing:The PPU advances LY every 456 T-Cycles. This is implemented and verified by testing, but may need fine-tuning if synchronization issues are detected in real games.

Hypotheses and Assumptions

Main hypothesis:The "eternal white screen" issue observed in the previous step (0040) NOT due to an MMU-PPU connection problem, since the code is correctly implemented and the tests pass. The problem is probably caused by another factor, such as:

  • The game is waiting for a V-Blank interrupt that is not processing correctly
  • The game is waiting for a specific time to pass (counting cycles) before continuing
  • There is some other I/O register that is not implemented correctly

This hypothesis will be validated in later steps when the emulator is tested with real ROMs and observe the detailed behavior.

Next Steps

  • [ ] If the "white screen" issue persists, investigate V-Blank interrupt handling
  • [ ] Verify that interrupts are processed correctly when IME is enabled
  • [ ] Test the emulator with test ROMs to validate the complete behavior
  • [ ] Continue to implement missing features as needed