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.
V-Blank Polling: IF Independiente de IME
Resumen
Se verificó y documentó que el registro IF (Interrupt Flag, 0xFF0F) se actualiza siempre cuando ocurre V-Blank, independientemente del estado de IME (Interrupt Master Enable). Esto permite que los juegos hagan "polling" manual de IF para detectar V-Blank sin usar interrupciones automáticas. Se crearon tests específicos para validar este comportamiento crítico y se mejoró la documentación en el código para dejar claro este aspecto del hardware.
Concepto de Hardware
En la Game Boy, existen dos mecanismos para detectar eventos del hardware (V-Blank, Timer, etc.):
-
Interrupciones Automáticas: Si
IME=True,IEtiene el bit activo, yIFtiene el bit activo, la CPU automáticamente salta al vector de interrupción. -
Polling Manual: El juego lee manualmente el registro
IFy verifica si algún bit está activo. Si detecta V-Blank (bit 0), ejecuta su propia rutina de actualización.
CRÍTICO: El registro IF es hardware puro. Cuando ocurre un evento
(V-Blank, Timer, etc.), el hardware siempre activa el bit correspondiente en IF,
independientemente de:
- El estado de
IME(Interrupt Master Enable) - El estado de
IE(Interrupt Enable, 0xFFFF)
Esto significa que incluso si un juego ejecuta DI (Disable Interrupts, IME=False)
y nunca ejecuta EI (Enable Interrupts), el hardware sigue actualizando IF cuando
ocurre V-Blank. El juego puede leer IF manualmente y detectar V-Blank para actualizar gráficos.
Fuente: Pan Docs - Interrupts, V-Blank Interrupt Flag
Implementación
Se verificó que la implementación actual en src/gpu/ppu.py ya actualiza IF
correctamente cuando ocurre V-Blank, sin depender de IME. Sin embargo, se mejoró la
documentación para dejar explícito este comportamiento crítico.
Componentes creados/modificados
-
src/gpu/ppu.py: Se añadió documentación explícita en el métodostep()explicando queIFse actualiza siempre, independientemente deIME. -
tests/test_ppu_vblank_polling.py: Nuevo archivo con 3 tests que validan:test_vblank_sets_if_with_ime_false: Verifica queIFse activa conIME=Falsetest_vblank_if_persists_until_cleared: Verifica queIFpersiste hasta limpieza manualtest_vblank_if_independent_of_ie: Verifica queIFse actualiza independientemente deIE
Decisiones de diseño
La implementación actual ya era correcta: la PPU actualiza IF directamente llamando a
mmu.write_byte(0xFF0F, if_val | 0x01) sin verificar el estado de IME.
Esto es correcto porque IF es un registro de hardware que se actualiza automáticamente
cuando ocurre el evento, no cuando la CPU procesa la interrupción.
La MMU permite escribir libremente en 0xFF0F (no hay restricciones especiales), lo cual
es correcto porque el hardware puede actualizar IF en cualquier momento.
Archivos Afectados
src/gpu/ppu.py- Mejora de documentación en métodostep()para explicar queIFse actualiza independientemente deIMEtests/test_ppu_vblank_polling.py- Nuevo archivo con tests para validar V-Blank polling
Tests y Verificación
Se ejecutaron los tests nuevos para validar el comportamiento de V-Blank polling:
Comando ejecutado
pytest tests/test_ppu_vblank_polling.py -v
Entorno
- OS: Windows 10
- Python: 3.13.5
Resultado
============================= test session starts =============================
platform win32 -- Python 3.13.5, pytest-9.0.2, pluggy-1.6.0
collecting ... collected 3 items
tests/test_ppu_vblank_polling.py::TestPPUVBlankPolling::test_vblank_sets_if_with_ime_false PASSED [ 33%]
tests/test_ppu_vblank_polling.py::TestPPUVBlankPolling::test_vblank_if_persists_until_cleared PASSED [ 66%]
tests/test_ppu_vblank_polling.py::TestPPUVBlankPolling::test_vblank_if_independent_of_ie PASSED [100%]
======================== 3 passed, 2 warnings in 0.31s ========================
Qué valida
-
test_vblank_sets_if_with_ime_false: Valida que el registro
IFse actualiza cuando ocurre V-Blank (LY=144), incluso cuandoIME=False. Esto demuestra que el hardware actualizaIFindependientemente del estado deIME, permitiendo polling manual. -
test_vblank_if_persists_until_cleared: Valida que
IFpermanece activo hasta que el juego lo limpia manualmente, y que se reactiva en el siguiente V-Blank. Esto demuestra el comportamiento de polling: el juego puede leerIF, detectar V-Blank, hacer su trabajo, y limpiar el bit manualmente. -
test_vblank_if_independent_of_ie: Valida que
IFse actualiza incluso cuandoIE(Interrupt Enable) tiene el bit 0 deshabilitado. Esto demuestra queIFes hardware puro y no depende de la configuración deIE.
Código del test
Fragmento esencial del test principal:
def test_vblank_sets_if_with_ime_false(self) -> None:
"""Test: IF se actualiza cuando ocurre V-Blank, incluso con IME=False."""
mmu = MMU(None)
cpu = CPU(mmu)
ppu = PPU(mmu)
mmu.set_ppu(ppu)
# Configurar IME=False (interrupciones automáticas deshabilitadas)
cpu.ime = False
# Limpiar IF inicialmente
mmu.write_byte(IO_IF, 0x00)
# Avanzar PPU hasta V-Blank (línea 144)
total_cycles = 144 * 456
ppu.step(total_cycles)
# CRÍTICO: IF debe tener el bit 0 activado, incluso con IME=False
if_val = mmu.read_byte(IO_IF)
assert (if_val & 0x01) == 0x01
Por qué este test demuestra algo del hardware: Este test verifica que el registro IF
se comporta como hardware puro: se actualiza automáticamente cuando ocurre el evento (V-Blank), sin depender
de la configuración de software (IME). Esto es exactamente cómo funciona el hardware real de la
Game Boy, permitiendo que los juegos hagan polling manual incluso cuando las interrupciones automáticas están
deshabilitadas.
Fuentes Consultadas
- Pan Docs: Interrupts - Explicación de IF, IE, IME y polling
- Pan Docs: LCD Timing - V-Blank y registro LY
Integridad Educativa
Lo que Entiendo Ahora
-
IF es hardware puro: El registro
IF (0xFF0F)se actualiza automáticamente por el hardware cuando ocurre un evento (V-Blank, Timer, etc.), independientemente del estado deIMEoIE. Esto es diferente de otros sistemas donde los flags de interrupción pueden depender de la configuración de software. -
Polling vs Interrupciones Automáticas: Los juegos pueden usar dos estrategias para detectar
V-Blank: (1) Interrupciones automáticas (requiere
IME=True,IEcon bit activo, yIFcon bit activo), o (2) Polling manual (leerIFperiódicamente y verificar bits). La segunda estrategia funciona incluso conIME=False. -
Separación de responsabilidades:
IFindica "qué eventos han ocurrido",IEindica "qué eventos quiero procesar automáticamente", yIMEindica "si quiero procesar interrupciones automáticamente". El hardware siempre actualizaIF, pero solo procesa automáticamente siIME=Truey el bit correspondiente está activo enIE.
Lo que Falta Confirmar
-
Comportamiento en hardware real: Aunque la documentación y los tests confirman que
IFse actualiza independientemente deIME, sería útil verificar esto con un test ROM específico que haga polling deIFconIME=Falsey verifique que detecta V-Blank correctamente. -
Timing exacto: El test actual verifica que
IFse activa cuandoLY=144, pero no verifica el timing exacto dentro del ciclo de la línea. En hardware real,IFse activa al inicio de la línea 144, pero no está claro si ocurre al principio o al final del ciclo de la línea.
Hipótesis y Suposiciones
Suposición verificada: La implementación actual asume que IF se actualiza cuando
LY llega a 144, independientemente de IME. Los tests confirman que esta suposición
es correcta y coincide con el comportamiento documentado del hardware.
Suposición pendiente: Asumimos que el timing de activación de IF (al inicio de
la línea 144) es correcto, pero esto no está completamente verificado con test ROMs. Si un juego hace polling
muy preciso del timing, podría haber discrepancias menores.
Próximos Pasos
- [ ] Verificar que los juegos que hacen polling de
IFconIME=Falsepueden detectar V-Blank correctamente - [ ] Si el juego sigue sin avanzar, investigar si hay otros aspectos del polling que no están implementados correctamente
- [ ] Considerar añadir logging opcional para rastrear cuando el juego lee/escribe en
IFpara depurar polling - [ ] Verificar si el juego espera algún estado específico de
LCDCo otros registros antes de hacer polling