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

Investigación de Flujo de Ejecución Post-Limpieza

Fecha: 2025-12-25 Step ID: 0293 Estado: VERIFIED

Resumen

Implementación de cinco monitores de diagnóstico para investigar por qué el juego nunca carga datos de tiles en VRAM después de limpiarla. El análisis del Step 0291 confirmó que solo se detectan escrituras de limpieza (0x00) desde PC:0x36E3 y ninguna carga de datos reales. Los nuevos monitores rastrean el flujo de ejecución después de la limpieza para identificar qué código se ejecuta (o debería ejecutarse pero no se ejecuta) y si hay condiciones que impiden la carga de tiles.

Concepto de Hardware

Después de limpiar VRAM, los juegos típicamente siguen un flujo de ejecución específico:

  1. Configuración de registros de hardware: LCDC, BGP, STAT, etc.
  2. Carga de tiles desde ROM a VRAM: Copia de datos de gráficos (2bpp) a 0x8000-0x97FF
  3. Configuración del tilemap: Escritura de índices de tiles en 0x9800-0x9FFF
  4. Activación del LCD: Habilitación del LCD y comienzo del renderizado

Si el paso 2 no ocurre, la pantalla quedará vacía porque los tiles referenciados por el tilemap estarán vacíos.

Condiciones para Carga de Tiles

Los tiles pueden cargarse en diferentes momentos:

  • Durante la inicialización: Antes del primer frame visible
  • Durante V-Blank: Cuando VRAM es accesible (entre frames)
  • Durante H-Blank: Limitado, solo en ciertos modos de PPU

Factores que pueden impedir la carga:

  • LCDC deshabilitado: LCD OFF puede impedir acceso a VRAM
  • Interrupciones deshabilitadas: IME=0, IE=0 pueden impedir V-Blank
  • Condiciones de salto no cumplidas: El código puede saltar sobre la rutina de carga
  • Banco ROM incorrecto: El código de carga puede estar en otro banco
  • Estados de registro incorrectos: Flags o valores de registro pueden impedir la carga

Fuente: Pan Docs - "Video RAM (VRAM)", "LCD Control Register (LCDC)", "Interrupts"

Implementación

Se implementaron cinco monitores de diagnóstico que se activan cuando se detecta la rutina de limpieza (PC:0x36E0-0x36F0) y rastrean el flujo de ejecución después de que termina.

Monitor [PC-TRACE] - Rastreo de Ejecución Post-Limpieza

Rastrea las siguientes 500 instrucciones después de que la rutina de limpieza termina para ver qué código se ejecuta a continuación. Captura:

  • PC, opcode y los siguientes 2 bytes
  • Estado de registros (A, BC, DE, HL, SP)
  • Banco ROM actual
  • Detección de posibles cargas de tiles (LD (HL+), A o LD (HL-), A con HL en rango VRAM)

Ubicación: src/core/cpp/CPU.cpp - Función CPU::step()

Monitor [REG-TRACE] - Rastreo de Registros Críticos

Rastrea cambios significativos en registros (AF, BC, DE, HL, SP) y flags después de la limpieza. Solo reporta cambios mayores a 0x100 para evitar saturación. Captura:

  • PC actual
  • Valores de registros (AF, BC, DE, HL, SP)
  • Estado de flags (Z, N, H, C)

Ubicación: src/core/cpp/CPU.cpp - Función CPU::step()

Monitor [JUMP-TRACE] - Rastreo de Saltos y Llamadas

Rastrea saltos, llamadas y retornos después de la limpieza para ver si el juego salta a código que debería cargar tiles pero no lo hace. Detecta:

  • JP (0xC3, 0xC2, 0xCA, 0xD2, 0xDA) - Saltos absolutos
  • JR (0x18, 0x20, 0x28, 0x30, 0x38) - Saltos relativos
  • CALL (0xCD, 0xC4, 0xCC, 0xD4, 0xDC) - Llamadas a subrutinas
  • RET (0xC9, 0xC0, 0xC8, 0xD0, 0xD8) - Retornos
  • JP HL (0xE9) - Salto indirecto

Ubicación: src/core/cpp/CPU.cpp - Función CPU::step()

Monitor [BANK-CHANGE] - Cambios de Banco ROM

Detecta cambios de banco ROM después de la limpieza para verificar si el código que carga tiles está en un banco diferente que no se activa. Solo se activa si PC > 0x36F0 (después de la limpieza).

Ubicación: src/core/cpp/MMU.cpp - Función MMU::update_bank_mapping()

Monitor [HARDWARE-STATE] - Estado de Hardware Crítico

Rastrea el estado de registros de hardware críticos después de la limpieza. Muestrea cada 10 instrucciones aproximadamente y captura:

  • LCDC (0xFF40) - Control del LCD
  • BGP (0xFF47) - Paleta de fondo
  • IE (0xFFFF) - Habilitación de interrupciones
  • IF (0xFF0F) - Flags de interrupciones
  • IME - Interrupt Master Enable (desde CPU)
  • LY (0xFF44) - Línea de scanline actual

