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.
Verificación: Ejecución Post-Saltos Condicionales
Resumen
Después de implementar los saltos relativos condicionales (JR Z, JR NC, JR C) en el Step 0162, se ejecutó el emulador para verificar si el deadlock de LY=0 se había resuelto. Los resultados muestran que el problema persiste: LY sigue atascado en 0, pero no aparecen warnings de opcodes desconocidos, lo que indica que la CPU está ejecutando instrucciones conocidas. Esto sugiere que el problema puede ser más complejo de lo inicialmente previsto o que hay otra causa adicional al deadlock original.
Concepto de Hardware
En un emulador de Game Boy, el contador de líneas de escaneo (LY) debe incrementarse cada 456 ciclos de reloj (T-Cycles) cuando el LCD está encendido. Si LY permanece atascado en 0, significa que la PPU no está recibiendo suficientes ciclos de CPU para avanzar las líneas de escaneo, lo cual puede deberse a varias razones:
- Opcodes no implementados: Si la CPU ejecuta un opcode desconocido que devuelve 0 ciclos, el tiempo no avanza.
- Bucles infinitos en el código del juego: El código del juego puede estar ejecutando un bucle infinito esperando una condición que nunca se cumple.
- HALT sin interrupciones: Si la CPU entra en estado HALT y no hay interrupciones habilitadas, la CPU consumirá ciclos mínimos pero el código no avanzará.
- Problemas de sincronización: La CPU puede estar devolviendo ciclos válidos, pero la lógica de sincronización puede tener un error.
La ausencia de warnings de opcodes desconocidos es un hallazgo importante: significa que la CPU está ejecutando instrucciones conocidas y correctamente implementadas, pero algo más está impidiendo que el sistema avance correctamente.
Proceso de Verificación
Se ejecutó el emulador con el módulo C++ recompilado después de implementar los saltos condicionales, usando el modo verbose para monitorear el estado del sistema.
Comandos Ejecutados
python setup.py build_ext --inplace
python main.py roms/tetris.gb --verbose > temp_execution_0163.log 2>&1
Resultados Observados
- Estado de LY: Permanece atascado en 0 durante toda la ejecución.
- Warnings de CPU: No aparecen warnings de opcodes no implementados ([CPU WARN]).
- Trazas de CPU: No aparecen trazas de ejecución (el PC no alcanza 0x0300 donde se activa el debug trace).
- Renderizado: El renderer muestra frames pero todos con índices de color 0 (pantalla negra).
- Bucle principal: El bucle principal está funcionando (se muestran heartbeats periódicos), pero LY no avanza.
Análisis de la Situación
El hecho de que no aparezcan warnings de opcodes desconocidos es significativo. Esto indica que:
- La CPU no está ejecutando opcodes que caigan en el caso `default` del switch.
- La CPU está devolviendo ciclos válidos (mayores a 0), porque el sistema de protección contra deadlock no se activa (no aparecen warnings de "CPU devolvió 0 ciclos").
- El problema puede estar en otro lugar: ya sea en la lógica del bucle principal, en la sincronización de la PPU, o en un bucle infinito en el código del juego mismo.
Archivos Consultados
temp_execution_0163.log- Log completo de la ejecución del emuladorsrc/core/cpp/CPU.cpp- Código de la CPU para verificar implementación de saltos condicionalessrc/viboy.py- Bucle principal del emulador para entender la sincronización
Tests y Verificación
Este step es puramente de verificación ejecutando el emulador completo. No se ejecutaron tests unitarios, pero sí se verificó que el módulo C++ se recompiló correctamente.
- Recompilación: El módulo C++ se recompiló exitosamente sin errores.
- Ejecución del emulador: El emulador se ejecutó sin crashes, pero LY permanece atascado.
- Análisis de logs: Se analizaron los logs buscando warnings, trazas y patrones de comportamiento.
Evidencia del Log
Extracto representativo del log de ejecución:
💓 Heartbeat ... LY=0 | Mode=2 | LCDC=0x80 (LCD ON) | PPU viva
[Renderer] Frame #60: framebuffer leído, muestra índices: [0, 0, 0, 0, 0, 0], len=23040
💓 Heartbeat ... LY=0 | Mode=2 | LCDC=0x80 (LCD ON) | PPU viva
[Renderer] Frame #120: framebuffer leído, muestra índices: [0, 0, 0, 0, 0, 0], len=23040
...
(patrón se repite indefinidamente)
Fuentes Consultadas
- Pan Docs: LCD Timing, V-Blank Interrupt
- Implementación existente del bucle principal en
src/viboy.py - Implementación de la CPU en
src/core/cpp/CPU.cpp
Integridad Educativa
Lo que Entiendo Ahora
- Diagnóstico de deadlocks: La ausencia de warnings de opcodes desconocidos es información valiosa. Indica que el problema puede estar en otro lugar del sistema, no necesariamente en la implementación de opcodes.
- Complejidad del debugging: Cuando un sistema complejo como un emulador presenta un problema, puede haber múltiples causas potenciales que interactúan de manera no obvia.
- Importancia de la instrumentación: Los logs y heartbeats son esenciales para entender qué está pasando en tiempo de ejecución, especialmente cuando el sistema parece estar funcionando pero no produce los resultados esperados.
Lo que Falta Confirmar
- Causa raíz del deadlock: Aunque los saltos condicionales están implementados, el deadlock persiste. Necesitamos identificar si es un problema de sincronización, un bucle infinito en el código del juego, o algún otro factor.
- Estado real de la CPU: Sería útil activar trazas de CPU desde el principio (no solo después de PC=0x0300) para ver qué opcodes se están ejecutando realmente.
- Sincronización PPU-CPU: Verificar que la PPU está recibiendo correctamente los ciclos de la CPU y que el cálculo de avance de LY es correcto.
Hipótesis y Suposiciones
Hipótesis principal: El código del juego puede estar ejecutando un bucle infinito esperando una condición que nunca se cumple. Esto podría ser porque:
- Falta implementar alguna funcionalidad de hardware (por ejemplo, el Timer puede no estar funcionando correctamente).
- El estado inicial de la CPU o la memoria no es exactamente el esperado por el juego.
- Hay algún flag o registro que el juego está consultando y que no está en el estado correcto.
Suposición: Asumimos que los saltos condicionales están correctamente implementados porque los tests unitarios pasaron. Sin embargo, en un sistema complejo, las interacciones entre componentes pueden revelar problemas que no aparecen en tests aislados.
Próximos Pasos
- [ ] Activar trazas de CPU desde el inicio (modificar DEBUG_TRIGGER_PC a 0x0100) para ver qué opcodes se están ejecutando.
- [ ] Verificar el estado de los registros de la CPU en diferentes momentos para detectar patrones anómalos.
- [ ] Revisar la implementación del Timer y otras funcionalidades de I/O que el juego podría estar esperando.
- [ ] Considerar la posibilidad de que el juego esté en un bucle infinito esperando V-Blank, pero V-Blank nunca ocurre porque LY no avanza.
- [ ] Analizar si hay algún problema en la conversión de M-Cycles a T-Cycles en el bucle principal.