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 0259: VRAM Write Monitor & MBC Check
Resumen
Este Step instrumenta la MMU para monitorear las escrituras en VRAM y analiza la lógica de lectura de ROM para confirmar si hay soporte de MBC (Memory Bank Controllers). El objetivo es determinar si la VRAM está vacía porque el juego intenta leer gráficos de bancos ROM no mapeados, lo que explicaría por qué la CPU copia ceros a la VRAM.
Hipótesis Principal: Si la VRAM está completamente vacía (todo ceros), la PPU renderizará píxeles de índice 0 (verdes/blancos). Con la paleta forzada en C++ (Step 0257) y Python (Step 0256), si la pantalla sigue verde incluso con juegos que tienen el LCD encendido (como Pokémon Red, `LCDC:E3`), la única explicación lógica que queda es que la VRAM está llena de ceros. Si la VRAM es todo 0, la PPU dibuja el "Color 0" perfectamente, que es... verde.
Teoría del MBC: Si la CPU funciona (Mario y Pokémon corren), ¿por qué no copian los gráficos? La teoría principal es que el mapeo de memoria (MBC) no está implementado. Si el juego intenta leer gráficos del Banco 2, 3, etc., pero solo se cargó el Banco 0, leerá basura o ceros, y copiará esos ceros a la VRAM.
Concepto de Hardware
VRAM (Video RAM)
La VRAM en la Game Boy ocupa el rango `0x8000-0x9FFF` (8KB) y contiene:
- Tile Data (0x8000-0x97FF): Datos de los tiles (gráficos) que se usan para renderizar el fondo y los sprites. Cada tile ocupa 16 bytes (2 bytes por línea de 8 píxeles).
- Tile Map (0x9800-0x9FFF): Mapas de tiles que indican qué tile se dibuja en cada posición del fondo. Cada byte del mapa apunta a un tile en el Tile Data.
MBC (Memory Bank Controllers)
Los cartuchos de Game Boy pueden tener diferentes tamaños de ROM:
- ROM ONLY (32KB): Cabe entero en el espacio de direcciones `0x0000-0x7FFF`. No necesita MBC.
- MBC1/MBC3 (>32KB): Usan un Memory Bank Controller para intercambiar bancos de ROM. El espacio `0x0000-0x3FFF` siempre mapea al Banco 0, pero el espacio `0x4000-0x7FFF` puede mapear a diferentes bancos (1, 2, 3, etc.) escribiendo en registros especiales del MBC.
Problema Crítico: Si nuestro emulador C++ (`MMU.cpp`) NO implementa MBC1/MBC3, el juego intenta leer gráficos del Banco X, pero lee el Banco 1 (o basura), o ceros. La CPU copia esos "ceros" a la VRAM. Resultado: Pantalla Verde.
Fuente: Pan Docs - "Memory Bank Controllers", "Cartridge Types", "Memory Map"
Implementación
1. Monitor de Escrituras en VRAM (`MMU.cpp::write`)
Se añadió un monitor específico para el rango de VRAM (`0x8000` - `0x9FFF`) que registra las primeras 50 escrituras:
// --- Step 0259: VRAM WRITE MONITOR ---
// Monitorizar las primeras 50 escrituras en VRAM para ver qué datos llegan
// Si la VRAM está vacía (ceros), la PPU renderizará píxeles de índice 0 (verdes/blancos).
// Si vemos valores distintos de cero, significa que la CPU está copiando datos.
// Si solo vemos ceros, el problema está en la carga de datos gráficos (posiblemente MBC).
static int vram_write_counter = 0;
if (addr >= 0x8000 && addr <= 0x9FFF) {
if (vram_write_counter < 50) {
printf("[VRAM] PC:%04X -> Write VRAM [%04X] = %02X\n", debug_current_pc, addr, value);
vram_write_counter++;
}
}
// -----------------------------------------
Este monitor registra:
- PC: El Program Counter de la CPU cuando se ejecuta la escritura (para saber desde dónde escribe el juego).
- Addr: La dirección de VRAM donde se escribe.
- Value: El valor que se escribe. Si son todos `00`, la CPU está copiando ceros. Si son `FF` o variados, hay datos.
2. Análisis de Lectura de ROM (`MMU.cpp::read`)
Se añadió un comentario crítico que documenta la falta de soporte de MBC:
// --- Step 0259: ANÁLISIS DE LECTURA DE ROM (MBC) ---
// IMPORTANTE: La implementación actual NO soporta MBC (Memory Bank Controllers).
// La ROM se carga de forma plana en memory_[0x0000-0x7FFF] mediante load_rom().
//
// Para juegos grandes (>32KB):
// - Banco 0 (0x0000-0x3FFF): Cargado correctamente
// - Banco 1+ (0x4000-0x7FFF): Si el juego intenta cambiar de banco, leerá
// basura o ceros porque solo se cargó el banco 0.
//
// Esto puede explicar por qué la VRAM está vacía: el juego intenta leer gráficos
// del banco 2, 3, etc., pero lee ceros, y copia esos ceros a la VRAM.
//
// Fuente: Pan Docs - "Memory Bank Controllers", "Cartridge Types"
// -----------------------------------------
3. Revisión de `load_rom()`
El método `load_rom()` simplemente copia la ROM directamente a `memory_` empezando en `0x0000`, sin ningún manejo de bancos:
void MMU::load_rom(const uint8_t* data, size_t size) {
// Validar que los datos no excedan el tamaño de memoria
size_t copy_size = (size > MEMORY_SIZE) ? MEMORY_SIZE : size;
// Copiar los datos ROM a memoria, empezando en 0x0000
// Usamos memcpy para máxima velocidad
std::memcpy(memory_.data(), data, copy_size);
}
Problema: Si la ROM es mayor de 32KB, solo se cargan los primeros 32KB. Si el juego intenta leer del banco 1, 2, etc. (direcciones `0x4000-0x7FFF`), leerá basura o ceros porque solo se cargó el banco 0.
Decisiones de Diseño
- Monitor limitado a 50 escrituras: Se limita a las primeras 50 escrituras para no saturar el log. Esto es suficiente para ver si la CPU está copiando ceros o datos reales.
- Incluir PC en el log: Se incluye el Program Counter para saber desde dónde escribe el juego (probablemente una rutina de copia `LDI` o `LD`).
- Documentación de MBC: Se añadió un comentario crítico que documenta la falta de soporte de MBC, explicando por qué la VRAM puede estar vacía.
Archivos Afectados
src/core/cpp/MMU.cpp- Modificado el métodowrite()para añadir monitor de escrituras en VRAM (Step 0259).src/core/cpp/MMU.cpp- Modificado el métodoread()para añadir comentario sobre falta de soporte de MBC (Step 0259).
Tests y Verificación
Validación del Monitor VRAM:
- Recompilación: Ejecutar
.\rebuild_cpp.ps1para recompilar la extensión C++. - Ejecución: Ejecutar
python main.py roms/pkmn.gb(Pokémon es ideal porque sabemos que intenta dibujar). - Observación del Log: Buscar en el log las líneas
[VRAM] PC:XXXX -> Write VRAM [XXXX] = XX. - Interpretación:
- Si los valores son `00`: La CPU está copiando ceros. Esto confirma la teoría de MBC roto (el juego intenta leer gráficos del banco X, pero lee ceros).
- Si los valores son `FF` o variados: Hay datos. Entonces el problema vuelve a ser la PPU (no está leyendo correctamente los tiles desde VRAM).
- Mira el `PC`: ¿Desde dónde escribe? (Probablemente una rutina de copia `LDI` o `LD`).
Comando de Prueba:
.\rebuild_cpp.ps1
python main.py roms/pkmn.gb
Resultado Esperado: El log debe mostrar las primeras 50 escrituras en VRAM con el formato [VRAM] PC:XXXX -> Write VRAM [XXXX] = XX. Si todos los valores son `00`, confirmamos que la CPU está copiando ceros, lo que sugiere un problema de MBC.
Validación de Módulo Compilado C++: El código se ejecuta en C++ compilado, por lo que es necesario recompilar la extensión antes de ejecutar. El monitor se ejecuta en tiempo real durante la emulación, registrando las escrituras en VRAM.
Fuentes Consultadas
- Pan Docs: Memory Map
- Pan Docs: Cartridge Header
- Pan Docs: MBC1
- Pan Docs: MBC3
- Pan Docs: Video Display
- Pan Docs: VRAM
Integridad Educativa
Lo que Entiendo Ahora
- MBC (Memory Bank Controllers): Los cartuchos grandes (>32KB) usan MBC para intercambiar bancos de ROM. El espacio `0x0000-0x3FFF` siempre mapea al Banco 0, pero el espacio `0x4000-0x7FFF` puede mapear a diferentes bancos escribiendo en registros especiales del MBC.
- Problema de MBC no implementado: Si el juego intenta leer gráficos del banco 2, 3, etc., pero solo se cargó el banco 0, leerá basura o ceros. La CPU copia esos "ceros" a la VRAM, resultando en una pantalla verde.
- Monitor de Escrituras: Al monitorear las escrituras en VRAM, podemos ver qué datos está copiando la CPU. Si todos son ceros, confirmamos que el problema está en la carga de datos gráficos (posiblemente MBC).
- Lógica Negativa: Si la PPU funcionara y tuviera datos distintos de cero, veríamos píxeles grises o negros. Si solo vemos verde, significa que la PPU solo está leyendo ceros. Por lo tanto, la VRAM está vacía (o llena de ceros).
Lo que Falta Confirmar
- Valores en VRAM: Ejecutar el diagnóstico con Pokémon Red y verificar los valores que se escriben en VRAM. Si todos son `00`, confirmamos que la CPU está copiando ceros, lo que sugiere un problema de MBC.
- Implementación de MBC: Si confirmamos que el problema es MBC, debemos implementar soporte básico de MBC1/MBC3 en la MMU para permitir que los juegos grandes carguen gráficos desde bancos superiores.
- Timing de Carga: Si la VRAM contiene datos pero la pantalla sigue verde, debemos investigar por qué la PPU no está leyendo correctamente los tiles desde VRAM o por qué el Tile Map apunta a tiles vacíos.
Hipótesis y Suposiciones
Hipótesis Principal: Si la CPU funciona (Mario y Pokémon corren), ¿por qué no copian los gráficos? La teoría principal es que el mapeo de memoria (MBC) no está implementado. Si el juego intenta leer gráficos del banco 2, 3, etc., pero solo se cargó el banco 0, leerá basura o ceros, y copiará esos ceros a la VRAM.
Suposición: Asumimos que el monitor de escrituras en VRAM (primeras 50 escrituras) es suficiente para determinar si la CPU está copiando ceros o datos reales. Si todos los valores son `00`, confirmamos que el problema está en la carga de datos gráficos (posiblemente MBC).
Próximos Pasos
- [ ] Recompilar:
.\rebuild_cpp.ps1 - [ ] Ejecutar:
python main.py roms/pkmn.gb(Pokémon es ideal porque sabemos que intenta dibujar). - [ ] Observar los logs de
[VRAM]:- ¿Ves logs de `[VRAM]`? Si no, la CPU no está escribiendo en VRAM (problema más grave).
- Mira los valores (`Val`):
- Si son `00`: La CPU está copiando ceros. (Confirma teoría de MBC roto).
- Si son `FF` o variados: Hay datos. Entonces el problema vuelve a ser la PPU.
- Mira el `PC`: ¿Desde dónde escribe? (Probablemente una rutina de copia `LDI` o `LD`).
- [ ] Si confirmamos que el problema es MBC:
- Implementar soporte básico de MBC1/MBC3 en la MMU.
- Detectar el tipo de cartucho desde el header de la ROM.
- Implementar cambio de bancos cuando el juego escribe en `0x0000-0x7FFF` (registros del MBC).
- [ ] Si la VRAM contiene datos pero la pantalla sigue verde:
- Investigar por qué la PPU no está leyendo correctamente los tiles desde VRAM.
- Verificar que el Tile Map apunta a tiles válidos (no a tiles vacíos).
- Verificar que la PPU está decodificando correctamente los tiles desde VRAM.