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

Silencio Total (Release Candidate)

Fecha: 2025-12-23 Step ID: 0253 Estado: Draft

Resumen

Este Step elimina toda la instrumentación de depuración (`printf`) de `MMU.cpp` y `CPU.cpp` para permitir que el emulador corra a velocidad real (60 FPS). El Step 0252 confirmó que la lógica funcional (protección de ROM, DMA, interrupciones) está correcta, pero los miles de logs estaban ralentizando masivamente la ejecución, impidiendo ver el resultado final en pantalla. Esta es la limpieza final antes del "momento de la verdad": ejecutar Tetris a velocidad nativa.

Concepto de Hardware

En hardware real, la Game Boy ejecuta instrucciones a ~4.19 MHz, lo que permite renderizar 60 frames por segundo. Cada instrucción consume un número preciso de ciclos de máquina (M-Cycles), y el sistema debe mantener una sincronización perfecta entre la CPU, PPU, Timer y otros componentes.

El problema de la instrumentación: Cada llamada a `printf()` es una operación de I/O extremadamente lenta comparada con la ejecución de una instrucción de CPU. En un bucle de emulación que ejecuta millones de instrucciones por segundo, incluso un solo `printf()` por instrucción puede reducir el rendimiento de 60 FPS a 0.01 FPS reales. Para la CPU emulada, el tiempo pasa normal, pero para el usuario, el juego parece congelado.

Zero-Cost Abstractions: En el bucle crítico de emulación, cada operación debe ser lo más eficiente posible. Las abstracciones de alto nivel (como logging) deben eliminarse o moverse fuera del bucle crítico. El código C++ compilado debe ejecutarse sin overhead de I/O en el camino crítico.

Fuente: Pan Docs - "CPU Instruction Set", "Timing", "Performance Considerations"

Implementación

Se eliminaron todos los `printf()` activos de los archivos críticos del núcleo, manteniendo únicamente la lógica funcional. Los logs comentados se mantienen para referencia futura, pero no se ejecutan en tiempo de ejecución.

Componentes modificados

  • MMU.cpp: Eliminados logs de `[TIME]`, `[SENTINEL]`, `[DMA]`, `[WRAM-WRITE]`, `[HRAM]`. Eliminada variable estática `wram_log_count`.
  • CPU.cpp: Eliminados logs de `[DI]`, `[EI]`, `[INT]`, `[SNIPER]`. Eliminado `#include `.

Lógica preservada

Se mantiene intacta toda la lógica funcional crítica:

  • Protección de ROM (Step 0252): Previene escrituras en `0x0000-0x7FFF`.
  • DMA (OAM Transfer) (Step 0251): Copia 160 bytes a OAM cuando se escribe en `0xFF46`.
  • Interrupciones: Procesamiento completo de V-Blank, LCD STAT, Timer, Serial y Joypad.
  • Registros de Hardware: Lectura/escritura dinámica de STAT, DIV, TIMA, TMA, TAC, P1, LY.

Decisiones de diseño

Eliminación Total de Logs: En lugar de usar flags de compilación condicionales (`#ifdef DEBUG`), se eliminaron todos los logs activos. Esto simplifica el código y garantiza que no haya overhead en builds de release. Si se necesita depuración en el futuro, se puede usar un sistema de logging más sofisticado (como un buffer circular que se vacía periódicamente) o herramientas externas (como GDB).

Preservación de Comentarios: Los logs comentados se mantienen en el código para referencia futura. Esto permite reactivar la instrumentación rápidamente si es necesario, sin perder el contexto histórico de por qué se añadieron.

Eliminación de Includes Innecesarios: Se eliminó `#include ` de ambos archivos, ya que no hay funciones de I/O activas. Esto reduce ligeramente el tiempo de compilación y el tamaño del binario.

Archivos Afectados

  • src/core/cpp/MMU.cpp - Eliminados todos los `printf()` activos y variable estática `wram_log_count`. Eliminado `#include `.
  • src/core/cpp/CPU.cpp - Eliminados todos los `printf()` activos en `DI`, `EI` e `handle_interrupts()`. Eliminado `#include `.

Tests y Verificación

La verificación se realiza mediante compilación y ejecución a velocidad real:

  • Compilación: El código compila sin errores ni warnings. No hay referencias a funciones no definidas.
  • Linter: No se detectaron errores de linter en los archivos modificados.
  • Validación Nativa: El código C++ compilado no contiene llamadas a funciones de I/O en el bucle crítico.

Prueba de Rendimiento: El emulador debe ejecutarse a 60 FPS reales cuando se ejecuta `python main.py roms/tetris.gb`. Si la lógica es correcta (y el Step 0252 sugiere que lo es), Tetris debería arrancar y mostrar el copyright o el menú principal.

Nota: Si el juego sigue mostrando una pantalla verde después de 10 segundos, el problema no es de rendimiento sino de lógica. En ese caso, se puede reactivar el logging selectivo (por ejemplo, solo en el GPS de Python) para diagnóstico.

Fuentes Consultadas

  • Pan Docs: CPU Instruction Set, Timing
  • Principios de Optimización: "Zero-Cost Abstractions" en C++
  • Análisis de Rendimiento: Overhead de I/O en bucles críticos

Integridad Educativa

Lo que Entiendo Ahora

  • Overhead de I/O: Las operaciones de I/O (`printf`, `std::cout`) son órdenes de magnitud más lentas que las operaciones aritméticas o de memoria. En un bucle crítico que ejecuta millones de iteraciones por segundo, incluso un solo `printf()` puede reducir el rendimiento de 60 FPS a menos de 1 FPS.
  • Bucle Crítico: El método `step()` de la CPU se ejecuta millones de veces por segundo. Cualquier overhead en este método se multiplica por el número de instrucciones ejecutadas, haciendo que el emulador sea inutilizable.
  • Instrumentación vs. Rendimiento: La instrumentación es esencial para el desarrollo y depuración, pero debe eliminarse o moverse fuera del bucle crítico en builds de release. El código de producción debe ser lo más eficiente posible.

Lo que Falta Confirmar

  • Rendimiento Real: Verificar que el emulador ejecuta Tetris a 60 FPS reales sin logs. Si el rendimiento sigue siendo bajo, puede haber otros cuellos de botella (por ejemplo, en la PPU o en el bucle principal de Python).
  • Comportamiento del Juego: Confirmar que Tetris arranca correctamente y muestra el copyright o el menú principal. Si la pantalla sigue verde, el problema es de lógica, no de rendimiento.

Hipótesis y Suposiciones

Hipótesis Principal: El único problema restante era el overhead de los logs. Con la eliminación de todos los `printf()`, el emulador debería ejecutarse a velocidad real y Tetris debería arrancar correctamente.

Suposición: Si el juego sigue sin arrancar después de eliminar los logs, el problema está en la lógica de emulación (por ejemplo, un bug en el procesamiento de interrupciones o en la sincronización de componentes). En ese caso, se puede reactivar el logging selectivo para diagnóstico.

Próximos Pasos

  • [ ] Ejecutar `python main.py roms/tetris.gb` y verificar que el emulador corre a 60 FPS reales.
  • [ ] Confirmar que Tetris arranca y muestra el copyright o el menú principal.
  • [ ] Si el juego arranca correctamente, celebrar el hito y documentar el éxito.
  • [ ] Si la pantalla sigue verde, reactivar el logging selectivo (solo GPS de Python) para diagnóstico.
  • [ ] Considerar implementar un sistema de logging más sofisticado (buffer circular) para futuras depuraciones sin sacrificar rendimiento.