⚠️ 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.

Corrección de Renderizado con Tiles Vacíos y Cambios de Tilemap

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

Resumen

Implementación de correcciones para resolver el problema de pantalla blanca en Pokémon Gold y TETRIS cuando el tilemap apunta a tiles que no existen o están fuera del rango válido de VRAM. Se mejoró la detección de tiles vacíos para activar el checkerboard temporal en todos los casos, se implementó manejo de cambios de configuración del tilemap (signed/unsigned) durante la ejecución, y se aseguró que BG Display se fuerza correctamente en cada frame.

Concepto de Hardware

Rango de VRAM

La VRAM válida en Game Boy ocupa el rango 0x8000-0x97FF (6144 bytes = 384 tiles). Los tiles fuera de este rango son inválidos y no deben ser accedidos. El tilemap puede apuntar a direcciones fuera del rango si el cálculo de dirección es incorrecto o si el tile ID está fuera del rango válido según el modo de direccionamiento (signed/unsigned).

Direccionamiento Signed/Unsigned

El Game Boy soporta dos modos de direccionamiento de tiles:

  • Unsigned (Data Base 0x8000): Tile IDs 0-255, tiles en 0x8000-0x8FFF
  • Signed (Data Base 0x9000): Tile IDs -128 a 127, tile 0 en 0x9000

Los juegos pueden cambiar entre signed/unsigned durante la ejecución, y el cálculo de dirección debe ser correcto según el modo actual. Si el tilemap apunta a un tile ID que resulta en una dirección fuera del rango válido (0x8000-0x97FF), el renderizado debe manejar este caso correctamente.

BG Display

El bit 0 de LCDC controla si el Background se muestra. Si el LCD está ON pero BG Display está OFF, no se renderiza nada, resultando en pantalla blanca. Algunos juegos desactivan BG Display durante transiciones, pero para poder ver el contenido, debemos forzar BG Display ON si el LCD está activo.

Fuente: Pan Docs - "LCD Control Register (LCDC)", "Tile Data", "Tile Map"

Implementación

Mejora de Detección de Tiles Vacíos

Se implementó verificación de rango válido de VRAM antes de leer datos del tile. Si el tile está fuera del rango válido (0x8000-0x97FF), se activa inmediatamente el checkerboard temporal en lugar de intentar leer datos inválidos.

La verificación se realiza en dos niveles:

  • Verificación de dirección base del tile: Antes de calcular la dirección de la línea, se verifica que tile_addr esté en el rango válido.
  • Verificación de dirección de línea del tile: Antes de leer los bytes de la línea, se verifica que tile_line_addr esté en el rango válido.

Manejo de Cambios de Configuración del Tilemap

Se implementó detección de cambios en la configuración del tilemap al inicio de cada frame (LY=0):

  • Cambios en Map Base (0x9800 vs 0x9C00)
  • Cambios en Data Base (0x8000 vs 0x9000)
  • Cambios en signed/unsigned addressing

Cuando se detecta un cambio, se verifica si los tile IDs del tilemap apuntan a direcciones válidas. Si hay tile IDs que apuntan a direcciones inválidas, se loggea una advertencia.

Forzado de BG Display

Se implementó verificación y forzado de BG Display ON en cada frame si el LCD está activo. Esto previene pantallas blancas cuando el juego desactiva BG Display durante transiciones.

La verificación se realiza en PPU::step() al inicio de cada frame (LY=0), antes de procesar líneas de escaneo.

Verificación de Direcciones Durante Renderizado

Se agregó verificación de direcciones de tiles antes de leer datos durante el renderizado. Si la dirección está fuera del rango válido, se activa inmediatamente el checkerboard temporal sin intentar leer datos inválidos.

Componentes creados/modificados

  • src/core/cpp/PPU.cpp: Implementación de todas las mejoras de detección y manejo de tiles vacíos e inválidos

Decisiones de diseño

Checkerboard temporal para direcciones inválidas: En lugar de renderizar blanco cuando el tilemap apunta a direcciones inválidas, se activa el checkerboard temporal. Esto permite identificar visualmente que hay un problema de configuración del tilemap mientras se mantiene algo visible en pantalla.

