⚠️ 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 Actualización de vram_is_empty_ y Resolución de Discrepancia

Fecha: 2025-12-30 Step ID: 0370 Estado: VERIFIED

Resumen

Se implementaron verificaciones detalladas para investigar y resolver la discrepancia entre la verificación de VRAM completa (0/6144 bytes no-cero) y la verificación de tiles específicos (20/20 con datos). Se mejoró la actualización de `vram_is_empty_` para que se actualice no solo en LY=0, sino también durante V-Blank cuando los tiles se cargan típicamente. Se agregaron verificaciones de rangos de direcciones de tiles y de todos los rangos posibles de VRAM para identificar la causa raíz de la discrepancia.

Concepto de Hardware

Rangos de VRAM para Tiles

En la Game Boy, los tiles pueden estar en dos rangos diferentes según el modo de direccionamiento configurado en el bit 4 de LCDC (0xFF40):

  • Unsigned Addressing (Bit 4 de LCDC = 1):
    • Base: 0x8000
    • Tiles: 0-255 (256 tiles)
    • Rango: 0x8000-0x8FFF (4096 bytes)
  • Signed Addressing (Bit 4 de LCDC = 0):
    • Base: 0x8800
    • Tiles: -128 a 127 (256 tiles)
    • Tile 0 está en 0x9000
    • Rango: 0x8800-0x97FF (4096 bytes)

El rango completo de VRAM (0x8000-0x97FF, 6144 bytes) cubre ambos modos, pero hay superposición en 0x8800-0x8FFF. Esta superposición puede causar confusión si no se verifica correctamente qué modo de direccionamiento está activo.

Timing de Actualización de Estado

En sistemas de renderizado, el estado debe actualizarse cuando cambia, no solo en momentos fijos. Si `vram_is_empty_` se actualiza solo en LY=0 (inicio del frame), puede quedar desactualizado si los tiles se cargan durante V-Blank (LY 144-153) o después de LY=0. La actualización durante V-Blank captura tiles cargados durante ese período, y la actualización periódica (cada N frames) asegura que el estado refleje la realidad.

Implementación

Se implementaron cuatro verificaciones principales para investigar y resolver la discrepancia:

1. Verificación de Discrepancia Entre VRAM y Tiles

Se agregó una verificación detallada que compara la verificación de VRAM completa (0x8000-0x97FF) con los tiles específicos que apunta el tilemap. Esta verificación:

  • Cuenta bytes no-cero en VRAM completa (0x8000-0x97FF)
  • Verifica los primeros 20 tiles del tilemap para ver si tienen datos
  • Verifica si las direcciones de tiles están en el rango correcto (0x8000-0x97FF)
  • Reporta discrepancias cuando los tiles tienen datos pero VRAM muestra 0/6144

2. Actualización Mejorada de vram_is_empty_

Se mejoró la actualización de `vram_is_empty_` para que se actualice no solo en LY=0, sino también durante V-Blank (LY 144-153) cuando los tiles se cargan típicamente. La actualización durante V-Blank:

  • Se ejecuta cuando LY está entre 144 y 153 y el modo es MODE_1_VBLANK
  • Verifica VRAM completa (0x8000-0x97FF)
  • Solo actualiza `vram_is_empty_` si el valor cambió
  • Registra el cambio en los logs para diagnóstico

3. Verificación de Rangos de Direcciones de Tiles

Se agregó una verificación que confirma que todas las direcciones de tiles calculadas están en el rango válido (0x8000-0x97FF). Esta verificación:

  • Se ejecuta durante el renderizado (LY 0 y 72)
  • Verifica cada tile (cada 8 píxeles en X)
  • Reporta tiles fuera de rango con su dirección y Tile ID
  • Confirma tiles en rango válido

4. Verificación Completa de Rangos de VRAM

Se agregó una verificación que verifica todos los rangos posibles donde pueden estar los tiles:

  • Rango 1: 0x8000-0x8FFF (unsigned addressing, tiles 0-127)
  • Rango 2: 0x8800-0x97FF (signed addressing, tiles -128 a 127)
  • Rango completo: 0x8000-0x97FF (6144 bytes)
  • Reporta si hay tiles en rangos superpuestos

