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

Step 0460: Fix Setup Test Insuficiente - Tilemap Completo

Fecha: 2026-01-03 Step ID: 0460 Estado: VERIFIED

Resumen

Objetivo: Diagnosticar y corregir el problema de "setup de test insuficiente" que causaba que los tests de paleta fallaran con solo 2 colores únicos en vez de ≥4. Los Steps 0458 y 0459 confirmaron que el PPU lee VRAM correctamente y que el pipeline de conversión funciona bien cuando recibe índices variados. El problema real era que el tilemap estaba casi vacío (solo 1 entrada escrita), lo que causaba que la mayoría del BG usara tiles por defecto que solo producían índices {0, 2}.

Diagnóstico confirmado: El framebuffer de índices global mostraba solo {0, 2} en la mayoría de la pantalla porque el tilemap solo tenía 1 entrada escrita (tile 0 en posición 0,0). El resto del tilemap estaba sin inicializar, usando tiles por defecto que solo producían índices 0 y 2.

Solución aplicada: Llenar completamente el tilemap (32×32 = 1024 bytes) con el tile 0 que tiene el patrón 0x55/0x33 que garantiza índices {0, 1, 2, 3}. Esto asegura que toda la pantalla visible use el tile con 4 índices distintos.

Resultado: ✅ Tests BGP y Not Flat pasan (2 de 3 tests objetivo). El test OBJ tiene un problema conocido con la conversión de paleta para sprites que está fuera del alcance de este plan (índices correctos {1, 3}, pero RGB colapsa a (0,0,0)).

Concepto de Hardware

BG Tilemap en Game Boy

El Background Tilemap es una tabla de 32×32 tiles (1024 bytes) que define qué tile se renderiza en cada posición del fondo. Cada byte del tilemap contiene el índice del tile (0-255) que se debe renderizar en esa posición.

Direcciones del Tilemap:

  • 0x9800-0x9BFF: Tilemap base (LCDC bit 3 = 0)
  • 0x9C00-0x9FFF: Tilemap alternativo (LCDC bit 3 = 1)

Problema de Setup Insuficiente: Si solo se escribe 1 entrada en el tilemap (ej: tile 0 en posición 0,0), el resto del tilemap queda sin inicializar. Cuando el PPU renderiza el BG, lee tiles por defecto (generalmente 0x00) que solo producen índices {0, 2}, causando que el framebuffer tenga solo 2 colores únicos en la mayoría de la pantalla.

Solución: Llenar completamente el tilemap (32×32 = 1024 bytes) con el tile deseado para asegurar que toda la pantalla visible use el mismo tile con 4 índices distintos.

Fuente: Pan Docs - "LCD Control Register" (LCDC bit 3) y "Tile Maps"

Implementación

Fase A: Confirmación Pre-Change

Añadido diagnóstico al test BGP para verificar el conjunto de índices únicos global del framebuffer. Esto confirmó que el problema era setup insuficiente (tilemap casi vacío).

# Calcular índices únicos en todo el framebuffer (no solo primeros píxeles)
unique_idx_set = set()
for i in range(min(23040, len(indices_buffer))):  # Toda la pantalla
    unique_idx_set.add(indices_buffer[i] & 0x03)

print(f"[TEST-PRE-CHANGE] Unique idx set global: {unique_idx_set}")

# Si solo vemos {0, 2} o similar, confirma que el problema es tilemap casi vacío
if len(unique_idx_set) < 3:
    print(f"⚠️ CONFIRMADO: Tilemap casi vacío. Solo índices {unique_idx_set} en pantalla completa.")

Fase B: Fix del Setup BG (Paleta BGP)

Modificado el test BGP para escribir tile data completo y llenar el tilemap completo (32×32 = 1024 bytes).

# Escribir tile data completo con patrón 0x55/0x33
tile_index = 0
tile_base_addr = 0x8000 + (tile_index * 16)

for row in range(8):
    addr_low = tile_base_addr + (row * 2)
    addr_high = addr_low + 1
    mmu.write(addr_low, 0x55)
    mmu.write(addr_high, 0x33)

# Llenar tilemap completo (32×32 = 1024 bytes)
tilemap_base = 0x9800
for i in range(32 * 32):  # 1024 bytes (32×32 tiles)
    mmu.write(tilemap_base + i, tile_index)

