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.
Rastreo de Interrupciones V-Blank
Resumen
Se añadieron logs de diagnóstico críticos para monitorizar el despacho de interrupciones en la CPU, específicamente para detectar si la interrupción V-Blank (0x0040) se está ejecutando correctamente después de que el juego enciende el LCD. El diagnóstico incluye un log informativo con el símbolo ⚡ cuando se despacha una interrupción, mostrando el vector, el PC previo y el tipo de interrupción. Adicionalmente, se añadió un log en el renderer para detectar cuando LCDC es 0x80 (LCD ON, BG OFF), un estado crítico que indica que el juego espera la interrupción V-Blank para configurar el resto de los gráficos.
Concepto de Hardware
En la Game Boy, cuando un juego enciende el LCD escribiendo 0x80 en el registro LCDC (0xFF40),
está activando el bit 7 (LCD Enable) pero dejando el bit 0 (BG Display) en 0. Esto significa que el LCD está
encendido pero el fondo no se dibuja todavía.
El flujo típico de inicialización de un juego es:
- Encender LCD: Escribir
0x80en LCDC (LCD ON, BG OFF) - Esperar V-Blank: El juego espera a que la PPU genere la interrupción V-Blank (vector 0x0040)
- Configurar gráficos: Dentro del handler de V-Blank, el juego activa el fondo y sprites (escribe
0x93o similar en LCDC)
Si la interrupción V-Blank no se despacha correctamente después del paso 1, el juego se queda congelado esperando una interrupción que nunca llega. Esto puede ocurrir si:
- IME está desactivado: La CPU tiene las interrupciones deshabilitadas (IME=False)
- IE no está configurado: El registro IE (0xFFFF) no tiene el bit 0 (V-Blank) activado
- IF no se está generando: La PPU no está generando correctamente el flag de interrupción en IF (0xFF0F)
Fuente: Pan Docs - Interrupts, V-Blank Interrupt, LCD Control Register
Implementación
Se añadieron dos puntos de diagnóstico estratégicos:
1. Log de Despacho de Interrupciones (CPU)
En src/cpu/core.py, método handle_interrupts(), se añadió un log informativo
justo después de que la CPU acepta una interrupción y salta al vector. El log muestra:
- Vector de interrupción (0x0040 para V-Blank, 0x0048 para STAT, etc.)
- PC previo (dirección donde estaba la CPU antes de saltar)
- Tipo de interrupción (V-Blank, LCD STAT, Timer, Serial, Joypad)
Este log se ejecuta solo cuando la interrupción se despacha realmente, es decir, cuando: IME=True, IE tiene el bit activado, IF tiene el bit activado, y la CPU acepta la interrupción.
2. Log de Estado LCDC 0x80 (Renderer)
En src/gpu/renderer.py, método render_frame(), se añadió un log de debug
que se activa cuando LCDC es exactamente 0x80. Este estado indica que el LCD está encendido
pero el fondo está apagado, lo cual es un estado transitorio que el juego usa mientras espera V-Blank.
Decisiones de diseño
- Nivel de log INFO para interrupciones: Se usa
logger.info()para que el log sea visible incluso sin modo debug, ya que es crítico para el diagnóstico. - Nivel de log DEBUG para LCDC 0x80: Se usa
logger.debug()porque es menos crítico y puede generar muchos mensajes si el juego permanece en ese estado. - Símbolo ⚡ para interrupciones: Se añadió un símbolo visual distintivo para facilitar la búsqueda en los logs.
Archivos Afectados
src/cpu/core.py- Añadido log informativo enhandle_interrupts()cuando se despacha una interrupciónsrc/gpu/renderer.py- Añadido log de debug cuando LCDC es 0x80
Tests y Verificación
Modo de ejecución: Manual con ROM comercial (Pokémon Red, aportada por el usuario, no distribuida)
Comando ejecutado: python main.py pkmn.gb
Entorno: Windows 10, Python 3.13.5
Criterio de éxito:
- Ver el mensaje
CRITICAL: [TRAP LCDC] INTENTO DE CAMBIO LCDC: 00 -> 80(confirmado en paso anterior) - Ver el mensaje
⚡ INTERRUPT DISPATCHED! Vector: 0040 | PC Previo: XXXX | Tipo: V-Blankdespués del cambio de LCDC - Si NO aparece el mensaje de interrupción, identificar por qué (IME=False, IE sin configurar, IF no generado)
Observación esperada:
- Si aparece
⚡ INTERRUPT DISPATCHED! Vector: 0040: La CPU funciona correctamente y el problema es gráfico (renderer no dibuja lo que el juego espera tras V-Blank) - Si NO aparece: El bug está en el sistema de interrupciones (IME, IE, IF, o generación de V-Blank por la PPU)
Resultado: Draft - Pendiente de ejecución manual para verificar si aparece el log de interrupción
Notas legales: La ROM de Pokémon Red es aportada por el usuario para pruebas locales, no se distribuye ni se enlaza en el repositorio.
Fuentes Consultadas
Integridad Educativa
Lo que Entiendo Ahora
- Flujo de inicialización de juegos: Los juegos encienden el LCD con BG apagado (0x80) y esperan V-Blank para configurar el resto de gráficos. Si V-Blank no se despacha, el juego se congela.
- Condiciones para interrupciones: Una interrupción se despacha solo si IME=True, IE tiene el bit activado, e IF tiene el bit activado. Si alguna de estas condiciones falla, la interrupción no se procesa.
- Diagnóstico de interrupciones: El log de despacho de interrupciones permite identificar si el problema está en la CPU (no acepta interrupciones) o en la PPU (no genera V-Blank).
Lo que Falta Confirmar
- Estado de IME en Pokémon: Verificar si IME está activado cuando el juego escribe 0x80 en LCDC. Si IME=False, las interrupciones no se procesarán aunque estén pendientes.
- Configuración de IE: Verificar si el registro IE (0xFFFF) tiene el bit 0 (V-Blank) activado. Si no está activado, la interrupción no se procesará aunque IF esté activado.
- Generación de V-Blank por PPU: Verificar si la PPU está generando correctamente el flag de interrupción en IF (0xFF0F) cuando entra en modo V-Blank.
Hipótesis y Suposiciones
Hipótesis principal: El juego enciende el LCD (0x80), pero la interrupción V-Blank no se despacha porque: (a) IME está desactivado, (b) IE no tiene el bit 0 activado, o (c) la PPU no está generando correctamente el flag en IF.
Próximo paso de verificación: Ejecutar el emulador y buscar el log ⚡ INTERRUPT DISPATCHED!.
Si aparece, el problema es gráfico. Si no aparece, el problema está en el sistema de interrupciones.
Próximos Pasos
- [ ] Ejecutar el emulador con Pokémon Red y verificar si aparece el log
⚡ INTERRUPT DISPATCHED! Vector: 0040 - [ ] Si NO aparece: Añadir logs adicionales para verificar el estado de IME, IE, e IF cuando se escribe 0x80 en LCDC
- [ ] Si aparece: Investigar por qué el renderer no dibuja correctamente después de V-Blank (verificar configuración de paletas, VRAM, tilemap)
- [ ] Verificar que la PPU está generando correctamente el flag de V-Blank en IF cuando entra en modo V-Blank