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

Validar Diagnóstico VRAM RAW + Headless + Mapping Bancos

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

Resumen

Validación del diagnóstico de VRAM RAW, headless trust test y herramientas de prueba de mapping MBC. Se confirmó que VRAM está almacenada en bancos separados (vram_bank0_, vram_bank1_) en MMU, se corrigió read_raw() para leer correctamente de los bancos VRAM, se creó test de validación write→read_raw, se creó herramienta de headless trust test y se creó herramienta de MBC bank probe para validar mapping determinista. Hallazgo clave: VRAM storage confirmado en MMU (no en PPU), read_raw() funciona correctamente, y las herramientas de diagnóstico están listas para validar mapping MBC y confiabilidad de headless.

Concepto de Hardware

En Game Boy Color (CGB), la VRAM (Video RAM) está dividida en dos bancos de 8KB cada uno (total 16KB):

  • VRAM Bank 0 (0x8000-0x9FFF): Tile Data y Tile Map base
  • VRAM Bank 1 (0x8000-0x9FFF): Tile Data alternativo y atributos de Tile Map (CGB)

El registro VBK (0xFF4F) bit 0 selecciona qué banco ve la CPU. El PPU puede acceder a ambos bancos simultáneamente durante el renderizado. En modo DMG (Game Boy clásico), solo se usa Bank 0.

Diagnóstico RAW: Para diagnóstico confiable, necesitamos leer VRAM directamente sin restricciones de modo PPU. read_raw() debe leer de los bancos VRAM correctos (vram_bank0_, vram_bank1_) cuando la dirección está en el rango 0x8000-0x9FFF, no de memory_[] que no contiene el contenido de VRAM.

Fuente: Pan Docs - "CGB Registers", "VRAM Banks", "FF4F - VBK - VRAM Bank"

Implementación

Se implementaron tres fases del plan:

Fase A: Verificar Dónde Está VRAM Realmente

Se localizó el storage de VRAM usando grep sobre el código C++:

  • Hallazgo: VRAM está en MMU como vram_bank0_ y vram_bank1_ (vectores de 0x2000 bytes cada uno)
  • NO está en PPU: PPU no tiene arrays propios de VRAM, solo lee desde MMU usando read_vram_bank()
  • Problema identificado: read_raw() leía de memory_[] que no contiene VRAM

Fase B: Corregir read_raw() para Leer de Bancos VRAM

Se modificó MMU::read_raw() en src/core/cpp/MMU.cpp para leer de los bancos VRAM cuando la dirección está en el rango 0x8000-0x9FFF:

uint8_t MMU::read_raw(uint16_t addr) const {
    // Step 0452: VRAM está en bancos separados (vram_bank0_, vram_bank1_)
    // Para diagnóstico confiable, read_raw() debe leer de los bancos VRAM
    if (addr >= 0x8000 && addr <= 0x9FFF) {
        uint16_t offset = addr - 0x8000;
        if (vram_bank_ == 0 && offset < vram_bank0_.size()) {
            return vram_bank0_[offset];
        } else if (vram_bank_ == 1 && offset < vram_bank1_.size()) {
            return vram_bank1_[offset];
        }
        return 0xFF;
    }
    
    if (addr >= MEMORY_SIZE) {
        return 0xFF;
    }
    return memory_[addr];
}

Fase C: Crear Test de Validación write→read_raw

Se creó tests/test_vram_raw_write_read_0452.py con tres tests:

  • test_vram_write_read_raw_mmu: Valida que escribir a VRAM y leer con read_raw() funciona
  • test_vram_write_read_raw_range: Valida que dump_raw_range() funciona correctamente
  • test_vram_nonzero_sampling: Valida que podemos detectar bytes non-zero en VRAM usando read_raw()

Resultado: Todos los tests pasan correctamente ✅

Fase D: Crear Herramientas de Diagnóstico

Se crearon dos herramientas:

  • tools/test_headless_trust_0452.py: Headless trust test que valida que headless reporta correctamente con ROM clean-room
  • tools/mbc_bank_probe_0452.py: MBC bank probe que prueba mapping MBC determinista comparando bytes leídos con ROM real

Corrección de dump_raw_range() en Cython

