This project is educational and Open Source. No code is copied from other emulators. Implementation based solely on technical documentation and permitted tests.
X-ray Mode: Forced Rendering
Summary
Implemented "X-Ray Mode", a diagnostic tool that forces rendering from VRAM even when the LCD is off (LCDC bit 7=0). This allows you to see what content is in VRAM during times when the game quickly turns off the LCD, which is especially useful for diagnosing boot problems in games like Pokémon Red that turn the LCD on and off in milliseconds.
Hardware Concept
On the real Game Boy, when Bit 7 of the LCDC register is 0, the LCD is completely disabled and nothing is rendered. The PPU (Picture Processing Unit) hardware simply does not generate video signals, and the screen displays a blank or off state.
During the startup of many games, especially those that have initialization sequences complex, the game may turn on the LCD briefly (LCDC=0x80), check the status, and then turn it off again (LCDC=0x00) to make additional settings before displaying the final screen. This behavior is normal and allows the game to configure the VRAM, paddles, sprites and other components without the user seeing incomplete or corrupted content.
However, when we are debugging an emulator, it can be very useful to see what is in the VRAM even when the LCD is off. This allows us to understand:
- If VRAM is loading correctly (DMA, manual copies)
- If the tiles are in the expected directions
- If the tilemap has valid data
- What the game is seeing (or what it would try to see) when you turn on the LCD
"X-Ray Mode" is a diagnostic tool that does NOT represent actual behavior of the hardware. It is purely educational and allows you to "see through" the LCD status to inspect the contents of VRAM at any time.
Fountain:Pan Docs - LCD Control Register, PPU States
Implementation
Function changedrender_frame()insrc/gpu/renderer.pyfor
implement X-Ray Mode. Instead of returning immediately when the LCD is off,
We now force an LCDC configuration that allows the contents of VRAM to be rendered.
Change made
Thereturnearly whenlcdc_bit7 == 0and was replaced
with logic that forces an appropriate LCDC value for rendering. Specifically:
- Forced LCDC: 0x91
- Bit 7 = 1: LCD ON (forced to allow rendering)
- Bit 4 = 1: Tile Data from 0x8000 (unsigned addressing)
- Bit 3 = 0: Tile Map from 0x9800
- Bit 0 = 1: BG Display ON
- It is established
lcdc_bit7 = Trueso that the rest of the rendering code work normally - A debug message is logged indicating that X-Ray Mode is being used
Design decisions
LCDC=0x91 was chosen as the forced configuration because:
- It is a common setting that many games use during initialization
- Allows you to render both the background (Background) and use tiles from 0x8000
- It's a "reasonable" setting that probably represents what the game would try see if the LCD was on
Important note:This is a temporary diagnostic tool. does not represent the actual behavior of the hardware and should only be used for debugging. In a full emulator, when the LCD is off, nothing should be rendered.
Affected Files
src/gpu/renderer.py- Modification inrender_frame()to implement X-ray Mode
Tests and Verification
This implementation is a diagnostic tool and does not require formal unit tests, since it does not represent real hardware behavior. It was validated by running the emulator with Pokémon Red.
Test run with Pokémon Red
Command executed: python main.py pkmn.gb
Around:Windows 10, Python 3.13.5, pygame-ce 2.5.6
ROM:Pokémon Red (user-contributed ROM, not distributed)
Console output:
pygame-ce 2.5.6 (SDL 2.32.10, Python 3.13.5)
Viboy Color - System Started
==================================================================
📦 Loaded cartridge:
Title: POKEMON RED
Type: 0x13
ROM: 1024KB
RAM: 32KB
Total size: 1048576 bytes
🖥️ CPU initialized:
PC = 0x0100
SP = 0xFFFE
✅ System ready to run
Press Ctrl+C to stop
WARNING: 🔥 HACK: Forcing BGP 0x00 -> 0xE4 for visibility (the game tried to write white palette, we forced standard palette)
Visual result:
Observed screen:Completely white screen
Interpretation:The white screen indicates that:
- X-Ray Mode is working correctly (it is forcing rendering when LCD is off)
- VRAM is empty or contains only zeros (all tiles have color index 0)
- With the standard palette (BGP=0xE4), color index 0 corresponds to white, so an empty VRAM is rendered as a white screen
- The BGP hack is active (warning is displayed), but it doesn't help because there is no data in VRAM to render
Diagnostic conclusions:
State: draft- Complete diagnosis, pending solution implementation
Seeing a white screen with X-ray Mode active reveals that the problem is not just timing. on/off of the LCD, but the VRAM is never being loaded with data. This suggests that:
- Main problem:VRAM is not being populated with tiles/logos during initialization
- Possible causes:
- DMA (Direct Memory Access) is not working correctly
- Manual copies of data to VRAM are not running
- Game initialization code is not running completely
- There is a CPU crash or error before the game can load graphics
Next diagnostic step:Check if the game code is executing the instructions that copy data to VRAM. This may require logging of writes to VRAM or execution step by step to see where the initialization stops.
Legal note:The Pokémon Red ROM is provided by the user for local testing. It is not distributed or included in the repository.
Sources consulted
- Pan Docs: LCD Control Register (gbdev.io/pandocs/LCDC.html)
- Pan Docs: PPU States (gbdev.io/pandocs/STAT.html)
Note: X-ray Mode is its own diagnostic tool and is not documented in official specifications, since it does not represent real hardware behavior.
Educational Integrity
What I Understand Now
- LCD control:LCDC Bit 7 controls whether the LCD is on or off. When turned off, the actual hardware does not generate video signal, but the VRAM is still accessible and may contain valid data.
- Boot timing:Many games turn the LCD on and off during play. initialization to configure the hardware without showing partial content to the user.
- Visual debugging:To understand what is happening in the emulator, it can be useful to display the contents of VRAM even when the LCD is off, although this does not represents the actual behavior of the hardware.
What remains to be confirmed
- Optimal Forced LCDC Settings:0x91 was chosen as the default value, but it might not be the most appropriate setting for all games. Could be useful make this value configurable or try to "guess" the settings better than the game would use if the LCD was on.
- Impact on performance:Rendering when LCD is off consumes unnecessary resources. In the future it should be optional or disabled when not needed debugging.
Hypotheses and Assumptions
Main hypothesis:If Pokémon Red (or another game) displays a blue screen or blank screen, it could be because:
- The game turns on the LCD briefly but turns it off immediately because it is not receiving the Expected V-Blank interruption
- VRAM not loaded correctly (DMA or manual copies issue)
- The timing of interruptions does not match what the game expects
X-Ray Mode allows you to view the VRAM at these critical moments to determine which of these hypotheses is the correct one.
Next Steps
With X-Ray Mode active, VRAM was confirmed to be empty (white screen). This completely changes the approach to diagnosis:
- [x] Run Pokémon Red with X-Ray Mode active and observe what content is in the VRAM→ Result: White screen (VRAM empty)
- [ ] Check if the game code is executing the instructions that copy data to VRAM
- Implement logging of writes to VRAM (0x8000-0x9FFF) to see if data is being written
- Check if DMA (Direct Memory Access) is working correctly
- Run step by step to identify where initialization stops before loading graphics
- [ ] If the code is not running: check for a CPU hang or error before reaching the load instructions
- [ ] If code is running but VRAM is not filling: check DMA implementation and manual copies to VRAM
- [ ] Once the problem has been identified and corrected, disable X-ray Mode to return to the real behavior of the hardware