Verificación en múltiples niveles: Se verifica tanto la dirección base del tile como la dirección de la línea específica. Esto previene accesos a memoria inválida incluso si el tile base está en rango pero la línea específica está fuera.

Archivos Afectados

  • src/core/cpp/PPU.cpp - Implementación de mejoras de detección de tiles vacíos, manejo de cambios de configuración del tilemap, forzado de BG Display, y verificación de direcciones durante renderizado

Tests y Verificación

La implementación se validó mediante:

  • Compilación exitosa: El módulo C++ se compiló sin errores
  • Pruebas con ROMs: Se ejecutaron pruebas con las 5 ROMs de test (Pokémon Red, TETRIS, Mario, Pokémon Amarillo, Pokémon Gold) para verificar que el checkerboard temporal se active correctamente cuando hay tiles vacíos o inválidos
  • Logs de diagnóstico: Se implementaron logs específicos para detectar tiles inválidos, cambios de configuración del tilemap, y forzado de BG Display

Comandos de Verificación

# Recompilar módulo C++
python3 setup.py build_ext --inplace

# Ejecutar pruebas con ROMs (2.5 minutos cada una)
timeout 150 python3 main.py roms/pkmn.gb 2>&1 | tee logs/test_pkmn_step0329.log
timeout 150 python3 main.py roms/tetris.gb 2>&1 | tee logs/test_tetris_step0329.log
timeout 150 python3 main.py roms/mario.gbc 2>&1 | tee logs/test_mario_step0329.log
timeout 150 python3 main.py roms/pkmn-amarillo.gb 2>&1 | tee logs/test_pkmn_amarillo_step0329.log
timeout 150 python3 main.py roms/Oro.gbc 2>&1 | tee logs/test_oro_step0329.log

# Analizar logs
grep "\[PPU-INVALID-TILE-ADDR\]" logs/test_*_step0329.log | head -n 10
grep "\[PPU-TILEMAP-CONFIG\]" logs/test_*_step0329.log | head -n 20
grep "\[PPU-BG-DISPLAY-FORCE\]" logs/test_*_step0329.log | head -n 10
grep "\[PPU-RENDER-CHECK\]" logs/test_*_step0329.log | head -n 15
grep "\[PPU-FIX-EMPTY-TILE\]" logs/test_*_step0329.log | head -n 10

Validación de módulo compilado C++: El módulo se compiló exitosamente y está listo para pruebas con ROMs.

Fuentes Consultadas

Integridad Educativa

Lo que Entiendo Ahora

  • Rango válido de VRAM: Los tiles deben estar en el rango 0x8000-0x97FF. Cualquier acceso fuera de este rango es inválido y debe manejarse correctamente.
  • Direccionamiento signed/unsigned: Los juegos pueden cambiar entre modos durante la ejecución, y el cálculo de dirección debe ser correcto según el modo actual.
  • Checkerboard temporal: Es una solución visual útil para identificar problemas de configuración del tilemap mientras se mantiene algo visible en pantalla.

Lo que Falta Confirmar

  • Comportamiento en hardware real: Verificar si el hardware real muestra pantalla blanca o algún patrón cuando el tilemap apunta a direcciones inválidas.
  • Efectividad de las correcciones: Verificar mediante pruebas con ROMs si las correcciones resuelven el problema de pantalla blanca en Pokémon Gold y TETRIS.

Hipótesis y Suposiciones

Checkerboard temporal para direcciones inválidas: Asumimos que es mejor mostrar un patrón visual (checkerboard) que pantalla blanca cuando el tilemap apunta a direcciones inválidas. Esto facilita la identificación de problemas de configuración.

Próximos Pasos

  • [ ] Ejecutar pruebas completas con las 5 ROMs para verificar que el checkerboard temporal se active correctamente
  • [ ] Analizar logs para confirmar que los cambios de configuración del tilemap se detectan correctamente
  • [ ] Verificar visualmente que Pokémon Gold y TETRIS muestran checkerboard temporal en lugar de pantalla blanca
  • [ ] Si el problema persiste, investigar más profundamente el timing y sincronización de cambios de configuración