Step 0480: Cerrar Loops JOYP y HRAM FF92 + Arreglar Parser

← Volver al índice

Resumen Ejecutivo

Step 0479 identificó que mario.gbc espera 0xFF92 (HRAM, no I/O) y tetris_dx.gbc espera 0xFF00 (JOYP). Step 0480 corrige el parser para evitar falsos positivos (FF92=HRAM), implementa instrumentación quirúrgica de HRAM[FF92], corrige semántica JOYP (bits 6-7 siempre 1), y mejora disasm_window para marcar PC y respetar banking.

Resultado: ✅ Parser corregido (distingue I/O vs HRAM). ✅ Instrumentación HRAM[FF92] funcionando. ✅ Semántica JOYP corregida. ✅ Tests clean-room (3/3 pasando). ✅ Disasm mejorado. ✅ Reporte generado: HRAM[FF92] nunca se escribe (valor 0 es inicial), JOYP fix no desbloquea tetris_dx aún (requiere más investigación).

Concepto de Hardware

HRAM (High RAM) en Game Boy

HRAM es una región de memoria de 127 bytes (0xFF80-0xFFFE) que es accesible rápidamente por la CPU. A diferencia de los registros I/O (0xFF00-0xFF7F), HRAM es memoria normal que se puede leer y escribir sin efectos secundarios.

Fuente: Pan Docs - Memory Map

JOYP Register (0xFF00)

El registro JOYP (P1) controla el input del joypad. Según Pan Docs, los bits 6-7 siempre leen como 1, independientemente del valor escrito. Los bits 4-5 seleccionan qué fila de botones leer (direcciones o acciones), y los bits 0-3 reflejan el estado de los botones (0 = presionado, 1 = suelto).

Fuente: Pan Docs - Joypad Input, P1 Register

Implementación

Fase A: Corregir Parser

El parser `parse_loop_io_pattern` ahora distingue correctamente entre:

  • I/O registers (0xFF00-0xFF7F): Detectados como wait loops si hay LDH A,(addr) con addr < 0xFF80, seguido de AND/BIT/CP y JR/JP de vuelta al hotspot.
  • HRAM (0xFF80-0xFFFF): NO detectados como wait loops (evita falsos positivos como 0xFF92).

Fase B: Instrumentación HRAM[FF92]

Añadida instrumentación quirúrgica en MMU para trackear reads/writes a 0xFF92:

  • Contadores de writes y reads (solo desde programa, no CPU poll)
  • Último PC, valor y timestamp de write
  • Último PC y valor de read
  • Gated por VIBOY_DEBUG_IO=1

Fase C: Semántica JOYP

Corregida semántica de JOYP en MMU::read(0xFF00):

  • Bits 6-7 siempre leen como 1 (según Pan Docs)
  • Valor por defecto: 0xFF (todos los bits en 1 = no presionados)

Fase D: Disasm Mejorado

Mejorado `disasm_window` en `tools/rom_smoke_0442.py`:

  • Marca el PC actual con >>> ... <<< PC ACTUAL
  • Respeta banking al leer bytes de ROM (usa MMU en lugar de raw file reads)
  • Evita "DB" (data byte) garbage en el disassembly

Tests y Verificación

Tests Clean-Room

Creados 3 tests nuevos para validar semántica JOYP:

  • test_joyp_default_no_input_returns_1s_0480.py: Verifica que JOYP con sin input devuelve bits 0-1 en 1
  • test_joyp_select_buttons_affects_low_nibble_0480.py: Verifica que seleccionar fila de botones afecta el nibble bajo
  • test_joyp_select_dpad_affects_low_nibble_0480.py: Verifica que seleccionar fila de direcciones afecta el nibble bajo

Resultado: ✅ 3/3 tests pasando

Ejecución rom_smoke

Ejecutado rom_smoke_0442.py con baseline limpio para 3 ROMs:

  • mario.gbc: 240 frames
  • tetris_dx.gbc: 240 frames
  • tetris.gb: 240 frames

Flags: VIBOY_SIM_BOOT_LOGO=0 VIBOY_DEBUG_IO=1 VIBOY_DEBUG_INJECTION=0 VIBOY_AUTOPRESS=0 VIBOY_FORCE_BGP=0 VIBOY_FRAMEBUFFER_TRACE=0

Resultados

mario.gbc

  • ✅ HRAM[FF92] instrumentación funcionando
  • ❌ HRAM[FF92] NUNCA se escribe (contador permanece en 0)
  • ⚠️ HRAM[FF92] no se lee desde programa (todas las lecturas son desde CPU poll)
  • Conclusión: HRAM[FF92] se lee pero nunca se escribe. El valor 0 es el valor inicial (HRAM se inicializa a 0x00).

tetris_dx.gbc

  • ❌ Loop JOYP NO detectado por el parser (requiere más investigación)
  • ✅ JOYP semántica corregida (bits 6-7 siempre 1)
  • Conclusión: El fix de JOYP no desbloquea el loop aún. Requiere más investigación sobre la condición exacta del loop.

Archivos Afectados

  • tools/rom_smoke_0442.py: Parser corregido, disasm_window mejorado, métricas HRAM FF92 añadidas
  • src/core/cpp/MMU.hpp: Miembros privados para instrumentación HRAM[FF92]
  • src/core/cpp/MMU.cpp: Instrumentación HRAM[FF92], semántica JOYP corregida
  • tests/test_joyp_*_0480.py: 3 tests nuevos para validar semántica JOYP

Integridad Educativa

Lo que Entiendo Ahora

  • HRAM vs I/O: HRAM (0xFF80-0xFFFF) es memoria normal, no registros I/O. El parser debe distinguir entre ambos para evitar falsos positivos.
  • JOYP Semantics: Los bits 6-7 de JOYP siempre leen como 1 según Pan Docs. Esto es crítico para la semántica correcta del registro.
  • Disasm Banking: Al desensamblar código, se debe respetar el banking de ROM usando MMU en lugar de raw file reads para evitar "DB" garbage.

Lo que Falta Confirmar

  • HRAM[FF92] en mario.gbc: Por qué se lee pero nunca se escribe. Puede ser que el valor 0 sea suficiente o que se escriba en un momento no capturado.
  • JOYP Loop en tetris_dx.gbc: Por qué el parser no detecta el loop JOYP. Puede requerir ajustes en el algoritmo de detección o la condición es más compleja.

Próximos Pasos

  • [ ] Investigar por qué HRAM[FF92] nunca se escribe en mario.gbc - puede ser que el valor 0 sea suficiente
  • [ ] Investigar por qué el parser no detecta el loop JOYP en tetris_dx.gbc - puede requerir ajustes en el algoritmo
  • [ ] Aplicar fixes adicionales según evidencia una vez identificada la causa raíz