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.
DMG Tiledata Cero + CGB Present Blanco
Resumen
Este step implementa un fix mínimo para el problema de pantalla en blanco en modo DMG (tetris.gb) y diagnostica el problema de ventana blanca en modo CGB (tetris_dx.gbc). El problema principal identificado: el juego no intentaba escribir a tiledata cuando `VIBOY_SIM_BOOT_LOGO=0` debido a un estado post-boot incorrecto. Se implementó `init_post_boot_dmg_state()` que establece el estado correcto según Pan Docs (LCDC=0x00 OFF inicialmente). Resultado: el juego ahora intenta escribir a tiledata (6144 intentos en frame 180), pero todos los writes son cero, lo que sugiere que el juego está en un estado de inicialización donde aún no ha descomprimido los datos gráficos.
Concepto de Hardware
Según Pan Docs - Power Up Sequence, después de que la Boot ROM termina, el hardware queda en un estado conocido:
- LCDC (0xFF40): LCD OFF (0x00) inicialmente. El juego debe activarlo manualmente.
- STAT (0xFF41): 0x00 por defecto
- BGP (0xFF47): 0xFC (shades 3,2,1,0) - paleta estándar DMG
- IF (0xFF0F): 0xE1 (VBlank, Timer, Serial flags set)
- IE (0xFFFF): 0x00 (sin interrupciones habilitadas inicialmente)
Problema Identificado: Nuestro emulador estaba inicializando LCDC=0x91 (LCD ON) cuando `VIBOY_SIM_BOOT_LOGO=0`, lo que puede haber causado que el juego no ejecutara correctamente su rutina de inicialización. El juego espera que LCDC esté OFF inicialmente y lo active manualmente durante su rutina de inicialización.
Referencia: Pan Docs - "Power Up Sequence", "LCDC Register (0xFF40)"
Implementación
Fase C: Fix Mínimo DMG - Caso 2
C1: Implementación de init_post_boot_dmg_state()
Se implementó el método `init_post_boot_dmg_state()` en MMU.cpp que establece el estado post-boot DMG correcto según Pan Docs:
void MMU::init_post_boot_dmg_state() {
// Estado conocido después del boot ROM DMG
// Fuente: Pan Docs - Power Up Sequence
memory_[0xFF40] = 0x00; // LCDC: LCD OFF
memory_[0xFF41] = 0x00; // STAT
memory_[0xFF42] = 0x00; // SCY
memory_[0xFF43] = 0x00; // SCX
memory_[0xFF47] = 0xFC; // BGP
memory_[0xFF48] = 0x00; // OBP0
memory_[0xFF49] = 0x00; // OBP1
memory_[0xFF0F] = 0xE1; // IF
memory_[0xFFFF] = 0x00; // IE
// ... otros registros ...
}
C2: Modificación de initialize_io_registers()
Se modificó `initialize_io_registers()` para llamar a `init_post_boot_dmg_state()` cuando es DMG y `VIBOY_SIM_BOOT_LOGO=0`:
void MMU::initialize_io_registers() {
bool is_cgb = (hardware_mode_ == HardwareMode::CGB);
// Step 0491: Si es DMG y VIBOY_SIM_BOOT_LOGO=0, usar estado post-boot correcto
const char* env_boot_logo = std::getenv("VIBOY_SIM_BOOT_LOGO");
bool sim_boot_logo = (env_boot_logo && std::string(env_boot_logo) == "1");
if (!is_cgb && !sim_boot_logo) {
// Modo DMG sin boot logo: usar estado post-boot según Pan Docs
init_post_boot_dmg_state();
return;
}
// ... resto del código ...
}
C3: Marcado de vram_write_stats_ como mutable
Se marcó `vram_write_stats_` como `mutable` en MMU.hpp para permitir actualización desde métodos const cuando sea necesario (aunque finalmente no se usa en read()).
Tests y Verificación
Comando de Ejecución
export PYTHONPATH=/media/fabini/8CD1-4C30/ViboyColor:$PYTHONPATH
export VIBOY_SIM_BOOT_LOGO=0
export VIBOY_DEBUG_DMG_TILE_FETCH=1
export VIBOY_DEBUG_VRAM_WRITES=1
export VIBOY_DEBUG_PRESENT_TRACE=1
export VIBOY_DUMP_RGB_FRAME=180
export VIBOY_DUMP_RGB_PATH=/tmp/viboy_tetris_gb_rgb_f####.ppm
python3 tools/rom_smoke_0442.py roms/tetris.gb --frames 240 > /tmp/viboy_0491_tetris_fix.log 2>&1
Resultados - Frame 180
| Métrica | Antes del Fix | Después del Fix | Cambio |
|---|---|---|---|
| TiledataAttemptsB0 | 0 | 6144 | ✅ +6144 |
| TiledataNonZeroB0 | 0 | 0 | ⚠️ Sin cambio |
| TilemapAttemptsB0 | 0 | 3072 | ✅ +3072 |
| TilemapNonZeroB0 | 0 | 1024 | ✅ +1024 |
Validación de Módulo Compilado C++
PYTHONPATH=/media/fabini/8CD1-4C30/ViboyColor:$PYTHONPATH python3 -c "from viboy_core import PyMMU; mmu = PyMMU(); print('✅ Módulo funciona correctamente')"
Resultado: ✅ Módulo compilado correctamente y funciona sin errores.
Archivos Modificados
src/core/cpp/MMU.hpp- Añadido métodoinit_post_boot_dmg_state()y marcadovram_write_stats_comomutablesrc/core/cpp/MMU.cpp- Implementadoinit_post_boot_dmg_state()y modificadoinitialize_io_registers()docs/reports/reporte_step0491.md- Reporte completo con métricas comparativas
Hallazgos y Conclusiones
Progreso Significativo
El fix de estado post-boot permitió que el juego intente escribir a tiledata y tilemap. Antes del fix, no había intentos de escritura (TiledataAttemptsB0=0). Después del fix, hay 6144 intentos de escritura a tiledata y 3072 intentos a tilemap.
Problema Persistente
Todos los writes a tiledata son cero (TiledataNonZeroB0=0), lo que sugiere que el juego está en un estado de inicialización donde aún no ha descomprimido los datos gráficos. El tilemap tiene datos (1024 bytes non-zero), pero tiledata está completamente vacío.
Próximos Pasos
- Investigar por qué el juego está escribiendo solo ceros a tiledata (¿está esperando alguna condición antes de descomprimir?)
- Ejecutar
rom_smokepara CGB (tetris_dx.gbc) y analizarFB_PRESENT_SRCpara entender por qué está blanco a pesar de queFB_RGBtiene señal - Verificar el contenido real de VRAM después de los writes para confirmar si los datos están siendo escritos pero no se están leyendo correctamente
Referencias
- Pan Docs - Power Up Sequence
- Pan Docs - LCDC Register (0xFF40)
- Pan Docs - VRAM Banking (CGB)
- Step 0490: VRAMWriteStats Expansion
- Step 0489: FB_PRESENT_SRC Capture
- Reporte completo (docs/reports/reporte_step0491.md)