This project is educational and Open Source. No code is copied from other emulators. Implementation based solely on technical documentation and permitted tests.
The State of GENESIS (Part 2): VRAM Pre-Loading with the Nintendo Logo
Summary
The emulator is fully synchronized and all hardware components are implemented, but the screen is still blank. The final diagnosis reveals that we are incorrectly simulating the Post-BIOS state: we initialize the CPU and hardware registers, butwe do not simulate the main action of the Boot ROM, which is to pre-load the graphic data of the Nintendo logo into the VRAM. The game assumes that the logo is already there and, upon finding the VRAM empty, enters a crash state.
This Step implements the "Genesis" state of the VRAM, modifying the MMU constructor to pre-load the tilemap data and Nintendo logo tiles into the correct VRAM addresses (0x8000and0x9904). With this implementation, the emulator should finally display the Nintendo logo on the screen, thus completing the full simulation of the Post-BIOS state.
Expected Result:With the VRAM properly initialized, the CPU should execute the boot code without errors, and the PPU should read the logo data from the VRAM and display it on the screen, allowing the game to continue with the logo animation.
Hardware Concept: Post-BIOS Visual Memory
When the Boot ROM gives control to the cartridge inPC=0x0100, you have not only initialized the CPU and peripheral registers, but also left avisual "footprint"in the VRAM. You have copied the Nintendo logo graphic data from the cartridge header to VRAM and configured the tilemap to display it on the screen. Our emulator must replicate this exact memory state so that the game can continue where the BIOS left off.
The Boot ROM Process:
- Logo Reading:The Boot ROM reads the 48 bytes of the Nintendo logo from the cartridge header (addresses
0x0104to0x0133). These bytes represent the graphic data of the tiles that make up the logo. - Copy to VRAM:The Boot ROM copies this data to VRAM, organizing it as 8x8 pixel tiles (16 bytes per tile). Tiles are placed in the tile data region of VRAM (usually starting at
0x8000either0x8010). - Tilemap configuration:The Boot ROM configures the tilemap (the region of VRAM that defines which tiles to display at each position on the screen) to display the logo centered at the top. The tilemap is in the region
0x9800-0x9BFF(either0x9C00-0x9FFF, depending on the LCDC configuration). - Display:With the tiles loaded and the tilemap configured, the PPU can read the VRAM and render the logo on the screen.
The Fundamental Problem:Our emulator does not run a Boot ROM. Instead, we initialize the registers and assume that the game will copy the graphics. However, the game code inPC=0x0100 does not copy the logo. Assume that the logoit's already there, set by a BIOS that we never run. What the game does is probably continue the logo scroll animation or simply wait for it to finish before displaying its own title screen. You are animating an empty VRAM, resulting in a blank screen.
Nintendo Logo Data:The 48 bytes of the logo are found in the header of all Game Boy cartridges (addresses0x0104-0x0133). These bytes are standardized and identical in all official games. The Boot ROM reads these bytes and copies them to VRAM, organizing them as graphical tiles.
Fountain:Pan Docs - "Boot ROM Behavior", "Nintendo Logo", "Cart Header (0x0104-0x0133)"
Implementation
The implementation consists of adding static arrays with the Nintendo logo data and modifying the constructor ofMMUso that it copies this data to the VRAM during initialization, thus simulating what the Boot ROM would do before giving control to the cartridge.
Modified components
src/core/cpp/MMU.cpp: Two static arrays were added with the logo data (NINTENDO_LOGO_DATAandNINTENDO_LOGO_TILEMAP) and the constructor was modified to copy this data to VRAM at the correct addresses.
Implemented code
Static arrays with logo data were added to the beginning of the fileMMU.cpp:
// --- Step 0197: Nintendo Logo Data (Post-BIOS) ---
// Boot ROM copies logo data from cartridge header (0x0104-0x0133)
// to VRAM. These are the standard 48 bytes of the Nintendo logo found
// in the header of all Game Boy cartridges.
// Source: Pan Docs - "Nintendo Logo", Cart Header (0x0104-0x0133)
static const uint8_t NINTENDO_LOGO_DATA[48] = {
0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B,
0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D,
0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E,
0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99,
0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC,
0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E
};
// Tilemap of the Nintendo logo on the screen (0x9904-0x9927)
// The Boot ROM configures the tilemap to show the logo centered at the top.
// 12 tiles in a row (0x01 to 0x0C) followed by empty tiles (0x00).
// Source: Pan Docs - "Boot ROM Behavior", Tile Map Layout
static const uint8_t NINTENDO_LOGO_TILEMAP[36] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, // Row 1: Logo tiles
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Row 2: Empty
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Row 3: Empty
};
The constructor was modifiedMMUTo copy this data to VRAM:
// --- Step 0197: Pre-load VRAM with Nintendo logo (Post-BIOS) ---
// Boot ROM copies logo data from cartridge header (0x0104-0x0133)
// to VRAM. These 48 bytes form 3 tiles (16 bytes each).
// The Boot ROM also configures the tilemap to show the logo centered.
// Source: Pan Docs - "Boot ROM Behavior", "Nintendo Logo"
// Copy logo data to VRAM (0x8000-0x802F)
// The 48 bytes of the logo are organized as 3 consecutive tiles
for (size_t i = 0; i< sizeof(NINTENDO_LOGO_DATA); ++i) {
memory_[0x8000 + i] = NINTENDO_LOGO_DATA[i];
}
// Copiar el tilemap a la VRAM (0x9904-0x9927)
// El tilemap configura qué tiles mostrar en la pantalla (12 tiles del logo en la primera fila)
for (size_t i = 0; i < sizeof(NINTENDO_LOGO_TILEMAP); ++i) {
memory_[0x9904 + i] = NINTENDO_LOGO_TILEMAP[i];
}
Design decisions
- Pre-load in the Builder:Logo data is copied to VRAM during MMU construction, ensuring that VRAM is pre-loaded before any game code is executed. This replicates the behavior of the Boot ROM.
- Standard Header Data:We use the standard 48 bytes of the Nintendo logo found in the header of all cartridges (0x0104-0x0133). These bytes are identical in all official games.
- VRAM addresses:The logo data is copied to
0x8000(tile data region) and the tilemap is set to0x9904(tilemap region), which corresponds to the first row of tiles visible on the screen. - Static Arrays:Logo data is stored as constant static arrays, avoiding any dynamic initialization overhead.
Affected Files
src/core/cpp/MMU.cpp- Added static arrays with logo data and modified constructor to pre-load VRAMdocs/bitacora/entries/2025-12-20__0197__state-genesis-part-2-pre-load-vram-logo-nintendo.html- New log entrydocs/bitacora/index.html- Updated with new entryREPORT_PHASE_2.md- Updated with Step 0197
Tests and Verification
This implementation does not require additional unit tests, since the validation is purely visual: the Nintendo logo should appear on the screen when the emulator is run with a game. However, you can verify that the VRAM is pre-charged by reading the corresponding addresses after initialization.
Compilation Verification
The C++ module compilation completed successfully:
python setup.py build_ext --inplace
The module compiled without errors, confirming that the code syntax is correct.
Expected Validation
Validation of this implementation is visual:
- Run the emulator:
python main.py roms/tetris.gb - Expected result:The Nintendo logo should appear on the screen, indicating that the VRAM was successfully pre-loaded and that the PPU can read and render the data.
- Code continuation:The game should continue running as it now finds the logo in VRAM as expected.
Note:If the logo does not appear, it may be necessary to adjust the VRAM addresses or the tilemap format, depending on how the actual Boot ROM organizes this data.
Sources consulted
- Bread Docs:Game Boy Pan Docs- "Boot ROM Behavior" section
- Bread Docs:Game Boy Pan Docs- "Nintendo Logo" section
- Bread Docs:Game Boy Pan Docs- "Cart Header (0x0104-0x0133)" section
- Bread Docs:Game Boy Pan Docs- Section "VRAM Tile Data", "Tile Map"
Educational Integrity
What I Understand Now
- Post-BIOS Complete Status:The Post-BIOS status not only includes the register values, but also the entire memory status, especially VRAM. The Boot ROM not only initializes the records, but also performs specific actions (such as copying the logo to VRAM) that the game code expects to already be completed.
- Boot ROM as Full Initializer:The Boot ROM is not only a registry initialization program, but also prepares the visual state of the system (the logo) before handing over control to the game. This visual state is an integral part of the Post-BIOS state.
- Game Code Dependencies:The game code assumes that certain tasks have already been completed by the Boot ROM. If these tasks are not completed, the game may crash in subtle ways (such as animating an empty VRAM instead of displaying an explicit error).
What remains to be confirmed
- Exact Organization of Tiles:The Boot ROM can organize the 48 bytes of the logo differently than we place them. It may be necessary to adjust the directions or the tilemap format depending on the visual results.
- Tilemap configuration:The tilemap may require additional settings (such as offset or exact position) that we have not considered yet.
Hypotheses and Assumptions
Main Assumption:We assume that copying the 48 bytes of the logo to0x8000and set the tilemap to0x9904It will replicate the state that the Boot ROM would leave. This assumption is based on the Pan Docs documentation, but may require fine adjustments depending on visual results.
Assumption about the Tilemap:We assume that the logo tilemap consists of 12 consecutive tiles (0x01 to 0x0C) in the first row. If the logo does not appear correctly, it may be necessary to review this organization.
Next Steps
- [ ] Visually verify that the Nintendo logo appears on the screen
- [ ] If the logo does not appear, adjust the VRAM addresses or the tilemap format
- [ ] Verify that the game continues running after displaying the logo
- [ ] If necessary, implement the logo animation (scroll down) if the game expects it