Step 0427: Tests Align Post-Boot Registers + EI Delay
📋 Executive Summary
Alignment of tests with the real behavior of the core: Post-Boot State (DMG) and EI delayed IME. Correction of 4 tests (3 Registers + 1 CPU Control) that assumed zero-init or immediate activation of IME, when the core correctly implements the hardware-accurate behavior according to Pan Docs.Without touching the core, only updating tests to reflect the project's Post-Boot policy.
- ✅ 4 tests fixed (test_program_counter, test_stack_pointer, test_initializacion_por_defecto, test_di_ei_sequence)
- ✅ 267 tests passing (vs 263 before)
- ✅ 10 remaining bugs (6 PPU + 4 pre-existing unrelated ones)
- ✅ Clean base for Step 0428 (fix PPU framebuffer swap)
🔧 Hardware Concept
1. Post-Boot State (Pan Docs - Power Up Sequence)
When the Game Boy is turned on, the Boot ROM runs an initialization sequence and leaves the records in aspecific statebefore jumping to the cartridge code (0x0100). This project implementsDefault Post-Boot State(skip-boot), simulating the state that the official Boot ROM leaves on the CPU.
Post-Boot Values (DMG mode):
A = 0x01 (identifies hardware as DMG)
F = 0xB0 (flags: Z=1, N=0, H=1, C=1)
B = 0x00
C = 0x13
D = 0x00
E = 0xD8
H = 0x01
L = 0x4D
PC = 0x0100 (cartridge code start)
SP = 0xFFFE
16-bit pairs:
AF=0x01B0
BC=0x0013
DE = 0x00D8
HL=0x014D
Fountain: src/core/cpp/Registers.cpp:24-47- BuilderCoreRegisters::CoreRegisters()with detailed comments on Post-BIOS status.
2. EI Delay (Pan Docs - CPU Instruction Set)
The instructionEI (Enable Interrupts)has critical behavior:1 instruction delay. This means that IME is not activated immediately, butafter executing the following statement.
Implementation in the core:
def _op_ei(self) -> int:
"""EI (Enable Interrupts) - Opcode 0xFB"""
# DO NOT activate IME immediately, program it
self.ime_scheduled = True
return 1
# In step() (at the beginning, before executing the statement):
if self.ime_scheduled:
self.ime = True
self.ime_scheduled = False
Hardware-accurate behavior: The statement following EI is executed with IME still False, and then IME is automatically activated. This is critical for patterns likeEI + RETIused in interrupt handlers.
Fountain: src/cpu/core.py:2382-2408(function_op_ei) andsrc/cpu/core.py:585-588(activation instep()).
⚙️ Technical Implementation
Task T1: Evidence of Actual Defaults (Read Only)
Commands executed:
cd /media/fabini/8CD1-4C30/ViboyColor
# Find Registers defaults
grep -n "CoreRegisters::CoreRegisters\|apply_post_boot_state\|pc(\|sp(\|a(\|f(" \
src/core/cpp/Registers.cpp src/core/cpp/Registers.hpp
nl -ba src/core/cpp/Registers.cpp | sed -n '1,180p'
# Search EI behavior
grep -n "\bEI\b\|ime_scheduled\|IME" src/cpu/core.py | head -n 30
nl -ba src/cpu/core.py | sed -n '2360,2460p'
Captured evidence:
- Registers: Constructor initializes with Post-Boot State (PC=0x0100, SP=0xFFFE, A=0x01, F=0xB0, etc.)
- EI: Sets
ime_scheduled = True, IME is activated at the start of the nextstep()
Task T2: Fix Tests Registers Post-Boot
Modified file: tests/test_core_registers.py
Changes applied:
- test_program_counter: Updated
assert reg.pc == 0x0100(was== 0) - test_stack_pointer: Updated
assert reg.sp == 0xFFFE(was== 0) - test_initialization_by_default: Completely rewritten to validate Post-Boot State:
- A=0x01, F=0xB0, B=0x00, C=0x13, D=0x00, E=0xD8, H=0x01, L=0x4D
- PC=0x0100, SP=0xFFFE
- Pairs: AF=0x01B0, BC=0x0013, DE=0x00D8, HL=0x014D
- Flags: Z=True, N=False, H=True, C=True
Comment added in tests:
# This project uses post-boot defaults (skip boot ROM)
# PC starts at 0x0100 according to Pan Docs - Power Up Sequence
Task T3: Fix Test EI Delay (CPU Control)
Modified file: tests/test_cpu_control.py
Changes applied to test_di_ei_sequence:
- After running
cpu._op_ei():- Validate
assert cpu.ime is False(IME does not activate immediately) - Validate
assert cpu.ime_scheduled is True(it is programmed for the next step)
- Validate
- Execute an instruction (NOP) with
cpu.step() - Validate
assert cpu.ime is True(IME activated after instruction) - Validate
assert cpu.ime_scheduled is False(scheduling flag cleared)
Comment added to the test:
"""
CRITICAL BEHAVIOR: EI has a delay of 1 instruction.
After executing EI, IME is not activated immediately, but is programmed
(ime_scheduled=True) and is activated at the start of the next step().
"""
Design Decision: Post-Boot Defaults
This project adoptsPost-Boot State as official policy:
- ✅ Advantage: Simplifies development (does not require implementing full Boot ROM)
- ✅ Advantage: Behavior consistent with most modern emulators
- ✅ Advantage: Commercial games assume this initial state (they do not depend on Boot ROM)
- ⚠️ Limitation: Cannot emulate the official boot sequence (Nintendo logo, scroll, etc.)
Future: If optional Boot ROM support is implemented (Step 0401 mentions this), the PC will be set to 0x0000 from the frontend before starting emulation.
✅ Tests and Verification
Compilation and Build
python3 setup.py build_ext --inplace > /tmp/viboy_0427_build.log 2>&1
echo BUILD_EXIT=$?
#BUILD_EXIT=0
python3 test_build.py > /tmp/viboy_0427_test_build.log 2>&1
echo TEST_BUILD_EXIT=$?
#TEST_BUILD_EXIT=0
Fixed Specific Tests
pytest -q tests/test_core_registers.py
#14 passed in 0.41s
# REGS_EXIT=0
pytest -q tests/test_cpu_control.py
#13 passed in 0.37s
# CPUCTRL_EXIT=0
# Individual verification of the 4 fixed tests:
pytest -vv \
tests/test_core_registers.py::TestPyRegistersPCSP::test_program_counter \
tests/test_core_registers.py::TestPyRegistersPCSP::test_stack_pointer \
tests/test_core_registers.py::TestPyRegistersInitialization::test_initialization_by_default \
tests/test_cpu_control.py::TestCPUControl::test_di_ei_sequence
#4 passed in 0.15s ✅
Complete Suite
pytest -q > /tmp/viboy_0427_all.log 2>&1
echo PYTEST_EXIT=$?
# PYTEST_EXIT=1 (expected, PPU failures remaining)
# Summary:
#10 failed, 267 passed in 0.54s
Analysis of Remaining Failures
10 total failures:
- 6 PPU faults(Cluster A of Step 0426):
test_bg_rendering_simple_tiletest_signed_addressing_fixtest_sprite_rendering_simpletest_sprite_transparencytest_sprite_x_fliptest_sprite_palette_selection
- 4 pre-existing faults(unrelated, not included in triage Step 0426):
test_unimplemented_opcode_raisestest_ldh_write_boundarytest_ld_c_a_write_stattest_ld_a_c_read
Success criterion met:The 4 specific tests for Cluster B (Registers) and Cluster C (CPU Control) from Step 0426 now pass correctly. The 6 PPU faults (Cluster A) remain for Step 0428.
C++ Compiled Module Validation
✅ The teststest_core_registers.pydirectly validate the compiled C++ module (viboy_core.PyRegisters), confirming that the Cython wrapper correctly exposes the Post-Boot State of the native core.
📁 Affected Files
tests/test_core_registers.py- 3 updated tests (PC, SP, initialization)tests/test_cpu_control.py- 1 updated test (test_di_ei_sequence)docs/bitacora/entries/2026-01-02__0427__tests-align-postboot-registers-and-ei-delay.html- New entrydocs/bitacora/index.html- Updated with new entrydocs/report_phase_2/part_01_steps_0412_0450.md- Updated with Step 0427
🔜 Next Steps
Step 0428: Fix PPU Framebuffer Swap (Cluster A)
- Investigate the swap bug in
renderer.py - Verify that the back buffer has correct pixels
- Correct the back → front copy at the end of the frame (LY=144)
- Validate the 6 PPU tests (BG rendering + sprites)
- Goal: 0 bugs in the entire suite (except the 4 pre-existing unrelated ones)
💡 Lessons Learned
- Tests must reflect the real behavior of the core: If the core implements Post-Boot State (hardware-accurate), the tests must validate that state, not assume zero-init.
- Document design policies: The decision to use Post-Boot State by default must be explicit in tests and documentation.
- Delay is critical: The original test assumed immediate activation of IME, but the real hardware has a delay of 1 instruction. Validate
ime_scheduledIt is essential. - Evidence before changes: Reading the core code (read only) before modifying tests ensures that the changes are correct and not invented.
- Prior triage is valuable: Step 0426 correctly identified the 3 clusters, allowing an atomic and orderly fix (foundation-first).
📚 References
- Bread Docs- Power Up Sequence (Post-Boot State DMG/CGB)
- Bread Docs- CPU Instruction Set (EI behavior, delay of 1 instruction)
src/core/cpp/Registers.cpp:24-47- Builder with Post-Boot Statesrc/cpu/core.py:2382-2408- Implementation of EI with delaysrc/cpu/core.py:585-588- IME activation in step()- Step 0426- Triage and clustering of the 10 failures