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.
Desactivación de Tiles de Prueba y Verificación de Carga de Tiles por el Juego
Resumen
Se desactivó load_test_tiles() para permitir que los juegos carguen sus propios tiles sin interferencia de tiles de prueba. Se agregó monitoreo detallado de escrituras no-cero a VRAM y verificación periódica del estado de VRAM sin tiles de prueba. Los resultados muestran que algunos juegos SÍ cargan tiles (Oro.gbc, PKMN, PKMN-Amarillo), pero lo hacen muy tarde en la ejecución (Frame 4720-4943, ~78-82 segundos). Otros juegos (TETRIS, Mario) no cargan tiles durante la ejecución. Las escrituras ocurren correctamente durante VBLANK (LCD=ON, VBLANK=YES).
Concepto de Hardware
Carga de Tiles por el Juego: Los juegos cargan tiles en VRAM durante la inicialización o cuando el LCD está apagado. Los tiles se cargan en secuencias de 16 bytes consecutivos (cada tile es 8x8 píxeles, 2 bytes por línea = 16 bytes total). Los juegos pueden cargar tiles en diferentes momentos según sus necesidades. Algunos juegos cargan tiles al inicio, otros los cargan más tarde cuando los necesitan.
Interferencia de Tiles de Prueba: Los tiles de prueba pueden interferir con el comportamiento real del juego. Los juegos pueden borrar tiles de prueba porque no son parte del juego real. Desactivar tiles de prueba permite ver el comportamiento real del juego y verificar si los juegos cargan tiles correctamente.
Timing de LCD y Carga de Tiles: Los juegos suelen cargar tiles cuando el LCD está apagado o durante VBLANK. El acceso a VRAM está restringido cuando el LCD está encendido (excepto durante VBLANK). El timing correcto es: LCD apagado → juego carga tiles → LCD encendido, o LCD encendido → VBLANK → juego carga tiles → fin de VBLANK.
VBLANK y Acceso a VRAM: Durante VBLANK (cuando LY >= 144), el acceso a VRAM está permitido incluso cuando el LCD está encendido. Los juegos aprovechan este período para cargar tiles sin causar problemas visuales. En nuestro emulador, las escrituras a VRAM durante VBLANK se detectan correctamente (LCD=ON, VBLANK=YES).
Implementación
Se implementaron 4 tareas principales según el plan Step 0356:
1. Desactivación de load_test_tiles() (viboy.py)
Se desactivó completamente la llamada a load_test_tiles() en viboy.py para permitir que los juegos carguen sus propios tiles sin interferencia. El código que carga tiles de prueba está comentado y se agregó un log que confirma la desactivación.
# --- Step 0356: DESACTIVACIÓN DE TILES DE PRUEBA ---
# Desactivar load_test_tiles() para permitir que los juegos carguen sus propios tiles
# sin interferencia de tiles de prueba
# if load_test_tiles and self._use_cpp and self._mmu is not None:
# print("[VIBOY] Ejecutando load_test_tiles()...")
# self._mmu.load_test_tiles()
# print("[VIBOY] load_test_tiles() ejecutado")
print("[VIBOY] load_test_tiles() DESACTIVADO (Step 0356) - Los juegos cargarán sus propios tiles")
# --- Fin Step 0356 ---
2. Verificación del Orden de Ejecución de check_initial_vram_state() (MMU.cpp)
Se agregó un log en check_initial_vram_state() para verificar cuándo se ejecuta esta función. El log confirma que la función se ejecuta correctamente y en el momento adecuado.
// --- Step 0356: Verificación de Orden de Ejecución ---
// Verificar cuándo se ejecuta check_initial_vram_state()
void MMU::check_initial_vram_state() {
static bool already_called = false;
if (!already_called) {
already_called = true;
printf("[MMU-VRAM-INITIAL-STATE-CALL] check_initial_vram_state() called\n");
}
// ... resto del código existente ...
}
// -------------------------------------------
3. Monitoreo de Escrituras No-Cero a VRAM (MMU.cpp)
Se agregó código en MMU::write() para monitorear todas las escrituras no-cero a VRAM. El código loggea las primeras 500 escrituras no-cero con información detallada (dirección, valor, PC, frame, estado del LCD, VBLANK). También detecta secuencias de tiles completos (16 bytes consecutivos) y genera estadísticas cada 1000 escrituras.
// --- Step 0356: Monitoreo de Escrituras No-Cero a VRAM ---
// Monitorear si los juegos cargan tiles después de desactivar tiles de prueba
if (addr >= 0x8000 && addr < 0x9800 && value != 0x00) {
static int vram_non_zero_write_count = 0;
static int vram_tile_sequences_detected = 0;
vram_non_zero_write_count++;
// Loggear todas las escrituras no-cero (no solo las primeras 100)
if (vram_non_zero_write_count <= 500) {
// Obtener PC del CPU, estado del LCD, VBLANK, frame
// ...
printf("[MMU-VRAM-NON-ZERO-WRITE] Write #%d | Addr=0x%04X | Value=0x%02X | "
"PC=0x%04X | Frame %llu | LCD=%s | VBLANK=%s\n",
vram_non_zero_write_count, addr, value, pc,
static_cast<unsigned long long>(frame),
lcd_is_on ? "ON" : "OFF",
in_vblank ? "YES" : "NO");
}
// Verificar si esta escritura es parte de una secuencia de 16 bytes (tile completo)
if ((addr & 0x0F) == 0x00) {
// Detectar secuencias de tiles completos
// ...
if (is_tile_sequence && vram_tile_sequences_detected < 50) {
vram_tile_sequences_detected++;
printf("[MMU-VRAM-TILE-SEQUENCE] Tile sequence detected #%d | Addr=0x%04X | Frame %llu\n",
vram_tile_sequences_detected, addr,
static_cast<unsigned long long>(frame));
}
}
// Loggear estadísticas cada 1000 escrituras
if (vram_non_zero_write_count > 0 && vram_non_zero_write_count % 1000 == 0) {
printf("[MMU-VRAM-NON-ZERO-WRITE-STATS] Total non-zero writes=%d | Tile sequences=%d\n",
vram_non_zero_write_count, vram_tile_sequences_detected);
}
}
// -------------------------------------------
4. Verificación Periódica del Estado de VRAM Sin Tiles de Prueba (PPU.cpp)
Se agregó código en PPU::step() para verificar periódicamente el estado de VRAM sin tiles de prueba. El código verifica el estado de VRAM cada 100 frames y loggea estadísticas (bytes no-cero, tiles completos, si hay tiles reales). Si se detectan tiles reales (más de 200 bytes no-cero), se genera un log adicional.
// --- Step 0356: Verificación Periódica de VRAM Sin Tiles de Prueba ---
// Verificar si los juegos cargan tiles reales después de desactivar tiles de prueba
static int vram_periodic_check_count = 0;
if (frame_counter_ % 100 == 0 && vram_periodic_check_count < 50) {
vram_periodic_check_count++;
// Contar bytes no-cero en VRAM
int non_zero_bytes = 0;
int complete_tiles = 0;
// ... contar bytes no-cero y tiles completos ...
printf("[PPU-VRAM-PERIODIC-NO-TEST-TILES] Frame %llu | Non-zero bytes: %d/6144 (%.2f%%) | "
"Complete tiles: %d/384 (%.2f%%) | Has real tiles: %s\n",
static_cast<unsigned long long>(frame_counter_),
non_zero_bytes, (non_zero_bytes * 100.0) / 6144,
complete_tiles, (complete_tiles * 100.0) / 384,
(non_zero_bytes >= 200) ? "YES" : "NO");
// Si se detectan tiles reales, verificar el framebuffer
if (non_zero_bytes >= 200) {
printf("[PPU-VRAM-PERIODIC-NO-TEST-TILES] ✅ Tiles reales detectados! Verificando framebuffer...\n");
}
}
// -------------------------------------------
Resultados de las Pruebas
Se ejecutaron pruebas con las 5 ROMs en paralelo (5 emuladores simultáneos, ~2.5 minutos cada una). Los resultados muestran que algunos juegos cargan tiles y otros no:
Juegos que SÍ Cargar Tiles
- Oro.gbc (Pokémon Gold):
- Primera escritura no-cero: Frame 4720, PC=0x5EB2
- Timing: Durante VBLANK (LCD=ON, VBLANK=YES)
- Secuencias de tiles detectadas: 30+
- Direcciones: 0x8800-0x89D0 (signed addressing, data base = 0x8800)
- PKMN (Pokémon Red/Blue):
- Primera escritura no-cero: Frame 4943, PC=0x618D
- Timing: Durante VBLANK (LCD=ON, VBLANK=YES)
- Total escrituras no-cero: 1,405,000+
- Secuencias de tiles detectadas: 50 (límite alcanzado)
- Direcciones: 0x8821-0x8BC0 (signed addressing, data base = 0x8800)
- PKMN-Amarillo (Pokémon Yellow):
- Primera escritura no-cero: Frame 4716, PC=0x65F0
- Timing: Durante VBLANK (LCD=ON, VBLANK=YES)
- Secuencias de tiles detectadas: Múltiples
- Direcciones: 0x8821-0x884F (signed addressing, data base = 0x8800)
Juegos que NO Cargar Tiles
- TETRIS:
- Escrituras no-cero: 0
- VRAM permanece vacía durante toda la ejecución (0 bytes no-cero)
- Estado periódico: Frame 0, 0/6144 bytes no-cero (0.00%)
- Mario (Super Mario Land):
- Escrituras no-cero: 0 (no detectadas en los primeros 500)
- VRAM permanece vacía durante la ejecución
Estadísticas Generales
- Total de secuencias de tiles detectadas: 150+ (Oro.gbc, PKMN, PKMN-Amarillo)
- Timing de carga: Frame 4716-4943 (~78-82 segundos después del inicio)
- Condiciones de carga: Todas las escrituras ocurren durante VBLANK (LCD=ON, VBLANK=YES)
- Direccionamiento: Los juegos usan signed addressing (data base = 0x8800)
Hallazgos y Conclusiones
Hallazgos Principales
- load_test_tiles() está desactivado correctamente:
- Confirmado en todos los logs:
[VIBOY] load_test_tiles() DESACTIVADO (Step 0356) - No se ejecuta durante las pruebas
- Confirmado en todos los logs:
- Algunos juegos SÍ cargan tiles:
- Oro.gbc, PKMN, PKMN-Amarillo cargan tiles correctamente
- Las escrituras ocurren durante VBLANK (timing correcto)
- Se detectan secuencias de tiles completos (16 bytes consecutivos)
- Los tiles se cargan muy tarde en la ejecución:
- Frame 4716-4943 = ~78-82 segundos después del inicio
- Esto explica por qué no se veían tiles antes: los juegos cargan tiles muy tarde
- Los juegos pueden tener pantallas en blanco o patrones simples hasta que cargan tiles
- Algunos juegos no cargan tiles durante la ejecución:
- TETRIS y Mario no cargan tiles durante los primeros 2.5 minutos
- Esto puede ser normal para algunos juegos que cargan tiles más tarde o en diferentes momentos
- Timing correcto:
- Todas las escrituras ocurren durante VBLANK (LCD=ON, VBLANK=YES)
- Esto es correcto según las especificaciones del hardware
Conclusiones
La desactivación de load_test_tiles() permite que los juegos carguen sus propios tiles sin interferencia. Los resultados muestran que algunos juegos SÍ cargan tiles, pero lo hacen muy tarde en la ejecución (después de ~78-82 segundos). Esto explica por qué no se veían tiles antes: los juegos cargan tiles después de un tiempo considerable de ejecución.
El problema de visualización no está en que los juegos no cargan tiles, sino en que los tiles se cargan muy tarde. Para ver los tiles, necesitamos esperar más tiempo o verificar si el framebuffer se actualiza correctamente cuando los tiles se cargan.
El siguiente paso debería verificar si el framebuffer se actualiza correctamente cuando los tiles se cargan (Frame 4720-4943) y si los tiles se renderizan correctamente en la pantalla.
Archivos Modificados
src/viboy.py- Desactivación deload_test_tiles()src/core/cpp/MMU.cpp- Monitoreo de escrituras no-cero a VRAM y verificación del orden de ejecuciónsrc/core/cpp/PPU.cpp- Verificación periódica del estado de VRAM sin tiles de prueba
Tests y Verificación
Se ejecutaron pruebas con las 5 ROMs en paralelo durante 2.5 minutos cada una. Los logs confirman que:
- load_test_tiles() está desactivado: Confirmado en todos los logs
- check_initial_vram_state() se ejecuta correctamente: Log
[MMU-VRAM-INITIAL-STATE-CALL]aparece en todos los logs - Monitoreo de escrituras no-cero funciona: Logs
[MMU-VRAM-NON-ZERO-WRITE]aparecen para juegos que cargan tiles - Detección de secuencias de tiles funciona: Logs
[MMU-VRAM-TILE-SEQUENCE]aparecen cuando se detectan tiles completos - Verificación periódica funciona: Logs
[PPU-VRAM-PERIODIC-NO-TEST-TILES]aparecen cada 100 frames
Comandos de Verificación
# Verificar que load_test_tiles() está desactivado
grep "load_test_tiles.*DESACTIVADO" logs/test_*_step0356.log
# Verificar escrituras no-cero a VRAM
grep "\[MMU-VRAM-NON-ZERO-WRITE\]" logs/test_*_step0356.log | head -n 50
# Verificar secuencias de tiles
grep "\[MMU-VRAM-TILE-SEQUENCE\]" logs/test_*_step0356.log | head -n 30
# Verificar estado periódico de VRAM
grep "\[PPU-VRAM-PERIODIC-NO-TEST-TILES\]" logs/test_*_step0356.log | tail -n 50
Próximos Pasos
Basándose en los hallazgos del Step 0356, los próximos pasos deberían ser:
- Verificar si el framebuffer se actualiza cuando los tiles se cargan:
- Verificar el contenido del framebuffer cuando se detectan tiles reales (Frame 4720-4943)
- Verificar si los tiles se renderizan correctamente en la pantalla
- Investigar por qué algunos juegos no cargan tiles:
- Verificar si TETRIS y Mario cargan tiles más tarde (después de 2.5 minutos)
- Verificar si hay algún problema que impide que estos juegos carguen tiles
- Optimizar la visualización cuando los tiles se cargan tarde:
- Verificar si el framebuffer se actualiza correctamente cuando los tiles se cargan
- Verificar si hay algún problema de sincronización o timing