⚠️ Clean-Room / Educativo

Este proyecto es educativo y Open Source. No se copia código de otros emuladores. Implementación basada únicamente en documentación técnica y tests permitidas.

Bitácora del Proyecto Viboy Color

← Volver al índice

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.

Resultado:
  • ✅ 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 siguiente step()

Tarea T2: Fix Tests Registers Post-Boot

Archivo modificado: tests/test_core_registers.py

Cambios aplicados:

  1. test_program_counter: Actualizado assert reg.pc == 0x0100 (era == 0)
  2. test_stack_pointer: Actualizado assert reg.sp == 0xFFFE (era == 0)
  3. 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:

  1. 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)
  2. Ejecutar una instrucción (NOP) con cpu.step()
  3. Validar assert cpu.ime is True (IME activado después de la instrucción)
  4. 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:

  1. 6 fallos PPU (Cluster A del Step 0426):
    • test_bg_rendering_simple_tile
    • test_signed_addressing_fix
    • test_sprite_rendering_simple
    • test_sprite_transparency
    • test_sprite_x_flip
    • test_sprite_palette_selection
  2. 4 fallos pre-existentes (no relacionados, no incluidos en triage Step 0426):
    • test_unimplemented_opcode_raises
    • test_ldh_write_boundary
    • test_ld_c_a_write_stat
    • test_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 entrada
  • docs/bitacora/index.html - Actualizado con nueva entrada
  • docs/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

  1. 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.
  2. 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.
  3. 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_scheduled es esencial.
  4. 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.
  5. 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 State
  • src/cpu/core.py:2382-2408 - Implementación de EI con delay
  • src/cpu/core.py:585-588 - Activación de IME en step()
  • Step 0426 - Triage y clustering de los 10 fallos