Step 0475: Disambiguate IO Polling + IF Clear on Service + Logo Prefill Gated
Executive Summary
Step 0475 implements three critical improvements to VRAM statistics and interrupt diagnostics:
- Source Tagging for IO Polling:Distinguishes IF/IE reads from program code vs internal CPU polling during interrupt handling.
- IF Clear on Service Tracking:Instrumentation to validate that the IF bit is cleared correctly when an IRQ is served.
- Boot Logo Prefill Gated:The logo prefill is crawled with an environment variable (
VIBOY_SIM_BOOT_LOGO), eliminating false positives in VRAM statistics.
Result:✅ All tests pass (10/10). ✅ Functional source tagging. ✅ IF clear on service verified. ✅ Logo prefill controllable and reported in metrics.
Hardware Concept (Pan Docs)
Source Tagging for IO Polling
Identified problem:In Step 0474, we observed obsessive IF/IE reads (59K-98K reads), but we couldn't distinguish whether these reads were coming from the game code or from internal CPU polling duringhandle_interrupts().
Solution:A "source tagging" system is implemented that distinguishes:
- PROGRAM:Reads/writes from code executed by the CPU (program instructions)
- CPU_POLL:Readings during internal interrupt polling (within
handle_interrupts())
This allows for more precise analysis: if we see many IF readings but they are all from CPU_POLL, the game is not doing manual polling; if there are reads from PROGRAM, the game is trying to read IF.
IF Clear on Service
Fountain:Pan Docs - "Interrupts"
When the CPU processes an interrupt, it must clear the corresponding bit in the IF register (0xFF0F). This is critical for the interrupt system to work correctly: if the bit is not cleared, the same interrupt would be processed repeatedly.
Step 0475 adds instrumentation to verify that this behavior is correct, tracing:
- IF value before serving the interrupt
- IF value after interrupt serving
- Cleaned bit mask
- Served Interrupt Vector
- Service timestamp
Boot Logo Prefill
Prefilling the "Viboy Color" logo in VRAM can contaminate VRAM statistics, making it difficult diagnose if the game is actually writing tiles or if the tiles come from the prefill.
Solution:The prefill is crawled with the environment variableVIBOY_SIM_BOOT_LOGO=1.
By default it is disabled, and its status is reported in the metrics to allow conditional analysis.
Implementation
Modified Files
1. CPU (C++) - Source Tagging and IF Tracking
src/core/cpp/CPU.hpp:- Added members for IRQ service tracking:
last_irq_serviced_vector_,last_irq_serviced_timestamp_,last_if_before_service_,last_if_after_service_,last_if_clear_mask_ - Added corresponding public getters
- Added members for IRQ service tracking:
src/core/cpp/CPU.cpp:- RAII class implemented
IrqPollScopewhat brandirq_poll_active_at MMU duringhandle_interrupts() - Updated
handle_interrupts()to track IF status before/after serving IRQ - Initializing new members in constructor
- RAII class implemented
2. MMU (C++) - Source Tagging and Prefill Gating
src/core/cpp/MMU.hpp:- Added flag
irq_poll_active_to mark internal polling - Added separate counters:
if_reads_program_,if_reads_cpu_poll_,if_writes_program_,ie_reads_program_,ie_reads_cpu_poll_,ie_writes_program_ - Added method
set_irq_poll_active(bool) - Added flag
boot_logo_prefill_enabled_and methodget_boot_logo_prefill_enabled() - Logical move from prefill to method
prefill_boot_logo_vram()
- Added flag
src/core/cpp/MMU.cpp:- Implemented
set_irq_poll_active() - Modified
read()andwrite()for IF/IE to increment appropriate counters according toirq_poll_active_ - Crawled prefill with
VIBOY_SIM_BOOT_LOGOenv var (disabled by default) - Added
#include <cstdlib>forstd::getenv
- Implemented
3. Cython Wrappers
src/core/cython/cpu.pxd: Added declarations for new CPU getterssrc/core/cython/cpu.pyx: Implemented Python wrappers for new getterssrc/core/cython/mmu.pxd: Added declarations for new MMU getterssrc/core/cython/mmu.pyx: Implemented Python wrappers (note:get_boot_logo_prefill_enabled()returnsintfor Cython compatibility)
4. Clean-Room Tests
tests/test_if_cleared_on_irq_service_0475.py:- 3 tests to verify that IF is cleared when serving IRQ
- Verify tracking of before/after service, mask, vector, and timestamp
tests/test_io_source_tagging_0475.py:- 7 tests to verify correct source tagging
- Verify that readings from code are counted as PROGRAM
- Verify that readings during IRQ polling are counted as CPU_POLL
- Verify that writes are always counted as PROGRAM
5. rom_smoke tool
tools/rom_smoke_0442.py:- Added new metrics to the snapshot: source tagging (6 counters), IF tracking (5 values), prefill status (1 flag)
- Metrics added to dictionary
metricsin_collect_metrics() - Metrics added to the snapshot print
Tests and Verification
Source Tagging Tests
$ 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 =============================
IF Clear on Service Tests
$ 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 =============================
C++ Compiled Module Validation
All tests use the compiled moduleviboy_coreand verify the behavior
from the C++ code directly, confirming that the implementation is correct.
Results and Conclusion
✅ Successful Implementation
- Source tagging functional: IF/IE reads are correctly distinguished between PROGRAM and CPU_POLL
- IF clear on service verified: Tests confirm that the IF bit is cleared correctly when serving an IRQ
- Prefill gated: The logo prefill is controlled by environment variable and is reported in metrics
- All tests pass: 10/10 new tests pass correctly
Next Steps
Step 0475 provides the tools necessary to more accurately diagnose problems of interruptions. Source tagging metrics will allow us to distinguish whether games are doing manual IF/IE polling or if there is only internal polling. IF clear on service tracking confirms that basic interrupt behavior is correct.
Gated prefill eliminates false positives in VRAM statistics, allowing for cleaner analysis of when the game actually writes tiles vs when the tiles come from the prefill.