Step 0475: Desambiguar IO Polling + IF Clear on Service + Logo Prefill Gated

← Volver al índice

Resumen Ejecutivo

Step 0475 implementa tres mejoras críticas para el diagnóstico de interrupciones y estadísticas de VRAM:

  1. 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.
  2. IF Clear on Service Tracking: Instrumentación para validar que el bit IF se limpia correctamente cuando se sirve una IRQ.
  3. 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
  • src/core/cpp/CPU.cpp:
    • Implementada clase RAII IrqPollScope que marca irq_poll_active_ en MMU durante handle_interrupts()
    • Actualizado handle_interrupts() para rastrear estado de IF antes/después de servir IRQ
    • Inicialización de nuevos miembros en constructor

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étodo get_boot_logo_prefill_enabled()
    • Movida lógica de prefill a método prefill_boot_logo_vram()
  • src/core/cpp/MMU.cpp:
    • Implementado set_irq_poll_active()
    • Modificados read() y write() para IF/IE para incrementar contadores apropiados según irq_poll_active_
    • Prefill gateado con VIBOY_SIM_BOOT_LOGO env var (deshabilitado por defecto)
    • Añadido #include <cstdlib> para std::getenv

3. Wrappers Cython

  • src/core/cython/cpu.pxd: Añadidas declaraciones para nuevos getters de CPU
  • src/core/cython/cpu.pyx: Implementados wrappers Python para nuevos getters
  • src/core/cython/mmu.pxd: Añadidas declaraciones para nuevos getters de MMU
  • src/core/cython/mmu.pyx: Implementados wrappers Python (nota: get_boot_logo_prefill_enabled() retorna int para 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 metrics en _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.