This project is educational and Open Source. No code is copied from other emulators. Implementation based solely on technical documentation and permitted tests.
Rendering of Real Tiles and Game Name in Title
Summary
This step implements checking real tiles in VRAM and rendering using those tiles when available, replacing the temporary test pattern. Additionally, the game name is added to the emulator's title bar for easy identification in screenshots.
Implemented checks in the PPU to detect when real tiles are loaded into VRAM (checking the first 2048 bytes every 60 frames), tilemap checks to ensure that it points to valid tiles, and diagnostic logs to confirm that the render uses tiles with real data.
The title bar now displays the format "Viboy Color v0.0.2 - [Game Name] - FPS: XX.X", getting the game name from the cartridge header (bytes 0x0134-0x0143).
Hardware Concept
Real Tiles Rendering
The tiles are loaded into VRAM (0x8000-0x97FF) in 2bpp format (2 bits per pixel). Each tile occupies 16 bytes (8 lines × 2 bytes per line). The tilemap (0x9800-0x9BFF or 0x9C00-0x9FFF) contains tile IDs that point to tiles in VRAM. When the actual tiles are loaded, the renderer must read from VRAM and decode the tiles correctly. If the tilemap points to valid tiles with data, the game graphics are rendered.
Fountain: Pan Docs - "Tile Data", "Tile Map", "VRAM"
Cartridge Header
The ROM header (0x0100-0x014F) contains cartridge information, including the game title. The title is at 0x0134-0x0143 (16 bytes, ending in 0x00 or 0x80). The title is decoded as ASCII and may contain non-printable characters. If the title is empty or not printable, "UNKNOWN" is used.
Fountain: Pan Docs - "Cartridge Header", "Title"
Transition from Test Pattern to Real Tiles
Initially, VRAM is empty and a checkerboard is used to confirm that rendering is working. When the game loads real tiles, the VRAM checksum changes significantly (more than 100 non-zero bytes in the first 2048 bytes). The renderer should detect this change and switch from the test pattern to the normal renderer. The tilemap must also be updated to point to the actual tiles.
Fountain: Pan Docs - "VRAM Access", "LCD Timing"
Implementation
1. Game Name in Title Bar
It was modifiedsrc/viboy.pyto get the game title from the cartridge and display it in the window title bar. The title is obtained usingget_header_info()of the objectCartridge, which returns a dictionary with the 'title' field.
If the title is valid (not empty, not "UNKNOWN", and contains printable characters), it is displayed in the format "Viboy Color v0.0.2 - [Title] - FPS: XX.X". If there is no cartridge loaded or the title is invalid, only "Viboy Color v0.0.2 - FPS: XX.X" is displayed.
2. Verification of Real Tiles in VRAM
Added a check onrender_scanline()that every 60 frames (1 second) checks the first 2048 bytes of VRAM (128 tiles) to detect when there are real tiles loaded. If there are more than 100 non-zero bytes, it is assumed that there are real tiles. When the change from empty VRAM to useful VRAM is detected, a log is output[PPU-TILES-REAL].
Verification uses a static variablevram_has_tilesto track the current state and only outputs logs when the state changes, avoiding saturating the logs.
3. Verification of Rendering with Real Tiles
Added a check that, when there are real tiles, verifies that the tileID of the tilemap points to a tile with valid data. This check is executed only in the first 5 frames after detecting real tiles, and only in LY=0, X=0 (first position of the tilemap). Issue logs[PPU-RENDER-VERIFY]when it confirms that tiles with valid data are being rendered.
4. Tilemap Verification
Added a tilemap check that, when there are actual tiles, checks the first 32 bytes of the tilemap (first row) to confirm that it contains non-zero tile IDs. If the tilemap is empty even though there are tiles in VRAM, a warning is issued[PPU-TILEMAP-VERIFY]. This check is executed only in the first 3 frames after detecting real tiles.
Design Decisions
- VRAM Check Frequency: Every 60 frames (1 second) to balance fast detection with low overhead.
- Detection threshold: 100 non-zero bytes in the first 2048 bytes of VRAM. This threshold avoids false positives due to random noise but detects when real tiles are loaded.
- Log limit: Verification logs are limited to the first N frames to avoid flooding the output. Only state changes are always logged.
Affected Files
src/viboy.py- Added code to get game title and show it in title barsrc/core/cpp/PPU.cpp- Added real tile, rendering and tilemap checks
Tests and Verification
The implementation was verified by:
- Successful build: The C++ module was recompiled without errors (only minor warnings for unused variables, corrected later).
- Quick test with pkmn.gb: The emulator runs correctly and the title bar displays the game name.
- Diagnostic logs: The logs
[PPU-TILES-REAL],[PPU-RENDER-VERIFY]and[PPU-TILEMAP-VERIFY]are implemented and ready to verify when full tests are run.
Native Validation: Compiled C++ module validation - C++ code compiles correctly and static functions maintain their state between frames, allowing detection of changes in VRAM.
Note: Full 2.5 minute tests with each ROM (pkmn.gb, tetris.gb, mario.gbc) will run as planned, but basic functionality has been verified.
Sources consulted
- Pan Docs: "Tile Data" - 2bpp format and VRAM storage
- Pan Docs: "Tile Map" - Mapping tile IDs to tiles in VRAM
- Pan Docs: "Cartridge Header" - Header structure and title location
- Pan Docs: "VRAM Access" - Access and timing restrictions
Educational Integrity
What I Understand Now
- Detection of real tiles: You can detect when games load real tiles by checking the VRAM content. A simple checksum (counting non-zero bytes) is enough to detect the change from empty VRAM to VRAM with data.
- Conditional rendering: Rendering should change from the test pattern to the actual tiles when they are available. Periodic verification allows this change to be detected without significant overhead.
- Cartridge header: The game title is stored in the ROM header at a specific location (0x0134-0x0143) and can be decoded as ASCII.
What remains to be confirmed
- visual transition: Visually verify that when the actual tiles load, they render correctly instead of the test pattern.
- Load timing: Confirm that the moment in which the real tiles are detected coincides with when the game loads them according to the logs in Step 0323.
- Valid Tilemap: Verify that the tilemap points to valid tiles when there are real tiles loaded.
Hypotheses and Assumptions
Detection threshold: It is assumed that 100 non-zero bytes in the first 2048 bytes of VRAM is a sufficient threshold to detect real tiles without false positives. This will be based on testing with real ROMs.
Check Frequency: It is assumed that checking every 60 frames (1 second) is sufficient to detect tile loading without significant overhead. Tiles are typically loaded during initialization, so a check every second should be sufficient.
Next Steps
- [ ] Run full tests with the 3 ROMs (2.5 minutes each) to verify the detection of real tiles
- [ ] Visually verify that game graphics are rendered when actual tiles are available
- [ ] Analyze the logs
[PPU-TILES-REAL],[PPU-RENDER-VERIFY]and[PPU-TILEMAP-VERIFY]to confirm the behavior - [ ] If rendering works correctly, proceed to Step 0325: Final Controls and Compatibility Check
- [ ] If the problem persists, look deeper into tile rendering and decoding