Este proyecto es educativo y Open Source. No se copia código de otros emuladores. Implementación basada únicamente en documentación técnica y tests permitidas.
Estado Inicial del Framebuffer y Verificación Visual con Logo Personalizado
Resumen
El diagnóstico del Step 0200 es definitivo: la limpieza del framebuffer en el ciclo LY=0 es correcta pero revela dos problemas: (1) El estado inicial del framebuffer no está garantizado en el constructor, permitiendo que el primer fotograma se dibuje sobre "memoria basura". (2) La transición del logo a la pantalla en blanco es demasiado rápida para ser visible, impidiendo la verificación visual.
Este Step aplica la solución arquitectónica correcta: garantizar un estado inicial limpio del framebuffer llamando a clear_framebuffer() en el constructor de la PPU, siguiendo el principio RAII de C++. Además, reintroduce temporalmente el "hack educativo" para forzar la visualización del logo y poder verificarlo, e integra el logo personalizado "VIBOY COLOR" en el formato correcto.
Concepto de Hardware y C++: RAII y Estado Inicial
En C++, el principio de RAII (Resource Acquisition Is Initialization) dicta que un objeto debe estar en un estado completamente válido y conocido inmediatamente después de su construcción. Nuestro objeto PPU no cumplía esto: su framebuffer_ contenía datos indeterminados ("basura") hasta el primer ciclo de step().
La solución correcta es limpiar el framebuffer dentro del constructor de la PPU. Esto garantiza que, sin importar cuándo se use, la PPU siempre comienza con un lienzo en blanco, eliminando cualquier comportamiento indefinido en el primer fotograma.
El Problema del Primer Frame Fantasma:
- El framebuffer se inicializa con
framebuffer_(FRAMEBUFFER_SIZE, 0), pero esto solo inicializa los valores al construir el objeto. - Sin embargo, si no llamamos explícitamente a
clear_framebuffer()en el constructor, el primer fotograma puede dibujarse sobre datos que no hemos garantizado como limpios. - El primer fotograma funciona por casualidad, pero esto es un comportamiento indefinido que puede fallar en diferentes condiciones.
Verificación Visual y el Hack Educativo:
Para poder verificar que nuestro logo (personalizado o no) se está dibujando correctamente, necesitamos que permanezca en pantalla. Por ello, reintroduciremos temporalmente el hack que ignora el Bit 0 del LCDC. Esta es una herramienta de diagnóstico, no una solución final. Una vez verificado que el logo se dibuja correctamente, el hack debe ser eliminado para restaurar la precisión de hardware.
Implementación
Este Step implementa tres cambios principales: garantizar el estado inicial del framebuffer en el constructor, reintroducir temporalmente el hack de verificación visual, e integrar el logo personalizado "VIBOY COLOR".
1. Limpieza en el Constructor (C++)
En src/core/cpp/PPU.cpp, dentro del constructor PPU::PPU(MMU* mmu), añadimos una llamada a clear_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: Garantizar estado inicial limpio (RAII) ---
// En C++, el principio de RAII (Resource Acquisition Is Initialization) dicta que
// un objeto debe estar en un estado completamente válido y conocido inmediatamente
// después de su construcción. El framebuffer debe estar limpio desde el momento
// en que la PPU nace, no en el primer ciclo de step().
clear_framebuffer();
// ... resto de la inicialización ...
Esta modificación garantiza que:
- El framebuffer está limpio desde el momento de la construcción del objeto.
- Cumplimos con el principio RAII: el objeto está en un estado válido inmediatamente después de su construcción.
- Eliminamos cualquier comportamiento indefinido relacionado con el primer fotograma.
2. Reintroducir Hack de Verificación Visual (C++)
En src/core/cpp/PPU.cpp, dentro de render_scanline(), comentamos la verificación del Bit 0 del LCDC:
void PPU::render_scanline() {
// ... código anterior ...
uint8_t lcdc = mmu_->read(IO_LCDC);
if ((lcdc & 0x80) == 0) {
return;
}
// --- Step 0201: HACK DE DIAGNÓSTICO TEMPORAL ---
// Se ignora el Bit 0 del LCDC para forzar el renderizado del fondo y poder
// verificar visualmente el logo. Debe ser eliminado una vez verificado.
// if (!is_set(mmu_->read(IO_LCDC), 0)) return;
// ... resto del código ...
⚠️ Importante: Este hack es temporal y debe ser eliminado una vez que se verifique visualmente que el logo se está dibujando correctamente. El hack fuerza el renderizado del fondo incluso cuando la ROM apaga el Bit 0 del LCDC, lo que permite que el logo permanezca visible en pantalla para su verificación.
3. Integrar el Logo Personalizado "VIBOY COLOR" (C++)
En src/core/cpp/MMU.cpp, reemplazamos el array VIBOY_LOGO_HEADER_DATA con los nuevos datos del logo personalizado:
// --- Step 0201: Datos del Logo Personalizado "Viboy Color" ---
// Convertido desde la imagen 'viboy_logo_48x8_debug.png' (48x8px) a formato de header (1bpp).
// Este es el formato que la BIOS leería desde la dirección 0x0104 del cartucho.
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
};
Estos 48 bytes representan el logo "VIBOY COLOR" convertido desde una imagen de 48×8 píxeles al formato de header de cartucho (1 bit por píxel). El formato es:
- 48 bytes = 48 columnas × 8 filas (1 bit por píxel)
- Bit 7 = píxel superior, Bit 0 = píxel inferior
- 1 = visible/negro, 0 = transparente/blanco
El constructor de la MMU ya copia estos datos desde VIBOY_LOGO_HEADER_DATA a la VRAM en la dirección 0x8000, así que no es necesaria ninguna modificación adicional.
Archivos Afectados
src/core/cpp/PPU.cpp- Añadida llamada aclear_framebuffer()en el constructor; reintroducido hack temporal de verificación visualsrc/core/cpp/MMU.cpp- Actualizado el arrayVIBOY_LOGO_HEADER_DATAcon los nuevos datos del logo personalizado
Tests y Verificación
La verificación es 100% visual:
- Recompilación: Recompilar el módulo C++ usando
.\rebuild_cpp.ps1 - Ejecución: Ejecutar el emulador con la ROM de Tetris:
python main.py roms/tetris.gb - Resultado Esperado: El logo personalizado "VIBOY COLOR" debe aparecer en pantalla de forma ESTABLE y no desaparecer después de un segundo, porque el hack educativo está forzando su renderizado continuo.
Validación de módulo compilado C++: La verificación visual confirma que:
- El estado inicial del framebuffer es correcto (RAII).
- Los datos del logo personalizado se están cargando correctamente desde la MMU a la VRAM.
- La PPU está renderizando el logo correctamente.
Fuentes Consultadas
- RAII (Resource Acquisition Is Initialization): Principio fundamental de C++ moderno. Un objeto debe estar en un estado válido inmediatamente después de su construcción.
- Pan Docs: "Nintendo Logo", Cart Header (0x0104-0x0133) - Formato del logo en el header del cartucho
- Pan Docs: "LCDC Register" - Control del LCD, Bit 0 controla el renderizado del fondo
Integridad Educativa
Lo que Entiendo Ahora
- RAII en C++: El principio RAII garantiza que los objetos estén en un estado válido inmediatamente después de su construcción. En nuestro caso, esto significa que el framebuffer debe estar limpio desde el constructor, no desde el primer ciclo de
step(). - Estado Inicial Garantizado: El primer fotograma no debe depender de "memoria basura". El constructor debe garantizar que todos los recursos estén inicializados correctamente.
- Hack Educativo Temporal: Los hacks temporales son herramientas válidas de diagnóstico, pero deben documentarse claramente y eliminarse una vez cumplido su propósito.
Lo que Falta Confirmar
- Verificación Visual: Una vez que se verifique visualmente que el logo se dibuja correctamente, el hack temporal debe ser eliminado para restaurar la precisión de hardware.
- Formato del Logo: El logo personalizado debe verificarse para asegurar que se muestra correctamente en pantalla con los datos proporcionados.
Hipótesis y Suposiciones
Suposición: Los datos del logo personalizado proporcionados (48 bytes) son correctos y representan fielmente el logo "VIBOY COLOR" en formato 1bpp. Esta suposición se validará visualmente al ejecutar el emulador.
Próximos Pasos
- [ ] Verificar visualmente que el logo personalizado "VIBOY COLOR" se muestra correctamente en pantalla
- [ ] Eliminar el hack temporal de verificación visual una vez confirmado que el logo se dibuja correctamente
- [ ] Continuar con la implementación de los Sprites (siguiente componente del hardware gráfico)