Step 0475: Desambiguar IO Polling + IF Clear on Service + Logo Prefill Gated
Resumen Ejecutivo
Step 0475 implementa tres mejoras críticas para el diagnóstico de interrupciones y estadísticas de VRAM:
- Source Tagging para IO Polling: Distingue lecturas de IF/IE desde código del programa vs polling interno de la CPU durante el manejo de interrupciones.
- IF Clear on Service Tracking: Instrumentación para validar que el bit IF se limpia correctamente cuando se sirve una IRQ.
- Boot Logo Prefill Gated: El prefill del logo se gatea con una variable de entorno (
VIBOY_SIM_BOOT_LOGO), eliminando falsos positivos en estadísticas de VRAM.
Resultado: ✅ Todos los tests pasan (10/10). ✅ Source tagging funcional. ✅ IF clear on service verificado. ✅ Prefill del logo controlable y reportado en métricas.
Concepto de Hardware (Pan Docs)
Source Tagging para IO Polling
Problema identificado: En Step 0474, observamos lecturas obsesivas de IF/IE (59K-98K reads), pero no podíamos distinguir si estas lecturas provenían del código del juego o del polling interno de la CPU durante handle_interrupts().
Solución: Se implementa un sistema de "source tagging" que distingue:
- PROGRAM: Lecturas/escrituras desde código ejecutado por la CPU (instrucciones del programa)
- CPU_POLL: Lecturas durante el polling interno de interrupciones (dentro de
handle_interrupts())
Esto permite análisis más precisos: si vemos muchas lecturas de IF pero todas son desde CPU_POLL, el juego no está haciendo polling manual; si hay lecturas desde PROGRAM, el juego sí está intentando leer IF.
IF Clear on Service
Fuente: Pan Docs - "Interrupts"
Cuando la CPU procesa una interrupción, debe limpiar el bit correspondiente en el registro IF (0xFF0F). Esto es crítico para que el sistema de interrupciones funcione correctamente: si el bit no se limpia, la misma interrupción se procesaría repetidamente.
Step 0475 añade instrumentación para verificar que este comportamiento es correcto, rastreando:
- Valor de IF antes de servir la interrupción
- Valor de IF después de servir la interrupción
- Máscara del bit limpiado
- Vector de interrupción servida
- Timestamp de servicio
Boot Logo Prefill
El prefill del logo "Viboy Color" en VRAM puede contaminar las estadísticas de VRAM, haciendo difícil diagnosticar si el juego está realmente escribiendo tiles o si los tiles provienen del prefill.
Solución: El prefill se gatea con la variable de entorno VIBOY_SIM_BOOT_LOGO=1.
Por defecto está deshabilitado, y su estado se reporta en las métricas para permitir análisis condicional.
Implementación
Archivos Modificados
1. CPU (C++) - Source Tagging y IF Tracking
src/core/cpp/CPU.hpp:- Añadidos miembros para tracking de IRQ service:
last_irq_serviced_vector_,last_irq_serviced_timestamp_,last_if_before_service_,last_if_after_service_,last_if_clear_mask_ - Añadidos getters públicos correspondientes
- Añadidos miembros para tracking de IRQ service:
src/core/cpp/CPU.cpp:- Implementada clase RAII
IrqPollScopeque marcairq_poll_active_en MMU durantehandle_interrupts() - Actualizado
handle_interrupts()para rastrear estado de IF antes/después de servir IRQ - Inicialización de nuevos miembros en constructor
- Implementada clase RAII
2. MMU (C++) - Source Tagging y Prefill Gating
src/core/cpp/MMU.hpp:- Añadido flag
irq_poll_active_para marcar polling interno - Añadidos contadores separados:
if_reads_program_,if_reads_cpu_poll_,if_writes_program_,ie_reads_program_,ie_reads_cpu_poll_,ie_writes_program_ - Añadido método
set_irq_poll_active(bool) - Añadido flag
boot_logo_prefill_enabled_y métodoget_boot_logo_prefill_enabled() - Movida lógica de prefill a método
prefill_boot_logo_vram()
- Añadido flag
src/core/cpp/MMU.cpp:- Implementado
set_irq_poll_active() - Modificados
read()ywrite()para IF/IE para incrementar contadores apropiados segúnirq_poll_active_ - Prefill gateado con
VIBOY_SIM_BOOT_LOGOenv var (deshabilitado por defecto) - Añadido
#include <cstdlib>parastd::getenv
- Implementado
3. Wrappers Cython
src/core/cython/cpu.pxd: Añadidas declaraciones para nuevos getters de CPUsrc/core/cython/cpu.pyx: Implementados wrappers Python para nuevos getterssrc/core/cython/mmu.pxd: Añadidas declaraciones para nuevos getters de MMUsrc/core/cython/mmu.pyx: Implementados wrappers Python (nota:get_boot_logo_prefill_enabled()retornaintpara compatibilidad con Cython)
4. Tests Clean-Room
tests/test_if_cleared_on_irq_service_0475.py:- 3 tests para verificar que IF se limpia al servir IRQ
- Verifica tracking de before/after service, máscara, vector, y timestamp
tests/test_io_source_tagging_0475.py:- 7 tests para verificar source tagging correcto
- Verifica que lecturas desde código se cuentan como PROGRAM
- Verifica que lecturas durante IRQ polling se cuentan como CPU_POLL
- Verifica que escrituras siempre se cuentan como PROGRAM
5. Herramienta rom_smoke
tools/rom_smoke_0442.py:- Añadidas nuevas métricas al snapshot: source tagging (6 contadores), IF tracking (5 valores), prefill status (1 flag)
- Métricas añadidas al diccionario
metricsen_collect_metrics() - Métricas añadidas al print de snapshot
Tests y Verificación
Tests de Source Tagging
$ pytest tests/test_io_source_tagging_0475.py -v
============================= test session starts ==============================
tests/test_io_source_tagging_0475.py::TestIOSourceTagging::test_if_reads_from_program_tagged_correctly PASSED
tests/test_io_source_tagging_0475.py::TestIOSourceTagging::test_ie_reads_from_program_tagged_correctly PASSED
tests/test_io_source_tagging_0475.py::TestIOSourceTagging::test_if_reads_from_irq_polling_tagged_correctly PASSED
tests/test_io_source_tagging_0475.py::TestIOSourceTagging::test_ie_reads_from_irq_polling_tagged_correctly PASSED
tests/test_io_source_tagging_0475.py::TestIOSourceTagging::test_if_writes_always_tagged_as_program PASSED
tests/test_io_source_tagging_0475.py::TestIOSourceTagging::test_ie_writes_always_tagged_as_program PASSED
tests/test_io_source_tagging_0475.py::TestIOSourceTagging::test_mixed_reads_program_and_polling PASSED
============================= 7 passed in 0.47s ===============================
Tests de IF Clear on Service
$ pytest tests/test_if_cleared_on_irq_service_0475.py -v
============================= test session starts ==============================
tests/test_if_cleared_on_irq_service_0475.py::TestIFClearedOnIRQService::test_vblank_irq_clears_if_bit PASSED
tests/test_if_cleared_on_irq_service_0475.py::TestIFClearedOnIRQService::test_timer_irq_clears_if_bit PASSED
tests/test_if_cleared_on_irq_service_0475.py::TestIFClearedOnIRQService::test_multiple_irqs_update_tracking PASSED
============================= 3 passed in 0.27s ===============================
Validación de Módulo Compilado C++
Todos los tests usan el módulo compilado viboy_core y verifican el comportamiento
del código C++ directamente, confirmando que la implementación es correcta.
Resultados y Conclusión
✅ Implementación Exitosa
- Source tagging funcional: Las lecturas de IF/IE se distinguen correctamente entre PROGRAM y CPU_POLL
- IF clear on service verificado: Los tests confirman que el bit IF se limpia correctamente al servir una IRQ
- Prefill gated: El prefill del logo está controlado por variable de entorno y se reporta en métricas
- Todos los tests pasan: 10/10 tests nuevos pasan correctamente
Próximos Pasos
Step 0475 proporciona las herramientas necesarias para diagnosticar con mayor precisión los problemas de interrupciones. Las métricas de source tagging permitirán distinguir si los juegos están haciendo polling manual de IF/IE o si solo hay polling interno. El tracking de IF clear on service confirma que el comportamiento básico de interrupciones es correcto.
El prefill gated elimina falsos positivos en estadísticas de VRAM, permitiendo análisis más limpios de cuándo el juego realmente escribe tiles vs cuándo los tiles provienen del prefill.