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

MBC Unificado & Instrumentación VRAM/WRAM

Fecha: 2025-12-25 Step ID: 0272 Estado: Draft

Resumen

Se unificó el soporte de controladores de banco (MBC) en la MMU C++ para ROM_ONLY, MBC1, MBC2, MBC3 y MBC5, dimensionando la RAM externa según el header y normalizando bancos de ROM/RAM. Se añadieron trazas ligeras para detectar escrituras/lecturas a 0xD732, VRAM y solicitudes/servicio de interrupciones.

El monitor GPS ahora separa VRAM_TILE_SUM (0x8000-0x97FF) de VRAM_MAP_SUM (0x9800-0x9FFF) y reporta 0xD732 en caliente. Resultado actual (Pokémon Red): VBlank se solicita y atiende, D732 solo se escribe con 00, se detecta un barrido de escrituras de VRAM llenando de ceros la tile data desde PC=0x36E3, y el tilemap sigue lleno de 0x7F (pantalla verde).

Concepto de Hardware

Los MBC (Memory Bank Controllers) permiten a cartuchos de >32KB exponer bancos de ROM/RAM conmutables. MBC1 combina bits bajos/altos y modo ROM/RAM; MBC2 trae RAM interna de 512x4 bits; MBC3 añade RTC y bancos de RAM seleccionables; MBC5 extiende a 9 bits de banco de ROM y hasta 16 bancos de RAM.

Instrumentar VRAM y flags de estado (ej. 0xD732) es clave para verificar si la CPU está copiando gráficos (tile data) o solo modificando el tilemap. Separar tile data vs tilemap ayuda a localizar la causa de pantalla verde cuando el mapa cambia pero los tiles no.

Implementación

En MMU.cpp/MMU.hpp se añadieron campos de estado para cada MBC, cálculo de bancos desde el header, asignación de RAM por tamaño declarado y mapeo de bancos bank0_rom/bankN_rom. Se implementaron rutas de escritura para enable de RAM, selección de banco de ROM/RAM (MBC1/2/3/5) y stub de RTC en MBC3. Se normalizan bancos contra el total cargado para evitar lecturas fuera de rango.

Se instrumentaron las primeras escrituras/lecturas a 0xD732 y VRAM (0x8000-0x9FFF) para detectar actividad real. En viboy.py el GPS ahora reporta sumas separadas de tile data y tilemap, más la lectura de D732 cada segundo.

Componentes creados/modificados

  • src/core/cpp/MMU.hpp / MMU.cpp – Soporte MBC1/2/3/5 unificado, asignación dinámica de RAM, logs de VRAM/WRAM.
  • src/viboy.py – GPS ampliado con VRAM_TILE_SUM, VRAM_MAP_SUM y lectura de 0xD732.

Decisiones de diseño

Se mantuvo el estado por-MBC para no romper compatibilidad con cartuchos pequeños (ROM_ONLY) y se limitaron los logs a los primeros accesos para no inundar la salida en modo --verbose. Se priorizó visibilidad sobre corrección visual mientras se diagnostica la falta de escrituras de tile data.

Archivos Afectados

  • src/core/cpp/MMU.hpp – Nuevos campos de estado y helpers de MBC/RAM.
  • src/core/cpp/MMU.cpp – Lógica de banking unificada, asignación de RAM, logs VRAM/WRAM.
  • src/viboy.py – Métricas de VRAM separadas y lectura de D732 en GPS.

Tests y Verificación

  • ROM: python main.py roms/pkmn.gb --verbose (10-15s). Observado: VRAM_TILE_SUM=0, VRAM_MAP_SUM=16256, D732=00, PC en 0x615x; VBlank IRQs solicitadas/atendidas; escritura masiva de 0x00 en VRAM tile data desde PC=0x36E3; tilemap permanece en 0x7F.
  • Rebuild: rebuild_cpp.ps1 tras cada cambio en C++.
  • VRAM inicial: PyMMU + cartucho: 0x8000/0x9800 arrancan en 0x00 (confirmado que el llenado de 0x7F ocurre en runtime, no en la carga).

Fuentes Consultadas

  • Pan Docs – Secciones: MBC1, MBC2, MBC3, MBC5, Memory Map.
  • Pan Docs – LCD Control, VRAM layout (tile data 0x8000-0x97FF, tilemaps 0x9800/0x9C00).

Integridad Educativa

Lo que Entiendo Ahora

  • Pokémon Red (tipo 0x13) usa MBC3: necesita bancos de ROM altos y RAM con enable.
  • El tilemap se está llenando (0x7F); la tile data se sobrescribe con ceros desde PC=0x36E3, lo que explica la pantalla verde.
  • 0xD732 permanece en 0, solo escrito con 0x00 en PC=0x1F80.
  • VBlank se solicita y se atiende (logs en IRQ/VBlank), por lo que las interrupciones básicas están vivas.

Lo que Falta Confirmar

  • Quién y por qué limpia la tile data a 0x00 en PC=0x36E3 (desensamblar esa rutina y su banco).
  • Quién debería setear D732 y en qué rutina (posible ISR o bucle de init).

Hipótesis y Suposiciones

El juego inicializa tilemap y luego limpia tile data (0x36E3) porque aún no ha ejecutado la rutina que copia los tiles reales; podría estar bloqueado esperando D732 antes de cargar gráficos o en otra rama de init.

Próximos Pasos

  • [ ] Loguear escrituras a 0x9800-0x9FFF y 0x8000-0x97FF con un límite mayor para captar el primer copy.
  • [ ] Desensamblar el bloque en 0x6150 (banco activo) y la rutina en 0x36E3 que limpia VRAM para ver condiciones de carga de tiles.
  • [ ] Identificar cuándo debería escribirse D732 (ISR o bucle de init) y forzar un log allí.