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.
Monitor Global de Accesos VRAM y Búsqueda de Rutinas de Carga
Resumen
Implementación de cinco monitores globales para rastrear TODOS los accesos a VRAM sin importar dónde ocurran en el flujo de ejecución. El análisis del Step 0294 rechazó parcialmente la hipótesis: las ISRs se ejecutan pero no acceden a VRAM, y el código post-BG tampoco accede. Necesitamos determinar si el código de carga existe y cuándo debería ejecutarse, o si simplemente no existe en esta fase del juego.
Los nuevos monitores detectan accesos a VRAM en cualquier momento del flujo, correlacionan PCs con accesos VRAM, identifican secuencias consecutivas de carga, detectan copias desde ROM usando LDIR, y rastrean el timing de accesos VRAM.
Concepto de Hardware
Video RAM (VRAM) y Carga de Tiles
La VRAM (0x8000-0x9FFF) contiene dos tipos de datos:
- Tile Data (0x8000-0x97FF): 384 tiles de 8x8 píxeles, cada tile ocupa 16 bytes (2 bytes por fila de 8 píxeles).
- Tile Maps (0x9800-0x9FFF): Dos mapas de tiles que indican qué tile se muestra en cada posición de la pantalla.
Los tiles se cargan típicamente desde la ROM del cartucho a VRAM usando instrucciones de bloque como LDIR (Load, Increment, Repeat),
que copia una secuencia de bytes desde una dirección fuente (ROM) a una dirección destino (VRAM).
Patrones de Carga de Tiles
Los juegos cargan tiles usando varios métodos:
- LDIR (0xED 0xB0): Patrón más común. Copia (HL++) a (DE++), decrementa BC, repite hasta BC=0.
- Loops manuales:
LD A,(HL) ; LD (DE),A ; INC HL ; INC DE ; DEC BC ; JR NZ - Escritura directa:
LD (HL+), AoLD (HL), nen secuencias consecutivas
Una secuencia típica carga 16 bytes consecutivos (un tile completo) desde una dirección en ROM a una dirección en VRAM.
Timing de Carga
Los tiles pueden cargarse en varios momentos:
- Durante la inicialización: Antes del primer frame, cuando el LCD está apagado
- Durante V-Blank: Cuando VRAM es accesible (aunque esto es más común para actualizaciones)
- Durante H-Blank: Limitado, solo en ciertos modos de LCD-STAT
- En el flujo principal: En cualquier momento cuando VRAM es accesible
Fuente: Pan Docs - "Video RAM (VRAM)", "CPU Instruction Set - LDIR", "Tile Data", "LCD Modes"
Implementación
Se implementaron cinco monitores globales en CPU::step() que detectan accesos a VRAM sin importar dónde ocurran
en el flujo de ejecución. Todos los monitores se ejecutan antes de cualquier early return para asegurar que capturamos todas
las ejecuciones.
Componentes creados/modificados
- CPU.cpp: Añadidos cinco monitores globales después de capturar
original_pc. - CPU.cpp: Añadido
#include <map>para el monitor de correlación PC-VRAM.
Monitores Implementados
[VRAM-ACCESS-GLOBAL] - Monitor Global de Accesos VRAM
Detecta TODOS los accesos de escritura a VRAM (0x8000-0x9FFF) independientemente de dónde ocurran. Verifica si HL apunta a VRAM cuando se ejecutan opcodes de escritura:
LD (HL+), A(0x22)LD (HL-), A(0x32)LD (HL), A(0x77)LD (HL), n(0x36)LD (HL), r(0x70-0x75)
Para cada acceso, reporta PC, opcode, dirección VRAM, valor escrito, si es Tile Data o Tile Map, Tile ID aproximado, si es dato real o limpieza, y banco ROM actual. Límite: 1000 accesos.
[PC-VRAM-CORRELATION] - Correlación PC-VRAM
Usa un std::map<uint16_t, int> para rastrear qué PCs acceden a VRAM y cuántas veces. Imprime
inmediatamente cuando detecta un PC nuevo o cuando es dato (no limpieza). Esto permite identificar rutinas específicas
que cargan tiles.
[LOAD-SEQUENCE] - Secuencias de Carga
Detecta secuencias consecutivas de escrituras a VRAM que podrían ser carga de tiles. Rastrea direcciones consecutivas (incremento o decremento) y reporta cuando se completa una secuencia de 16 bytes (un tile completo). Alerta especial cuando se detecta una secuencia completa.
[ROM-TO-VRAM] - Copias desde ROM
Detecta cuando se ejecuta LDIR (0xED 0xB0) con DE apuntando a VRAM. Esto indica una copia bloque desde ROM
(HL) a VRAM (DE) de longitud BC. Reporta PC, direcciones origen y destino, longitud y banco ROM.
[TIMING-VRAM] - Timing de Accesos VRAM
Rastrea el timing de accesos a VRAM usando un contador de instrucciones aproximado. Calcula el frame aproximado basado en instrucciones (asumiendo ~4 ciclos por instrucción promedio). Reporta PC, frame aproximado, LY (scanline actual), estado del LCD (ON/OFF), estado de BG Display (ON/OFF), dirección VRAM y valor escrito.
Decisiones de diseño
Los monitores usan variables static para mantener estado entre llamadas. Esto es apropiado porque los monitores
deben rastrear el estado global del sistema durante toda la ejecución. El monitor de correlación usa std::map
para almacenar eficientemente el conteo de accesos por PC.
El límite de 1000 accesos para [VRAM-ACCESS-GLOBAL] previene la saturación de logs mientras permite capturar suficiente información para análisis. El frame counter aproximado en [TIMING-VRAM] es suficiente para identificar el timing relativo de los accesos sin necesidad de acceso directo al frame counter real de PPU.
Archivos Afectados
src/core/cpp/CPU.cpp- Añadidos cinco monitores globales de accesos VRAMsrc/core/cpp/CPU.cpp- Añadido#include <map>para monitor de correlación
Tests y Verificación
El código compiló exitosamente sin errores. Los monitores están listos para ejecución.
- Compilación:
python setup.py build_ext --inplace- Exitoso - Validación de sintaxis: Sin errores de linter
- Validación de módulo compilado C++: Módulo
viboy_corecompilado correctamente
Nota: Los monitores generarán logs durante la ejecución del emulador. El análisis de estos logs permitirá determinar si hay accesos a VRAM en algún momento del flujo y cuándo ocurren.
Fuentes Consultadas
- Pan Docs: Video RAM (VRAM)
- Pan Docs: CPU Instruction Set - LDIR
- Pan Docs: Tile Data
- Pan Docs: LCD Modes
Nota: Implementación basada en documentación técnica de Pan Docs y conocimiento general de arquitectura LR35902.
Integridad Educativa
Lo que Entiendo Ahora
- Monitoreo Global: Para encontrar código de carga que puede ejecutarse en cualquier momento, necesitamos monitores que rastreen TODOS los accesos a VRAM, no solo en contextos específicos como ISRs o flujo principal después de eventos.
- Correlación PC-VRAM: Identificar qué rutinas específicas (PCs) acceden a VRAM permite encontrar el código de carga incluso si se ejecuta en momentos inesperados.
- Secuencias de Carga: Los tiles se cargan típicamente en secuencias consecutivas de 16 bytes, lo cual es un patrón detectable.
- LDIR: La instrucción LDIR es el método más común para copiar bloques de datos desde ROM a VRAM.
Lo que Falta Confirmar
- Existencia del código de carga: ¿Existe código que carga tiles en esta fase del juego, o el juego carga tiles más tarde?
- Timing de carga: Si el código existe, ¿cuándo se ejecuta? ¿Durante inicialización, V-Blank, o en otro momento?
- Condiciones de ejecución: Si el código existe pero no se ejecuta, ¿qué condiciones faltan?
Hipótesis y Suposiciones
El análisis del Step 0294 rechazó parcialmente la hipótesis de que el código de carga está en una ISR. Los nuevos monitores permitirán probar nuevas hipótesis:
- Hipótesis A: El código de carga existe pero se ejecuta ANTES de habilitar BG Display
- Hipótesis B: El código de carga existe pero se ejecuta MUCHO DESPUÉS de habilitar BG Display
- Hipótesis C: El código de carga existe pero usa métodos no detectados (ej: DMA no estándar, acceso indirecto)
- Hipótesis D: El código de carga NO existe en esta fase del juego - el juego carga tiles más tarde o en otra pantalla
Próximos Pasos
- [ ] Ejecutar el emulador con los nuevos monitores activos
- [ ] Analizar logs para determinar si hay accesos a VRAM en algún momento
- [ ] Identificar rutinas específicas que acceden a VRAM (si existen)
- [ ] Detectar secuencias de carga (si existen)
- [ ] Determinar el timing de accesos a VRAM
- [ ] Concluir si el código de carga existe o no en esta fase del juego