Fase C: Fix del Setup OBJ (Paleta OBP0/OBP1)

Modificado el test OBJ para usar el mismo tile (tile 0) con patrón 0x55/0x33 que garantiza índices {0, 1, 2, 3}.

Fase D: Ajuste del Test "Not Flat"

Modificado el test Not Flat para reutilizar el mismo setup de BG (tile data completo + tilemap completo) y exigir ≥4 colores únicos en vez de ≥3.

Cambios en Muestreo

Cambiado el muestreo de grid 16×16 a muestreo de primeros 100 píxeles para capturar mejor el patrón repetido 0,1,2,3.

Archivos Afectados

  • tests/test_palette_dmg_bgp_0454.py - Fix del setup BG: tile data completo + tilemap completo (32×32)
  • tests/test_palette_dmg_obj_0454.py - Fix del setup OBJ: usar mismo tile con patrón 0x55/0x33
  • tests/test_framebuffer_not_flat_0456.py - Ajuste: reutilizar setup completo y exigir ≥4 colores únicos

Tests y Verificación

Tests objetivo ejecutados:

  • test_palette_dmg_bgp_0454.py::test_dmg_bgp_palette_mapping - ✅ PASSED
  • test_framebuffer_not_flat_0456.py::test_framebuffer_not_flat - ✅ PASSED
  • test_palette_dmg_obj_0454.py::test_dmg_obj_palette_mapping - ⚠️ FAILED (problema conocido con conversión de paleta para sprites, fuera del alcance de este plan)

Evidencia pre-change:

[TEST-PRE-CHANGE] Unique idx set global: {0, 2}
⚠️ CONFIRMADO: Tilemap casi vacío. Solo índices {0, 2} en pantalla completa.
   Esto explica por qué unique_rgb_count < 3: la mayoría del BG usa tiles default.

Evidencia post-change:

[TEST-BG-SETUP] Tile data escrito: tile 0 en 0x8000
[TEST-BG-SETUP] Tilemap llenado: 32×32 = 1024 bytes con tile 0
[TEST-BG-SETUP] Unique idx set global después de llenar tilemap: {0, 1, 2, 3}
[TEST-BG-SETUP] Unique RGB colors (primeros 100 píxeles): 4
[TEST-BG-SETUP] Colores únicos encontrados: {(170, 170, 170), (85, 85, 85), (255, 255, 255), (0, 0, 0)}

Validación de módulo compilado C++: ✅ Compilación exitosa sin errores.

Fuentes Consultadas

  • Pan Docs: "LCD Control Register" (LCDC bit 3) - Tile Map selection
  • Pan Docs: "Tile Maps" - Background tilemap addressing
  • Pan Docs: "Color Palettes" (DMG) - BGP register mapping

Integridad Educativa

Lo que Entiendo Ahora

  • Setup de test insuficiente: Si el tilemap solo tiene 1 entrada escrita, el resto del tilemap queda sin inicializar y usa tiles por defecto que solo producen índices {0, 2}.
  • Llenado completo del tilemap: Para asegurar que toda la pantalla visible use el mismo tile, es necesario llenar completamente el tilemap (32×32 = 1024 bytes).
  • Muestreo robusto: El muestreo de grid 16×16 puede no capturar todos los colores si el patrón no está distribuido uniformemente. Muestrear los primeros 100 píxeles es más robusto para patrones repetidos.

Lo que Falta Confirmar

  • Conversión de paleta para sprites: El test OBJ muestra índices correctos {1, 3} pero RGB colapsa a (0,0,0). Esto sugiere un problema en la conversión de paleta para sprites, pero está fuera del alcance de este plan.

Hipótesis y Suposiciones

Se asume que el problema del test OBJ (RGB colapsa a (0,0,0) aunque los índices son correctos) es un bug del PPU en la conversión de paleta para sprites, no un problema de setup del test. El setup del test está correcto (índices {1, 3} se detectan correctamente).

Próximos Pasos

  • [ ] Investigar y corregir el problema de conversión de paleta para sprites (test OBJ)
  • [ ] Verificar que el tilemap se llena correctamente en otros tests que usen BG
  • [ ] Considerar crear una función helper para llenar tilemap completo en tests