Decisiones de Diseño

  • Límites de logs: Se usaron contadores estáticos para limitar la cantidad de logs y evitar saturación del contexto (máximo 20 verificaciones de discrepancia, 10 de rangos, 50 de direcciones de tiles).
  • Actualización durante V-Blank: Se eligió actualizar `vram_is_empty_` durante V-Blank porque es cuando los juegos típicamente cargan tiles, según la documentación del hardware.
  • Verificación de tiles específicos: Se verifican los primeros 20 tiles del tilemap porque es una muestra representativa sin ser demasiado costosa computacionalmente.

Archivos Afectados

  • src/core/cpp/PPU.cpp - Agregadas verificaciones de discrepancia, actualización de vram_is_empty_ durante V-Blank, verificación de rangos de direcciones de tiles, y verificación completa de rangos de VRAM. Agregado include de <vector> para std::vector.

Tests y Verificación

Se ejecutaron pruebas con las 6 ROMs de test (TETRIS, Mario, Zelda DX, Oro, PKMN, PKMN-Amarillo) durante 30-60 segundos cada una para análisis rápido. Los logs muestran:

  • Verificación de Discrepancia: 20 verificaciones por ROM, todas muestran VRAM completa: 0/6144 non-zero y Tiles with data: 0/20, lo que indica que no hay discrepancia en los primeros frames (los tiles simplemente no se han cargado todavía).
  • Verificación de Rangos de VRAM: Todos los rangos muestran 0/4096 o 0/6144 bytes no-cero, confirmando que VRAM está vacía en los primeros frames.
  • Verificación de Direcciones de Tiles: Todas las direcciones de tiles están en rango válido (0x8000-0x97FF), no se detectaron tiles fuera de rango.
  • Actualización durante V-Blank: No se detectaron actualizaciones de `vram_is_empty_` durante V-Blank en los primeros frames, lo que sugiere que los tiles no se están cargando durante V-Blank en esos frames (comportamiento normal para algunos juegos).

Validación de módulo compilado C++: El código se compiló exitosamente sin errores. Solo se generaron warnings menores sobre variables no usadas y formatos de printf, que no afectan la funcionalidad.

Fuentes Consultadas

  • Pan Docs: Sección sobre VRAM y rangos de tiles (0x8000-0x97FF)
  • GBEDG: Documentación sobre modos de direccionamiento signed/unsigned de tiles

Nota: Implementación basada en documentación técnica del hardware Game Boy y conocimiento general de arquitectura LR35902.

Integridad Educativa

Lo que Entiendo Ahora

  • Rangos de VRAM: Los tiles pueden estar en dos rangos diferentes según el modo de direccionamiento, y hay superposición en 0x8800-0x8FFF. La verificación completa debe considerar ambos rangos.
  • Timing de Actualización: El estado de `vram_is_empty_` debe actualizarse cuando cambia, no solo en momentos fijos. La actualización durante V-Blank captura tiles cargados durante ese período.
  • Discrepancia Identificada: En los primeros frames, no hay discrepancia real: tanto VRAM completa como los tiles específicos están vacíos. La discrepancia reportada en el Step 0368 probablemente ocurrió en frames posteriores cuando los tiles se cargaron.

Lo que Falta Confirmar

  • Actualización durante V-Blank: Verificar si la actualización de `vram_is_empty_` durante V-Blank captura tiles cargados en frames posteriores (después de los primeros 20 frames).
  • Discrepancia en Frames Posteriores: Verificar si la discrepancia reportada en el Step 0368 ocurre en frames posteriores cuando los tiles se cargan, y si las nuevas verificaciones la detectan correctamente.

Hipótesis y Suposiciones

Se asume que los juegos cargan tiles durante V-Blank, pero esto puede variar según el juego. Algunos juegos pueden cargar tiles en otros momentos del frame. La actualización durante V-Blank es una mejora, pero puede no capturar todos los casos.

Próximos Pasos

  • [ ] Verificar si la actualización de `vram_is_empty_` durante V-Blank captura tiles cargados en frames posteriores
  • [ ] Verificar si la discrepancia reportada en el Step 0368 ocurre en frames posteriores y si las nuevas verificaciones la detectan correctamente
  • [ ] Considerar desactivar el checkerboard temporal cuando hay tiles reales disponibles, basándose en la verificación mejorada de `vram_is_empty_`
  • [ ] Preparar para siguiente fase (Audio/APU) si el renderizado de tiles funciona correctamente