Se corrigió dump_raw_range() en src/core/cython/mmu.pyx para manejar correctamente la conversión de bytes:

def dump_raw_range(self, uint16_t start, uint16_t length):
    # ... código de asignación de buffer ...
    try:
        self._mmu.dump_raw_range(start, length, buffer)
        # Convert to Python bytes by creating a list and converting to bytes
        result_list = []
        for i in range(length):
            result_list.append(buffer[i])
        return bytes(result_list)
    finally:
        free(buffer)

Archivos Afectados

  • src/core/cpp/MMU.cpp - Modificado read_raw() para leer de bancos VRAM
  • src/core/cython/mmu.pyx - Corregido dump_raw_range() para conversión de bytes
  • tests/test_vram_raw_write_read_0452.py - Creado test de validación write→read_raw
  • tools/test_headless_trust_0452.py - Creado headless trust test
  • tools/mbc_bank_probe_0452.py - Creado MBC bank probe

Tests y Verificación

Tests unitarios:

$ python3 -m pytest tests/test_vram_raw_write_read_0452.py -v

tests/test_vram_raw_write_read_0452.py::test_vram_write_read_raw_mmu PASSED
tests/test_vram_raw_write_read_0452.py::test_vram_write_read_raw_range PASSED
tests/test_vram_raw_write_read_0452.py::test_vram_nonzero_sampling PASSED

✅ 3 passed in 0.30s

Validación de módulo compilado C++: Todos los tests pasan, confirmando que read_raw() lee correctamente de los bancos VRAM y que dump_raw_range() funciona correctamente.

Código del Test:

def test_vram_write_read_raw_mmu():
    """Valida que escribir a VRAM y leer con read_raw funciona."""
    mmu = PyMMU()
    ppu = PyPPU(mmu)
    mmu.set_ppu(ppu)
    
    # Escribir patrón no-cero en 0x8000-0x8010
    pattern = [0xAA, 0xBB, 0xCC, 0xDD]
    for i, byte_val in enumerate(pattern):
        mmu.write(0x8000 + i, byte_val)
    
    # Leer con read_raw (VRAM está en MMU)
    for i, expected in enumerate(pattern):
        actual = mmu.read_raw(0x8000 + i)
        assert actual == expected, (
            f"VRAM write→read_raw falló en 0x{0x8000+i:04X}: "
            f"esperado 0x{expected:02X}, obtenido 0x{actual:02X}"
        )
    
    print("✅ MMU.write→read_raw funciona correctamente")

Fuentes Consultadas

Integridad Educativa

Lo que Entiendo Ahora

  • VRAM Storage: VRAM está en MMU como bancos separados (vram_bank0_, vram_bank1_), no en memory_[] ni en PPU. Esto es crítico para diagnóstico confiable.
  • read_raw() vs read(): read_raw() debe leer directamente de los bancos VRAM cuando la dirección está en 0x8000-0x9FFF, no de memory_[]. read() hace mapping dinámico de ROM pero no es útil para diagnóstico RAW de VRAM.
  • Diagnóstico Confiable: Para validar que VRAM tiene datos, necesitamos read_raw() que lea directamente de los bancos VRAM sin restricciones de modo PPU.

Lo que Falta Confirmar

  • Headless Trust Test: Validar que headless reporta correctamente con ROM clean-room (ejecutado en Step 0453)
  • MBC Bank Probe: Validar que el mapping MBC funciona correctamente comparando bytes leídos con ROM real (ejecutado en Step 0453)

Hipótesis y Suposiciones

Se asume que los bancos VRAM (vram_bank0_, vram_bank1_) son la fuente de verdad para VRAM. Esto se confirmó mediante análisis del código C++ y tests de validación write→read_raw.

Próximos Pasos

  • [x] Validar VRAM storage (MMU vs PPU)
  • [x] Corregir read_raw() para leer de bancos VRAM
  • [x] Crear test write→read_raw
  • [x] Crear headless trust test
  • [x] Crear MBC bank probe
  • [ ] Ejecutar headless trust test y MBC bank probe (Step 0453)
  • [ ] Analizar resultados y decidir causa raíz (mapping vs CPU/IRQ vs PPU/paletas)