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.
Debug: Limpieza de Logs y Confirmación de Bucles Anidados
Resumen
El análisis de la traza del Step 0157 confirmó que el fix del flag Z (Step 0152) fue un éxito: el bucle DEC B -> JR NZ terminó correctamente cuando B llegó a 0x00 y el flag Z se activó. Sin embargo, la ejecución se detuvo silenciosamente en PC: 0x0297, indicando que la CPU entró inmediatamente en un segundo bucle de limpieza (DEC C -> JR NZ) que no estaba instrumentado. Se eliminaron los logs de depuración detallados de DEC B y JR NZ para limpiar la salida y permitir que la traza disparada capture el código que se ejecuta después de todos los bucles.
Concepto de Hardware
Las rutinas de inicialización de las ROMs de Game Boy suelen ejecutar múltiples bucles de limpieza de memoria en secuencia. Cada bucle utiliza un registro diferente (B, C, D, E, etc.) para contar iteraciones y limpiar diferentes regiones de memoria. La estructura típica es:
loop1:
DEC B
JR NZ, loop1 ; Bucle 1: Limpia región 1
loop2:
DEC C
JR NZ, loop2 ; Bucle 2: Limpia región 2
; ... más bucles ...
; Código principal después de la inicialización
Cuando un bucle termina (el registro llega a 0x00 y el flag Z se activa), la CPU continúa con la siguiente instrucción. Si esa instrucción es el inicio de otro bucle similar, la CPU entra inmediatamente en ese segundo bucle sin pausa.
Observación clave: Si solo instrumentamos el primer bucle con logs detallados, el segundo bucle se ejecutará en silencio, creando la impresión de que la ejecución se "detuvo" cuando en realidad está funcionando a máxima velocidad dentro del segundo bucle.
Fuente: Análisis de trazas de ejecución de ROMs de Game Boy - Patrones comunes de inicialización
Implementación
Se eliminaron todos los logs de depuración detallados que se añadieron en pasos anteriores para diagnosticar el comportamiento del flag Z en los bucles de inicialización. Estos logs ya cumplieron su misión: confirmaron que el flag Z se activa correctamente y que el bucle DEC B termina como se esperaba.
Logs eliminados
- DEC B (0x05): Se eliminaron los
printfque mostraban el valor de B y Z antes y después de la operación. - JR NZ (0x20): Se eliminaron los
printfque mostraban el estado del flag Z, el offset y la decisión de salto.
Lógica preservada
Se mantuvo intacta la lógica de la traza disparada implementada en el Step 0157. El sistema de trazado "disparado" sigue activo y se activará automáticamente cuando el PC supere 0x0300, capturando las 100 instrucciones críticas que se ejecutan después de todos los bucles de inicialización.
Cambios realizados
CPU.cpp - case 0x05 (DEC B):
case 0x05: // DEC B
{
regs_->b = alu_dec(regs_->b);
cycles_ += 1;
return 1;
}
CPU.cpp - case 0x20 (JR NZ, e):
case 0x20: // JR NZ, e (Jump Relative if Not Zero)
{
uint8_t offset_raw = fetch_byte();
if (!regs_->get_flag_z()) {
// Condición verdadera: saltar
int8_t offset = static_cast(offset_raw);
uint16_t new_pc = (regs_->pc + offset) & 0xFFFF;
regs_->pc = new_pc;
cycles_ += 3;
return 3;
} else {
// Condición falsa: no saltar, continuar ejecución normal
cycles_ += 2;
return 2;
}
}
Archivos Afectados
src/core/cpp/CPU.cpp- Eliminación de logs de depuración enDEC ByJR NZ
Tests y Verificación
Validación de compilación:
- Recompilación exitosa del módulo C++ con
.\rebuild_cpp.ps1 - Sin errores de compilación
- Módulo
viboy_core.cp313-win_amd64.pydgenerado correctamente
Ejecución del emulador:
- El emulador se ejecuta sin errores:
python main.py roms/tetris.gb - La consola permanece en silencio durante la ejecución de los bucles (comportamiento esperado)
- La traza disparada está lista para activarse cuando el PC supere
0x0300
Análisis del comportamiento esperado:
Al ejecutar el emulador, la consola debería permanecer completamente en silencio durante un breve instante mientras la CPU ejecuta a toda velocidad los bucles de limpieza DEC B y DEC C sin imprimir nada. Después de que todos los bucles terminen y el PC finalmente supere 0x0300, el sistema de traza disparada debería activarse y mostrar:
--- [CPU TRACE TRIGGERED at PC: 0x0300] ---
[CPU TRACE 0] PC: 0x0300 | Opcode: 0xXX
[CPU TRACE 1] PC: 0x0301 | Opcode: 0xXX
...
[CPU TRACE 99] PC: 0xXXXX | Opcode: 0xXX
Fuentes Consultadas
- Análisis de trazas de ejecución de ROMs de Game Boy - Patrones comunes de inicialización
- Step 0157: Implementación de Trazado de CPU "Disparado" (Triggered)
- Step 0152: Fix del flag Z en instrucciones DEC
Integridad Educativa
Lo que Entiendo Ahora
- Bucles anidados en secuencia: Las rutinas de inicialización ejecutan múltiples bucles de limpieza en secuencia, cada uno usando un registro diferente. Cuando un bucle termina, la CPU continúa inmediatamente con el siguiente.
- Importancia de la limpieza de logs: Los logs de depuración detallados son útiles para diagnosticar problemas específicos, pero una vez confirmado el comportamiento, deben eliminarse para permitir que otros sistemas de trazado (como la traza disparada) funcionen correctamente.
- Silencio como señal positiva: En un emulador funcionando correctamente, el silencio durante la ejecución de bucles optimizados es una señal positiva: significa que la CPU está ejecutando a máxima velocidad sin overhead de I/O.
Lo que Falta Confirmar
- Traza post-bucles: Necesitamos capturar la traza que se genera cuando el PC finalmente supera
0x0300para confirmar que todos los bucles terminaron correctamente y ver qué código se ejecuta después. - Número exacto de bucles: Aunque sabemos que hay al menos dos bucles (DEC B y DEC C), no conocemos el número total de bucles de limpieza que ejecuta la ROM antes de llegar al código principal.
Hipótesis y Suposiciones
Hipótesis principal: La CPU está ejecutando correctamente todos los bucles de limpieza y eventualmente llegará a PC: 0x0300, momento en el cual la traza disparada se activará y capturará las instrucciones críticas que configuran los gráficos y el estado inicial del juego.
Suposición: El segundo bucle (DEC C) funciona de la misma manera que el primero (DEC B), utilizando el flag Z correctamente para terminar cuando C llega a 0x00.
Próximos Pasos
- [ ] Ejecutar el emulador y capturar la traza disparada cuando el PC supere
0x0300 - [ ] Analizar las 100 instrucciones capturadas para identificar opcodes faltantes
- [ ] Implementar los opcodes faltantes que impiden el avance de la ejecución
- [ ] Continuar el ciclo de depuración hasta que la ROM ejecute código significativo