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

Auditoría del Handler de V-Blank

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

Resumen

Este Step implementa la Operación "Deep Handler Audit" para investigar el flujo de ejecución desde el vector de interrupción de V-Blank (0x0040). El análisis del Step 0280 confirmó que las interrupciones están habilitadas correctamente (IE=0x0D, IME=1) y que la CPU salta al vector 0x0040 constantemente. Sin embargo, el juego sigue atrapado en el bucle de polling porque el handler de V-Blank no parece estar actualizando el flag de progreso en 0xD732.

Se implementó un rastreador que identifica la dirección de destino del salto (JP) en el vector 0x0040 y un Sniper de ejecución que captura las instrucciones dentro de la rutina de V-Blank hasta encontrar un RETI (0xD9). Esto permitirá identificar qué hace el código del juego una vez que entra en la interrupción y por qué no se comunica con el bucle principal.

Concepto de Hardware

El Game Boy utiliza vectores de interrupción fijos en la memoria baja (Banco 0) para manejar eventos de hardware. Cuando ocurre una interrupción habilitada, el hardware realiza automáticamente un PUSH PC, desactiva el IME y salta a una dirección específica:

  • 0x0040: V-Blank (Vertical Blanking)
  • 0x0048: LCD STAT
  • 0x0050: Timer
  • 0x0058: Serial
  • 0x0060: Joypad

Como estos vectores solo disponen de 8 bytes de espacio antes del siguiente vector, la práctica estándar de los desarrolladores es colocar una instrucción JP nn (3 bytes) que salta a una rutina más larga ubicada en otra parte de la ROM. La rutina de interrupción (ISR) debe terminar con RETI (Return and Enable Interrupts), que recupera el PC de la pila y reactiva el maestro de interrupciones (IME).

Fuente: Pan Docs - "Interrupts": "When an interrupt is serviced, the PC is pushed onto the stack and the CPU jumps to the interrupt vector. The IME flag is reset... The ISR usually finishes with a RETI instruction."

Implementación

Se añadieron dos mecanismos de rastreo en CPU.cpp:

1. Rastreo del Destino del Salto en 0x0040

Cuando la CPU alcanza el vector de V-Blank, leemos los dos bytes siguientes en memoria (Little-Endian) para identificar a qué dirección salta el JP nn.

// Ubicación: CPU::step()
if (original_pc == 0x0040) {
    uint16_t jump_target = mmu_->read(0x0041) | (static_cast(mmu_->read(0x0042)) << 8);
    printf("[VBLANK-TRACE] Vector 0x0040: JP 0x%04X detectado. Iniciando rastreo del handler...\n", jump_target);
}

2. Sniper de Ejecución del Handler

Se implementó un Sniper que captura las instrucciones ejecutadas dentro del handler. El rastreo se activa al entrar en 0x0040 y se detiene cuando se encuentra la instrucción RETI (0xD9) o se alcanza un límite de 100 instrucciones.

// Ubicación: CPU::step()
static bool in_vblank_handler = false;
static int handler_step_count = 0;

if (original_pc == 0x0040) {
    in_vblank_handler = true;
    handler_step_count = 0;
}

if (in_vblank_handler && handler_step_count < 100) {
    uint8_t op = mmu_->read(original_pc);
    printf("[HANDLER-EXEC] PC:0x%04X OP:0x%02X | A:0x%02X HL:0x%04X | IME:%d\n",
           original_pc, op, regs_->a, regs_->get_hl(), ime_ ? 1 : 0);
    handler_step_count++;
    
    if (op == 0xD9) {
        printf("[HANDLER-EXIT] RETI detectado en PC:0x%04X. Fin del rastreo del handler.\n", original_pc);
        in_vblank_handler = false;
    }
}

Archivos Afectados

  • src/core/cpp/CPU.cpp - Implementación del rastreador del destino del salto y Sniper de ejecución del handler de V-Blank

Tests y Verificación

La verificación se realizará ejecutando Pokémon Red y analizando el flujo de instrucciones dentro del handler.

Comando ejecutado:

python main.py roms/pkmn.gb > debug_step_0281.log 2>&1

Validación: Si el log muestra el mensaje [VBLANK-TRACE] seguido de múltiples [HANDLER-EXEC], habremos capturado el flujo del handler. Buscaremos instrucciones de escritura en memoria (como LD (HL), A o LD (nnnn), A) que afecten a la dirección 0xD732.

Validación de módulo compilado C++:

python setup.py build_ext --inplace

Fuentes Consultadas

Integridad Educativa

Lo que Entiendo Ahora

  • Vectores de Interrupción: Son direcciones fijas donde la CPU salta cuando ocurre un evento. Debido a su tamaño limitado, suelen contener saltos a rutinas más complejas.
  • Handler de V-Blank: Es el responsable de realizar las actualizaciones gráficas y de lógica de juego que deben sincronizarse con el final del dibujado de la pantalla.
  • RETI: Es la instrucción crítica que cierra el ciclo de la interrupción, recuperando el flujo normal y reactivando la capacidad de recibir nuevas interrupciones.

Próximos Pasos

  • [ ] Recompilar el núcleo C++ y ejecutar Pokémon Red
  • [ ] Analizar el log [HANDLER-EXEC] para identificar a dónde salta el V-Blank
  • [ ] Verificar si el handler intenta modificar 0xD732
  • [ ] Si el handler salta a una zona vacía o corrupta, investigar por qué el banco de ROM 0 no es accesible