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.
IRQ Reality Check + CGB Palette Proof
Resumen
Este step implementa mecanismos de tracking avanzados para verificar el comportamiento real de las interrupciones (IRQ) en modo DMG y el estado de las paletas CGB. Se implementó tracking de interrupciones realmente tomadas (interrupt_taken_counts), tracking de writes a IF/IE y HRAM[0xFFC5], y se integró en rom_smoke_0442.py con una sección IRQReality siempre visible. Resultado clave DMG: IRQTaken_VBlank=2579 confirma que las interrupciones VBlank se están tomando correctamente, descartando problemas de interrupciones como causa de la pantalla blanca. Resultado clave CGB: IdxNonZero=22910 pero RgbNonWhite=0, confirmando que el problema está en el pipeline de renderizado (paletas/mapeo) más que en el fetch de tiles.
Concepto de Hardware
Interrupciones Realmente Tomadas: En el Game Boy, cuando una interrupción está pendiente (IF bit set) y el IME (Interrupt Master Enable) está activo, la CPU debe tomar la interrupción en el siguiente ciclo de instrucción. Sin embargo, es posible que el emulador reporte que las interrupciones están "servidas" sin que realmente se hayan tomado. El tracking de interrupciones realmente tomadas verifica que la CPU realmente ejecute el código del handler de interrupción.
HRAM[0xFFC5]: Algunos juegos usan HRAM[0xFFC5] como flag para indicar que el handler de VBlank ha completado. Tracking de writes a esta ubicación puede confirmar que el handler se está ejecutando.
Paletas CGB: En modo CGB, las paletas se configuran escribiendo a BGPI/OBPI (Palette Index) y luego a BGPD/OBPD (Palette Data). Si no hay writes a estas ubicaciones, el juego está usando paletas DMG (BGP/OBP0/OBP1) en lugar de CGB.
Referencia: Pan Docs - "Interrupts", "CGB Palettes", "Memory Map"
Implementación
Fase A: DMG IRQ Reality Check
A1-A2: Tracking de Interrupciones Tomadas
Se implementó en CPU.hpp/CPU.cpp:
interrupt_taken_counts_[5]: Contador de interrupciones realmente tomadas por tipo (VBlank, LCD-STAT, Timer, Serial, Joypad)IRQTraceEvent: Estructura con información detallada de cada interrupción (frame, PC antes, vector, IE, IF antes/después, IME, SP antes/después, PC guardado en pila)irq_trace_ring_[64]: Ring buffer de últimos 64 eventos IRQ
A3-A4: Tracking de Writes a IF/IE y HRAM[0xFFC5]
Se implementó en MMU.hpp/MMU.cpp:
IFIETracking: Tracking de writes a0xFF0F(IF) y0xFFFF(IE) con PC, valor escrito y valor aplicadoHRAMFFC5Tracking: Tracking de writes a0xFFC5con PC, valor escrito y frame de primera escritura
A5: Exposición Cython
Se implementaron getters en cpu.pyx y mmu.pyx:
get_interrupt_taken_counts(): Retorna diccionario con contadores por tipoget_irq_trace_ring(n): Retorna últimos n eventos IRQget_if_ie_tracking(): Retorna tracking de IF/IEget_hram_ffc5_tracking(): Retorna tracking de HRAM[0xFFC5]
A6: Integración en rom_smoke_0442.py
Se añadió sección IRQReality al snapshot principal (siempre visible, no solo en AfterClear):
- Captura de
interrupt_taken_counts - Captura de
if_ie_tracking - Captura de
hram_ffc5_tracking
Fase B: CGB Palette Proof
Se ejecutó tetris_dx.gbc con VIBOY_DEBUG_CGB_PALETTE_WRITES=1 por 1200 frames. El snapshot ya incluía CGBPaletteWriteStats, palette0_decode y bg_palette_nonwhite_entries (implementado en Step 0493).
Archivos Afectados
src/core/cpp/CPU.hpp- Añadido IRQTraceEvent, interrupt_taken_counts_, irq_trace_ring_src/core/cpp/CPU.cpp- Implementado tracking de interrupciones tomadas y ring buffersrc/core/cpp/MMU.hpp- Añadido IFIETracking, HRAMFFC5Trackingsrc/core/cpp/MMU.cpp- Implementado tracking de writes a IF/IE y HRAM[0xFFC5]src/core/cython/cpu.pxd- Declaraciones de estructuras y getterssrc/core/cython/cpu.pyx- Implementación de getters Pythonsrc/core/cython/mmu.pxd- Declaraciones de estructuras y getterssrc/core/cython/mmu.pyx- Implementación de getters Pythontools/rom_smoke_0442.py- Integración de sección IRQReality en snapshot principal
Tests y Verificación
Comando ejecutado (DMG):
export VIBOY_SIM_BOOT_LOGO=0
export VIBOY_POST_BOOT_DMG_PROFILE=B
export VIBOY_DEBUG_VRAM_WRITES=1
export VIBOY_DEBUG_DMG_TILE_FETCH=1
export VIBOY_DEBUG_PRESENT_TRACE=1
python3 -m tools.rom_smoke_0442 roms/tetris.gb --frames 3000
Resultados (Frame 2580):
IRQTaken_VBlank=2579✅ (criterio: > 0)HRAM_FFC5_WriteCount=1✅ (criterio: >= 1)IF_WriteCount=5160IE_WriteCount=3VBlankServ=2579
Comando ejecutado (CGB):
export VIBOY_SIM_BOOT_LOGO=0
export VIBOY_DEBUG_CGB_PALETTE_WRITES=1
python3 -m tools.rom_smoke_0442 roms/tetris_dx.gbc --frames 1200
Resultados (Frame 600):
IdxNonZero=22910✅ (criterio: > 0)RgbNonWhite=0❌ (criterio: > 0, no cumplido - juego usa paletas DMG)CGBPaletteWriteStats=BGPD_Writes=0 OBPD_Writes=0
Validación de módulo compilado C++:
python3 test_build.py
# Resultado: [EXITO] El pipeline de compilacion funciona correctamente
Fuentes Consultadas
- Pan Docs: "Interrupts" - Comportamiento de interrupciones en LR35902
- Pan Docs: "CGB Palettes" - Configuración de paletas CGB
- Pan Docs: "Memory Map" - Mapeo de memoria y registros I/O
Integridad Educativa
Lo que Entiendo Ahora
- Interrupciones Realmente Tomadas: El tracking de interrupciones realmente tomadas verifica que la CPU realmente ejecute el código del handler, no solo que el flag esté set. Esto es crítico para diagnosticar problemas de sincronización.
- HRAM[0xFFC5] como Flag: Algunos juegos usan HRAM[0xFFC5] como flag para indicar que el handler de VBlank ha completado. Tracking de writes a esta ubicación puede confirmar que el handler se está ejecutando.
- Paletas CGB vs DMG: En modo CGB, las paletas se configuran escribiendo a BGPI/OBPI y luego a BGPD/OBPD. Si no hay writes a estas ubicaciones, el juego está usando paletas DMG (BGP/OBP0/OBP1) en lugar de CGB.
Lo que Falta Confirmar
- Pipeline de Renderizado: Dado que las interrupciones funcionan correctamente, el problema de pantalla blanca está en el pipeline de renderizado (fetch de tiles, mapeo de paletas, o conversión de índices a RGB).
- Mapeo de Paletas DMG: Aunque tetris_dx.gbc usa paletas DMG, el hecho de que RgbNonWhite=0 sugiere que puede haber un problema en el mapeo de índices a colores RGB.
Hipótesis y Suposiciones
Hipótesis Principal: El problema de pantalla blanca NO es causado por interrupciones no tomadas, sino por un problema en el pipeline de renderizado (fetch de tiles, mapeo de paletas, o conversión de índices a RGB). Esta hipótesis está respaldada por los datos: las interrupciones se están tomando correctamente (IRQTaken_VBlank=2579), pero el framebuffer sigue siendo blanco.
Próximos Pasos
- [ ] Investigar pipeline de renderizado: Dado que las interrupciones funcionan correctamente, el problema está en el fetch/renderizado de tiles o en la conversión de índices a RGB.
- [ ] Verificar mapeo de paletas DMG: Aunque tetris_dx.gbc usa paletas DMG, el hecho de que RgbNonWhite=0 sugiere que puede haber un problema en el mapeo de índices a colores RGB.
- [ ] Analizar VRAM writes: Los datos muestran que hay writes a VRAM (TiledataNonZeroB0=11000), pero el framebuffer sigue siendo blanco, lo que sugiere un problema en el fetch o en la conversión.