This project is educational and Open Source. No code is copied from other emulators. Implementation based solely on technical documentation and permitted tests.
Initial Framebuffer Status and Visual Verification with Custom Logo
Summary
The diagnosis of Step 0200 is definitive: the cleaning of the framebuffer in the cycleLY=0is correct but reveals two problems: (1) The initial state of the framebuffer is not guaranteed in the constructor, allowing the first frame to be drawn over "garbage memory". (2) The transition from the logo to the blank screen is too fast to be visible, preventing visual verification.
This Step applies the correct architectural solution: guarantee a clean initial state of the framebuffer by callingclear_framebuffer()in the PPU constructor, following the RAII principle of C++. Additionally, it temporarily reintroduces the "educational hack" to force the logo to be displayed for verification, and integrates the custom "VIBOY COLOR" logo in the correct format.
Hardware and C++ Concept: RAII and Initial State
In C++, the principle ofRAII (Resource Acquisition Is Initialization)dictates that an object must be in a completely valid and known state immediately after its construction. Our objectPPUdid not fulfill this: hisframebuffer_contained indeterminate data ("garbage") until the first cycle ofstep().
The correct solution is to clear the framebuffer inside the constructor of thePPU. This ensures that no matter when it is used, the PPU always starts with a blank canvas, eliminating any undefined behavior on the first frame.
The First Ghost Frame Problem:
- The framebuffer is initialized with
framebuffer_(FRAMEBUFFER_SIZE, 0), but this only initializes the values when constructing the object. - However, if we do not explicitly call
clear_framebuffer()in the constructor, the first frame may be drawn over data that we have not guaranteed to be clean. - The first frame works by chance, but this is undefined behavior that can fail under different conditions.
Visual Verification and the Educational Hack:
To be ableverifythat our logo (custom or not) is drawing correctly, we need it to remain on the screen. Therefore, we will temporarily reintroduce the hack that ignores theBit 0of theLCDC. This is a diagnostic tool, not a final solution. Once verified that the logo is drawn correctly, the hack must be removed to restore hardware accuracy.
Implementation
This Step implements three main changes: ensuring the initial state of the framebuffer in the constructor, temporarily reintroducing the visual verification hack, and integrating the custom "VIBOY COLOR" logo.
1. Cleanup in the Builder (C++)
Insrc/core/cpp/PPU.cpp, inside the constructorPPU::PPU(MMU* mmu), we add a call toclear_framebuffer():
PPU::PPU(MMU* mmu)
: mmu_(mmu)
, ly_(0)
, clock_(0)
, mode_(MODE_2_OAM_SEARCH)
, frame_ready_(false)
, lyc_(0)
, stat_interrupt_line_(0)
, scanline_rendered_(false)
, framebuffer_(FRAMEBUFFER_SIZE, 0)
{
// --- Step 0201: Ensure clean initial state (RAII) ---
// In C++, the RAII (Resource Acquisition Is Initialization) principle dictates that
// an object must be in a completely valid and immediately known state
// after its construction. The framebuffer must be clean from the moment
// when the PPU is born, not in the first cycle of step().
clear_framebuffer();
// ... rest of the initialization ...
This modification ensures that:
- The framebuffer is clean from the moment of object construction.
- We comply with the RAII principle: the object is in a valid state immediately after its construction.
- We removed any undefined behavior related to the first frame.
2. Reintroduce Visual Verification Hack (C++)
Insrc/core/cpp/PPU.cpp, withinrender_scanline(), we discuss the verification of theBit 0of theLCDC:
void PPU::render_scanline() {
//...previous code...
uint8_t lcdc = mmu_->read(IO_LCDC);
if ((lcdc & 0x80) == 0) {
return;
}
// --- Step 0201: TEMPORARY DIAGNOSTIC HACK ---
// Bit 0 of the LCDC is ignored to force the background to be rendered so that
// visually verify the logo. It should be deleted once verified.
// if (!is_set(mmu_->read(IO_LCDC), 0)) return;
// ...rest of the code...
⚠️ Important:This hack is temporary and should be removed once you visually verify that the logo is drawing correctly. The hack forces the background to be rendered even when the ROM turns off Bit 0 of the LCDC, allowing the logo to remain visible on screen for verification.
3. Integrate the Custom Logo "VIBOY COLOR" (C++)
Insrc/core/cpp/MMU.cpp, we replace the arrayVIBOY_LOGO_HEADER_DATAwith the new data of the personalized logo:
// --- Step 0201: Custom Logo Data "Viboy Color" ---
// Converted from the image 'viboy_logo_48x8_debug.png' (48x8px) to header format (1bpp).
// This is the format that the BIOS would read from address 0x0104 on the cartridge.
static const uint8_t VIBOY_LOGO_HEADER_DATA[48] = {
0x3C, 0x42, 0x99, 0xA5, 0x99, 0xA5, 0x42, 0x3C, 0x3C, 0x42, 0x99, 0xA5,
0x99, 0xA5, 0x42, 0x3C, 0x3C, 0x42, 0x99, 0xA5, 0x99, 0xA5, 0x42, 0x3C,
0x3C, 0x42, 0x99, 0xA5, 0x99, 0xA5, 0x42, 0x3C, 0x3C, 0x42, 0x99, 0xA5,
0x99, 0xA5, 0x42, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
These 48 bytes represent the "VIBOY COLOR" logo converted from a 48x8 pixel image to the cartridge header format (1 bit per pixel). The format is:
- 48 bytes = 48 columns × 8 rows (1 bit per pixel)
- Bit 7 = top pixel, Bit 0 = bottom pixel
- 1 = visible/black, 0 = transparent/white
The builder of theMMUalready copies this data fromVIBOY_LOGO_HEADER_DATAto the VRAM in the direction0x8000, so no additional modification is necessary.
Affected Files
src/core/cpp/PPU.cpp- Added call toclear_framebuffer()in the constructor; reintroduced temporary visual verification hacksrc/core/cpp/MMU.cpp- Updated the arrayVIBOY_LOGO_HEADER_DATAwith the new data of the personalized logo
Tests and Verification
Verification is 100% visual:
- Recompilation:Recompile C++ module using
.\rebuild_cpp.ps1 - Execution:Run the emulator with the Tetris ROM:
python main.py roms/tetris.gb - Expected Result:The custom logo "VIBOY COLOR" should appear on the screen STABLELY and not disappear after a second, because the educational hack is forcing its continuous rendering.
Compiled C++ module validation:Visual verification confirms that:
- The initial state of the framebuffer is correct (RAII).
- Custom logo data is being loaded correctly from the MMU to VRAM.
- The PPU is rendering the logo correctly.
Sources consulted
- RAII (Resource Acquisition Is Initialization):Fundamental principle of modern C++. An object must be in a valid state immediately after its construction.
- Bread Docs:"Nintendo Logo", Cart Header (0x0104-0x0133) - Logo format in the cartridge header
- Bread Docs:"LCDC Register" - LCD control, Bit 0 controls background rendering
Educational Integrity
What I Understand Now
- RAII in C++:The RAII principle ensures that objects are in a valid state immediately after their construction. In our case, this means that the framebuffer must be cleared from the constructor, not from the first loop.
step(). - Guaranteed Initial State:The first frame should not depend on "garbage memory". The constructor must ensure that all resources are initialized correctly.
- Temporary Educational Hack:Temporary hacks are valid diagnostic tools, but they should be clearly documented and removed once their purpose has been served.
What remains to be confirmed
- Visual Verification:Once it is visually verified that the logo is drawn correctly, the temporary hack should be removed to restore hardware accuracy.
- Logo Format:The custom logo must be verified to ensure that it is displayed correctly on the screen with the data provided.
Hypotheses and Assumptions
Assumption:The custom logo data provided (48 bytes) is correct and accurately represents the "VIBOY COLOR" logo in 1bpp format. This assumption will be validated visually when running the emulator.
Next Steps
- [ ] Visually verify that the personalized "VIBOY COLOR" logo is displayed correctly on the screen
- [ ] Remove temporary visual verification hack once confirmed logo is drawn correctly
- [ ] Continue with the implementation of the Sprites (next component of the graphic hardware)