⚠️ Clean-Room / Educativo

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

Fecha: 2025-12-29 Step ID: 0491 Estado: VERIFIED

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étodo init_post_boot_dmg_state() y marcado vram_write_stats_ como mutable
  • src/core/cpp/MMU.cpp - Implementado init_post_boot_dmg_state() y modificado initialize_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_smoke para CGB (tetris_dx.gbc) y analizar FB_PRESENT_SRC para entender por qué está blanco a pesar de que FB_RGB tiene 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