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.
Hard Rebuild y Diagnóstico de Ciclos
Resumen
El usuario reportó que seguía viendo el "Punto Rojo" (código antiguo del paso 116) y que LY se mantenía en 0, a pesar de que el código fuente ya estaba actualizado. El diagnóstico indicó que el binario `.pyd` no se había actualizado correctamente en Windows, posiblemente porque Python tenía el archivo cargado en memoria. Se implementó una solución radical: añadir un log temporal en C++ para confirmar que se ejecuta código nuevo, mejorar el diagnóstico en Python para mostrar ciclos y LCDC, y proporcionar comandos para forzar la recompilación en Windows.
Concepto de Hardware
En Windows, cuando Python importa un módulo compilado (`.pyd`), el sistema operativo carga el archivo en memoria. Si intentas recompilar el módulo mientras Python aún tiene el archivo cargado, Windows puede:
- Bloquear la escritura: El archivo está en uso y no se puede sobrescribir.
- Permitir la escritura pero mantener la versión antigua en memoria: Python sigue usando la versión antigua que ya cargó.
- Fallar silenciosamente: La compilación parece exitosa, pero el archivo no se actualiza.
Para forzar la actualización, es necesario:
- Cerrar todas las instancias de Python que puedan tener el módulo cargado.
- Renombrar o eliminar el archivo `.pyd` antiguo antes de recompilar.
- Recompilar desde cero con `python setup.py build_ext --inplace`.
Además, para diagnosticar si el código nuevo se está ejecutando, añadimos un log temporal que se imprime la primera vez que se llama a `PPU::step()`. Si este log aparece, confirmamos que el binario se actualizó correctamente.
Implementación
Se implementaron tres cambios principales:
1. Log Temporal en PPU C++
Se añadió un log temporal en `PPU::step()` que se imprime la primera vez que se llama al método. Este log confirma que el código nuevo se está ejecutando:
// DIAGNÓSTICO TEMPORAL: Confirmar que se ejecuta código nuevo
static bool first_call = true;
if (first_call) {
printf("[PPU C++] STEP LIVE - Código actualizado correctamente\n");
first_call = false;
}
Nota: Este log es temporal y debe eliminarse después de verificar que funciona.
2. Diagnóstico de Ciclos en Python
Se añadió una advertencia en el bucle de scanline para detectar si `line_cycles` es 0, lo que indicaría que la CPU no está ejecutando instrucciones:
# DIAGNÓSTICO: Verificar ciclos ejecutados en el scanline
if line_cycles == 0:
logger.warning(f"⚠️ ADVERTENCIA: line_cycles=0 en scanline. CPU puede estar detenida.")
3. Diagnóstico de LCDC en Heartbeat
Se mejoró el heartbeat para mostrar el valor de LCDC (registro 0xFF40) y si el LCD está encendido o apagado:
logger.info(
f"💓 Heartbeat ... LY={ly_value} | LCDC=0x{lcdc_value:02X} "
f"(LCD {'ON' if (lcdc_value & 0x80) != 0 else 'OFF'}) "
f"| PPU {'viva' if ly_value > 0 or frame_count > 60 else 'inicializando'}"
)
Esto permite diagnosticar si el LCD está apagado (LCDC=0x00) o si hay otro problema.
Comandos para Forzar Recompilación en Windows
Se proporcionaron comandos para forzar la recompilación:
- Cerrar todas las instancias de Python (terminales, IDEs, procesos en segundo plano).
- Renombrar el archivo `.pyd` antiguo:
ren build\lib.win-amd64-cpython-313\viboy_core.cp313-win_amd64.pyd viboy_core_OLD.pyd - Limpiar archivos compilados:
python setup.py clean --all - Recompilar:
python setup.py build_ext --inplace
Archivos Afectados
src/core/cpp/PPU.cpp- Añadido log temporal para confirmar ejecución de código nuevosrc/viboy.py- Añadido diagnóstico de ciclos y LCDC en el bucle principal
Tests y Verificación
La verificación se realiza ejecutando el emulador y observando:
- Log de confirmación: Si aparece `[PPU C++] STEP LIVE - Código actualizado correctamente` en la consola, el binario se actualizó correctamente.
- Pantalla blanca: Si el framebuffer se inicializa correctamente a `0xFFFFFFFF`, la pantalla debe ser blanca (sin punto rojo).
- LY avanzando: Si LY cambia de 0 a valores mayores, la PPU está funcionando.
- LCDC cambiando: Si LCDC cambia de 0x00 a 0x91 (o similar), el juego está inicializando el LCD.
Comando de prueba:
python main.py roms/tetris.gb
Validación esperada:
- Log `[PPU C++] STEP LIVE` aparece al inicio.
- Pantalla blanca (sin punto rojo).
- Heartbeat muestra `LY` avanzando y `LCDC` cambiando.
Fuentes Consultadas
- Documentación de Windows: Comportamiento de archivos DLL/PDY en uso
- Pan Docs: Registro LCDC (0xFF40) y control del LCD
Integridad Educativa
Lo que Entiendo Ahora
- Windows y módulos compilados: Windows bloquea archivos `.pyd` cuando están en uso por Python. Para actualizar el módulo, es necesario cerrar todas las instancias de Python o renombrar el archivo antes de recompilar.
- Diagnóstico de código nuevo: Añadir un log temporal que se imprime la primera vez que se ejecuta un método es una forma efectiva de confirmar que el binario se actualizó correctamente.
- LCDC y estado del LCD: El registro LCDC (0xFF40) controla si el LCD está encendido (bit 7). Si el LCD está apagado, la PPU se detiene y LY se mantiene en 0.
Lo que Falta Confirmar
- Comportamiento en otros sistemas: ¿Linux y macOS tienen el mismo problema con archivos `.so` en uso?
- Estrategia de build: ¿Deberíamos añadir un script de build que automáticamente cierre procesos de Python y renombre archivos antes de compilar?
Hipótesis y Suposiciones
Asumimos que el problema es que Windows no permite sobrescribir archivos `.pyd` en uso. Si el problema persiste después de seguir estos pasos, puede haber otro problema (por ejemplo, el compilador no está generando el archivo en la ubicación correcta).
Próximos Pasos
- [ ] Verificar que el log `[PPU C++] STEP LIVE` aparece al ejecutar el emulador
- [ ] Confirmar que la pantalla es blanca (sin punto rojo)
- [ ] Verificar que LY avanza correctamente
- [ ] Eliminar el log temporal después de confirmar que funciona
- [ ] Considerar añadir un script de build automatizado para Windows