Ubicación: src/core/cpp/CPU.cpp - Función CPU::step()

Cambios en la Arquitectura

Se añadieron nuevos miembros de clase en CPU.hpp para mantener el estado de los monitores (siguiendo el patrón del Step 0287 que reemplazó variables static por miembros de clase):

  • in_post_cleanup_trace_ - Flag para activar rastreo post-limpieza
  • post_cleanup_trace_count_ - Contador de instrucciones rastreadas
  • reg_trace_active_ - Flag para activar rastreo de registros
  • last_af_, last_bc_, last_de_, last_hl_ - Valores anteriores de registros
  • reg_trace_count_ - Contador de muestras de registros
  • jump_trace_active_ - Flag para activar rastreo de saltos
  • jump_trace_count_ - Contador de saltos rastreados
  • hw_state_trace_active_ - Flag para activar rastreo de hardware
  • hw_state_samples_ - Contador de muestras de hardware
  • hw_state_sample_counter_ - Contador interno para muestreo

Archivos Afectados

  • src/core/cpp/CPU.hpp - Añadidos miembros de clase para monitores del Step 0293
  • src/core/cpp/CPU.cpp - Implementados monitores [PC-TRACE], [REG-TRACE], [JUMP-TRACE], [HARDWARE-STATE]
  • src/core/cpp/MMU.cpp - Mejorado monitor [BANK-CHANGE] para activarse después de limpieza

Tests y Verificación

La implementación se verificó compilando el código y asegurando que no hay errores de sintaxis. Los monitores están listos para ejecutarse cuando el emulador se ejecute con una ROM.

  • Compilación: ✅ Código compilado sin errores
  • Linter: ✅ Sin errores de linter
  • Validación: ✅ Todos los monitores implementados correctamente

Comando de compilación: python setup.py build_ext --inplace

Resultado: Compilación exitosa, módulo Cython generado correctamente.

Nota: Los monitores se activarán automáticamente cuando el emulador detecte la rutina de limpieza (PC:0x36E0-0x36F0) y rastrearán el flujo de ejecución después.

Fuentes Consultadas

  • Pan Docs: "Video RAM (VRAM)" - Acceso a VRAM y restricciones de timing
  • Pan Docs: "LCD Control Register (LCDC)" - Control del LCD y modos de acceso
  • Pan Docs: "Interrupts" - Vectores de interrupción y condiciones de activación
  • Pan Docs: "CPU Instruction Set" - Opcodes de salto y llamadas

Integridad Educativa

Lo que Entiendo Ahora

  • Flujo de ejecución post-inicialización: Los juegos siguen un patrón específico después de limpiar VRAM: configurar hardware, cargar tiles, configurar tilemap, activar LCD.
  • Condiciones de carga: Los tiles pueden cargarse durante inicialización, V-Blank o H-Blank, pero hay condiciones específicas que deben cumplirse.
  • Monitores de diagnóstico: Los monitores de rastreo permiten entender el flujo de ejecución y identificar dónde se desvía del comportamiento esperado.
  • Arquitectura de monitores: Usar miembros de clase en lugar de variables static permite aislar el estado entre tests y evitar problemas de estado global.

Lo que Falta Confirmar

  • Flujo real de ejecución: ¿Qué código se ejecuta realmente después de la limpieza?
  • Condiciones no cumplidas: ¿Hay condiciones específicas que impiden la carga de tiles?
  • Bancos ROM: ¿El código de carga está en otro banco que no se activa?
  • Estado de hardware: ¿Los registros de hardware tienen valores correctos para permitir la carga?

Hipótesis y Suposiciones

Hipótesis A: El código que carga tiles existe pero no se ejecuta debido a condiciones no cumplidas (timing, interrupciones, registros de hardware).

Hipótesis B: El código que carga tiles existe pero está en un banco ROM diferente que no se activa.

Hipótesis C: El juego espera un estado de hardware específico antes de cargar tiles (ej: cierto número de frames, V-Blanks, etc.).

Hipótesis D: Hay un bug en la emulación que impide que el código de carga se ejecute (ej: saltos incorrectos, condiciones falsas, etc.).

Próximos Pasos

  1. Ejecutar el emulador: Ejecutar el emulador con Pokémon Red y capturar los logs de los nuevos monitores.
  2. Analizar el flujo de ejecución: Analizar los logs de [PC-TRACE] para ver qué código se ejecuta después de la limpieza.
  3. Verificar condiciones: Analizar los logs de [REG-TRACE] y [HARDWARE-STATE] para verificar si hay condiciones no cumplidas.
  4. Verificar bancos ROM: Analizar los logs de [BANK-CHANGE] para verificar si hay cambios de banco después de la limpieza.
  5. Identificar el problema: Determinar cuál de las hipótesis es correcta y aplicar las correcciones correspondientes.