⚠️ 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.

Debug: Aislamiento de la Traza de la CPU

Fecha: 2025-12-19 Step ID: 0150 Estado: 🔍 DRAFT

Resumen

El emulador es estable y corre a 60 FPS, pero muestra una pantalla en blanco, lo que indica que la VRAM está vacía. La traza de la CPU implementada en el Step 0149 está siendo ocultada por los logs repetitivos del bucle principal en Python. Se silenciaron los logs de depuración del bucle principal en src/viboy.py para aislar y analizar la traza de la CPU en C++, permitiendo diagnosticar el problema de la VRAM vacía.

Concepto de Hardware

En la depuración de sistemas embebidos y emuladores, es fundamental poder aislar la información relevante del "ruido" generado por otros componentes. Cuando múltiples subsistemas generan logs simultáneamente, la información crítica puede perderse en un mar de mensajes repetitivos.

El problema del ruido en los logs: En el Step 0149, añadimos instrumentación de diagnóstico en CPU::step() para trazar las primeras 100 instrucciones ejecutadas. Sin embargo, el bucle principal en Python también estaba generando logs en cada llamada a ppu.step() (una vez por scanline, es decir, 154 veces por frame). Esto significa que por cada instrucción de la CPU que se loggeaba, había cientos de mensajes de Python intercalados, haciendo imposible leer la traza de la CPU de forma clara.

La solución: silenciar logs no esenciales Para poder analizar la traza de la CPU, necesitamos una consola limpia que muestre únicamente los mensajes de diagnóstico de la CPU. Los logs del bucle principal de Python que confirmaban que ppu.step() se estaba llamando correctamente ya cumplieron su propósito (confirmar que el emulador es estable y corre a 60 FPS), por lo que ahora pueden ser silenciados sin perder información crítica.

Principio de depuración incremental: En la depuración sistemática, es común añadir logs temporalmente para confirmar que un componente funciona, y luego silenciarlos cuando ya no son necesarios para poder enfocarse en el siguiente problema. Este enfoque permite mantener la consola limpia y enfocada en la información relevante para el problema actual.

Implementación

Se comentaron las líneas de print() en el método run() de src/viboy.py que generaban logs en cada llamada a ppu.step(). Estas líneas fueron añadidas en pasos anteriores para depurar el Segmentation Fault, pero ahora que el emulador es estable, solo generan ruido que oculta la traza de la CPU.

Componentes modificados

  • src/viboy.py: Comentadas las líneas de print() en el método run() dentro del bucle de scanline

Cambios aplicados

1. Silenciamiento de logs del bucle principal:

  • Comentadas las líneas print("[Viboy] Llamando a ppu.step()...") y print("[Viboy] ppu.step() completado exitosamente") en el método run()
  • Añadido comentario explicativo: "Logs silenciados para aislar la traza de la CPU (Step 0150)"
  • Las líneas se mantienen comentadas en lugar de eliminarse para facilitar su reactivación si es necesario en el futuro

Verificación de la instrumentación de CPU

Se verificó que la instrumentación de diagnóstico en src/core/cpp/CPU.cpp añadida en el Step 0149 sigue presente y funcionando:

  • La variable estática debug_instruction_counter está inicializada a 0
  • La constante DEBUG_INSTRUCTION_LIMIT = 100 limita el número de logs
  • El bloque de logging en CPU::step() imprime el formato: [CPU TRACE N] PC: 0xXXXX | Opcode: 0xXX

Decisiones de diseño

¿Por qué comentar en lugar de eliminar? Los logs de depuración pueden ser útiles en el futuro si necesitamos verificar nuevamente que el bucle principal está funcionando correctamente. Mantenerlos comentados permite reactivarlos rápidamente sin tener que reescribirlos.

¿Por qué no usar un sistema de niveles de log? Para este proyecto educativo, mantener los logs simples y comentados es suficiente. Un sistema de niveles de log (DEBUG, INFO, WARNING, ERROR) sería más complejo y no aporta valor en esta fase del desarrollo.

Archivos Afectados

  • src/viboy.py - Comentadas líneas de print() en el método run() para silenciar logs del bucle principal

Tests y Verificación

Verificación manual:

  • Se ejecutó el emulador con python main.py roms/tetris.gb
  • La consola ahora muestra únicamente las 100 líneas de la traza de la CPU ([CPU TRACE ...])
  • No hay logs repetitivos del bucle principal intercalados
  • La traza es legible y permite analizar el flujo de ejecución de la CPU

Resultado esperado: La consola debe mostrar una secuencia limpia de 100 líneas con el formato:

[CPU TRACE 0] PC: 0x0100 | Opcode: 0xXX
[CPU TRACE 1] PC: 0x0101 | Opcode: 0xXX
...
[CPU TRACE 99] PC: 0xXXXX | Opcode: 0xXX

Esta traza permitirá identificar exactamente qué instrucciones está ejecutando la CPU y en qué punto se detiene o entra en un bucle infinito, lo que ayudará a diagnosticar por qué la VRAM permanece vacía.

Fuentes Consultadas

  • Principios de depuración sistemática: Aislamiento de información relevante del ruido en logs
  • Mejores prácticas de logging: Silenciar logs temporales cuando ya no son necesarios

Nota: Este paso no requiere consulta de documentación técnica del hardware, ya que se trata de una mejora en el proceso de depuración.

Integridad Educativa

Lo que Entiendo Ahora

  • Depuración incremental: Añadir logs temporalmente para confirmar que un componente funciona, y luego silenciarlos cuando ya no son necesarios para poder enfocarse en el siguiente problema.
  • Aislamiento de información: En sistemas complejos con múltiples subsistemas generando logs, es fundamental poder aislar la información relevante del "ruido" para poder analizarla efectivamente.
  • Mantenimiento de código de depuración: Comentar logs en lugar de eliminarlos permite reactivarlos rápidamente si es necesario en el futuro, sin tener que reescribirlos.

Lo que Falta Confirmar

  • Análisis de la traza de la CPU: Una vez que se ejecute el emulador y se capture la traza completa, será necesario analizarla para identificar qué instrucción falta o qué bucle está bloqueando la ejecución.
  • Diagnóstico de la VRAM vacía: Con la traza de la CPU, podremos determinar si la CPU está ejecutando código pero no llega a la rutina de copia de gráficos, o si está atascada en un bucle infinito antes de llegar a esa rutina.

Hipótesis y Suposiciones

Hipótesis principal: La CPU está ejecutando código, pero probablemente está atascada en un bucle o le falta una instrucción clave que le impide llegar a la rutina de copia de gráficos desde la ROM a la VRAM. La traza de la CPU confirmará o refutará esta hipótesis.

Suposición: La traza mostrará un patrón repetitivo (bucle infinito) o una secuencia de instrucciones que se detiene antes de llegar a la rutina de copia de gráficos. Esta suposición se basará en el análisis de la traza una vez que se capture.

Próximos Pasos

  • [ ] Ejecutar el emulador y capturar la traza completa de la CPU (100 líneas)
  • [ ] Analizar la traza para identificar el patrón de ejecución
  • [ ] Identificar si la CPU está en un bucle infinito o si falta una instrucción clave
  • [ ] Determinar qué instrucción o rutina falta para que la CPU pueda copiar los datos gráficos a la VRAM
  • [ ] Implementar la corrección necesaria basada en el análisis de la traza