Step 0427: Tests Align Post-Boot Registers + EI Delay
📋 Resumen Ejecutivo
Alineación de tests con el comportamiento real del core: Post-Boot State (DMG) y EI delayed IME. Corrección de 4 tests (3 Registers + 1 CPU Control) que asumían zero-init o activación inmediata de IME, cuando el core implementa correctamente el comportamiento hardware-accurate según Pan Docs. Sin tocar el core, solo actualización de tests para reflejar la política Post-Boot del proyecto.
- ✅ 4 tests arreglados (test_program_counter, test_stack_pointer, test_inicializacion_por_defecto, test_di_ei_sequence)
- ✅ 267 tests passing (vs 263 antes)
- ✅ 10 fallos restantes (6 PPU + 4 pre-existentes no relacionados)
- ✅ Base limpia para Step 0428 (fix PPU framebuffer swap)
🔧 Concepto de Hardware
1. Post-Boot State (Pan Docs - Power Up Sequence)
Cuando la Game Boy se enciende, la Boot ROM ejecuta una secuencia de inicialización y deja los registros en un estado específico antes de saltar al código del cartucho (0x0100). Este proyecto implementa Post-Boot State por defecto (skip-boot), simulando el estado que la Boot ROM oficial deja en la CPU.
Valores Post-Boot (DMG mode):
A = 0x01 (identifica hardware como 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 (inicio del código del cartucho)
SP = 0xFFFE
Pares de 16 bits:
AF = 0x01B0
BC = 0x0013
DE = 0x00D8
HL = 0x014D
Fuente: src/core/cpp/Registers.cpp:24-47 - Constructor CoreRegisters::CoreRegisters() con comentarios detallados sobre el estado Post-BIOS.
2. EI Delay (Pan Docs - CPU Instruction Set)
La instrucción EI (Enable Interrupts) tiene un comportamiento crítico: delay de 1 instrucción. Esto significa que IME no se activa inmediatamente, sino después de ejecutar la siguiente instrucción.
Implementación en el core:
def _op_ei(self) -> int:
"""EI (Enable Interrupts) - Opcode 0xFB"""
# NO activar IME inmediatamente, programarlo
self.ime_scheduled = True
return 1
# En step() (al inicio, antes de ejecutar la instrucción):
if self.ime_scheduled:
self.ime = True
self.ime_scheduled = False
Comportamiento hardware-accurate: La instrucción que sigue a EI se ejecuta con IME aún False, y luego IME se activa automáticamente. Esto es crítico para patrones como EI + RETI usados en handlers de interrupción.
Fuente: src/cpu/core.py:2382-2408 (función _op_ei) y src/cpu/core.py:585-588 (activación en step()).
⚙️ Implementación Técnica
Tarea T1: Evidencia de Defaults Reales (Solo Lectura)
Comandos ejecutados:
cd /media/fabini/8CD1-4C30/ViboyColor
# Buscar defaults de Registers
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'
# Buscar comportamiento de EI
grep -n "\bEI\b\|ime_scheduled\|IME" src/cpu/core.py | head -n 30
nl -ba src/cpu/core.py | sed -n '2360,2460p'
Evidencia capturada:
- Registers: Constructor inicializa con Post-Boot State (PC=0x0100, SP=0xFFFE, A=0x01, F=0xB0, etc.)
- EI: Establece
ime_scheduled = True, IME se activa al inicio del siguientestep()
Tarea T2: Fix Tests Registers Post-Boot
Archivo modificado: tests/test_core_registers.py
Cambios aplicados:
- test_program_counter: Actualizado
assert reg.pc == 0x0100(era== 0) - test_stack_pointer: Actualizado
assert reg.sp == 0xFFFE(era== 0) - test_inicializacion_por_defecto: Reescrito completamente para validar Post-Boot State:
- A=0x01, F=0xB0, B=0x00, C=0x13, D=0x00, E=0xD8, H=0x01, L=0x4D
- PC=0x0100, SP=0xFFFE
- Pares: AF=0x01B0, BC=0x0013, DE=0x00D8, HL=0x014D
- Flags: Z=True, N=False, H=True, C=True
Comentario añadido en los tests:
# Este proyecto usa post-boot defaults (skip boot ROM)
# PC inicia en 0x0100 según Pan Docs - Power Up Sequence
Tarea T3: Fix Test EI Delay (CPU Control)
Archivo modificado: tests/test_cpu_control.py
Cambios aplicados en test_di_ei_sequence:
- Después de ejecutar
cpu._op_ei():- Validar
assert cpu.ime is False(IME no se activa inmediatamente) - Validar
assert cpu.ime_scheduled is True(se programa para el siguiente step)
- Validar
- Ejecutar una instrucción (NOP) con
cpu.step() - Validar
assert cpu.ime is True(IME activado después de la instrucción) - Validar
assert cpu.ime_scheduled is False(flag de scheduling limpiado)
Comentario añadido en el test:
"""
COMPORTAMIENTO CRÍTICO: EI tiene un delay de 1 instrucción.
Tras ejecutar EI, IME no se activa inmediatamente, sino que se programa
(ime_scheduled=True) y se activa al inicio del siguiente step().
"""
Decisión de Diseño: Post-Boot Defaults
Este proyecto adopta Post-Boot State como política oficial:
- ✅ Ventaja: Simplifica el desarrollo (no requiere implementar Boot ROM completa)
- ✅ Ventaja: Comportamiento consistente con la mayoría de emuladores modernos
- ✅ Ventaja: Los juegos comerciales asumen este estado inicial (no dependen de Boot ROM)
- ⚠️ Limitación: No se puede emular la secuencia de boot oficial (logo de Nintendo, scroll, etc.)
Futuro: Si se implementa soporte para Boot ROM opcional (Step 0401 lo menciona), el PC se ajustará a 0x0000 desde el frontend antes de iniciar la emulación.
✅ Tests y Verificación
Compilación y 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
Tests Específicos Arreglados
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
# Verificación individual de los 4 tests arreglados:
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::TestPyRegistersInicializacion::test_inicializacion_por_defecto \
tests/test_cpu_control.py::TestCPUControl::test_di_ei_sequence
# 4 passed in 0.15s ✅
Suite Completa
pytest -q > /tmp/viboy_0427_all.log 2>&1
echo PYTEST_EXIT=$?
# PYTEST_EXIT=1 (esperado, quedan fallos PPU)
# Resumen:
# 10 failed, 267 passed in 0.54s
Análisis de Fallos Restantes
10 fallos totales:
- 6 fallos PPU (Cluster A del Step 0426):
test_bg_rendering_simple_tiletest_signed_addressing_fixtest_sprite_rendering_simpletest_sprite_transparencytest_sprite_x_fliptest_sprite_palette_selection
- 4 fallos pre-existentes (no relacionados, no incluidos en triage Step 0426):
test_unimplemented_opcode_raisestest_ldh_write_boundarytest_ld_c_a_write_stattest_ld_a_c_read
Criterio de éxito cumplido: Los 4 tests específicos del Cluster B (Registers) y Cluster C (CPU Control) del Step 0426 ahora pasan correctamente. Los 6 fallos PPU (Cluster A) quedan para el Step 0428.
Validación de Módulo Compilado C++
✅ Los tests de test_core_registers.py validan directamente el módulo C++ compilado (viboy_core.PyRegisters), confirmando que el wrapper Cython expone correctamente el Post-Boot State del core nativo.
📁 Archivos Afectados
tests/test_core_registers.py- 3 tests actualizados (PC, SP, inicialización)tests/test_cpu_control.py- 1 test actualizado (test_di_ei_sequence)docs/bitacora/entries/2026-01-02__0427__tests-align-postboot-registers-and-ei-delay.html- Nueva entradadocs/bitacora/index.html- Actualizado con nueva entradadocs/informe_fase_2/parte_01_steps_0412_0450.md- Actualizado con Step 0427
🔜 Próximos Pasos
Step 0428: Fix PPU Framebuffer Swap (Cluster A)
- Investigar el bug de swap en
renderer.py - Verificar que el back buffer tiene píxeles correctos
- Corregir la copia back → front al final del frame (LY=144)
- Validar los 6 tests PPU (rendering BG + sprites)
- Objetivo: 0 fallos en la suite completa (salvo los 4 pre-existentes no relacionados)
💡 Lecciones Aprendidas
- Tests deben reflejar el comportamiento real del core: Si el core implementa Post-Boot State (hardware-accurate), los tests deben validar ese estado, no asumir zero-init.
- Documentar políticas de diseño: La decisión de usar Post-Boot State por defecto debe estar explícita en tests y documentación.
- EI delay es crítico: El test original asumía activación inmediata de IME, pero el hardware real tiene un delay de 1 instrucción. Validar
ime_scheduledes esencial. - Evidencia antes de cambios: Leer el código del core (solo lectura) antes de modificar tests asegura que los cambios son correctos y no inventados.
- Triage previo es valioso: El Step 0426 identificó correctamente los 3 clusters, permitiendo un fix atómico y ordenado (foundation-first).
📚 Referencias
- Pan Docs - Power Up Sequence (Post-Boot State DMG/CGB)
- Pan Docs - CPU Instruction Set (EI behavior, delay de 1 instrucción)
src/core/cpp/Registers.cpp:24-47- Constructor con Post-Boot Statesrc/cpu/core.py:2382-2408- Implementación de EI con delaysrc/cpu/core.py:585-588- Activación de IME en step()- Step 0426 - Triage y clustering de los 10 fallos