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.
Misión en la Zona Alta: Debugging del Juego
Resumen
El fix de `LY=0` funcionó a la perfección. La PPU ahora se comporta como un hardware real. La autopsia reveló que la CPU ha escapado de la BIOS y está ejecutando código del juego en la zona alta de la ROM (PC: `0x2B15`), pero mantiene la pantalla apagada (LCDC: `0x08`). Para entender por qué la secuencia de carga se ha detenido, reactivamos el trazado quirúrgico centrado en la dirección donde la CPU pasa su tiempo ahora.
Concepto de Hardware
Cuando un juego de Game Boy inicia, típicamente sigue esta secuencia:
- Fase de Arranque: La BIOS ejecuta código de inicialización (direcciones bajas: 0x0000-0x00FF).
- Transferencia de Control: El juego toma el control y comienza a ejecutar código del cartucho (direcciones altas: 0x0100+).
- Inicialización del Juego: El juego apaga la pantalla (LCDC Bit 7 = 0), carga gráficos en VRAM, configura paletas y vuelve a encenderla.
El hecho de que la CPU esté en `0x2B15` (zona alta de la ROM) indica que el juego ha superado la fase de arranque. Sin embargo, si el juego mantiene la pantalla apagada y no avanza, puede estar esperando:
- Timer (DIV): El registro DIV (0xFF04) incrementa continuamente. Algunos juegos esperan a que alcance un valor específico para sincronización.
- Interrupciones: El juego puede estar esperando una interrupción (V-Blank, Timer, etc.) que no está llegando.
- Joypad: Algunos juegos esperan una entrada del usuario antes de continuar.
- Bucle Infinito: Si el código en `0x2B15` es un salto incondicional a sí mismo (ej: `JR -1`), el juego está explícitamente colgado.
El trazado quirúrgico nos permitirá ver exactamente qué instrucciones está ejecutando la CPU y qué registros está consultando, lo que revelará la causa del bloqueo.
Implementación
Reactivamos el "Francotirador" (sniper) en la CPU para trazar instrucciones en el rango `0x2B10-0x2B20`, donde la CPU está pasando su tiempo según la autopsia del Step 0227.
Modificación en CPU.cpp
Añadimos un bloque de debug en el método `step()` que se activa cuando el PC está en el rango objetivo:
// --- Step 0228: FRANCOTIRADOR EN 0x2B15 ---
if (regs_->pc >= 0x2B10 && regs_->pc <= 0x2B20) {
uint8_t opcode_preview = mmu_->read(regs_->pc);
uint8_t div_val = mmu_->read(0xFF04);
printf("[SNIPER] PC:%04X | OP:%02X | AF:%04X | BC:%04X | DE:%04X | HL:%04X | DIV:%02X\n",
regs_->pc, opcode_preview, regs_->af, regs_->get_bc(), regs_->get_de(), regs_->get_hl(), div_val);
}
// ------------------------------------------
El trazado imprime:
- PC: Contador de programa (dirección actual)
- OP: Opcode de la instrucción que se va a ejecutar
- AF, BC, DE, HL: Estado de los registros principales
- DIV: Valor del registro DIV (Timer) para verificar si avanza
Decisiones de diseño
Elegimos un rango pequeño (0x2B10-0x2B20) para minimizar el impacto en el rendimiento. El debug solo se activa cuando la CPU está en esa zona específica, por lo que no afecta la ejecución normal del resto del código. También incluimos el registro DIV para verificar si el Timer está avanzando, lo que podría ser la causa del bloqueo.
Archivos Afectados
src/core/cpp/CPU.cpp- Añadido bloque de debug quirúrgico en `step()` para rango 0x2B10-0x2B20
Tests y Verificación
Para validar la implementación:
- Recompilar:
.\rebuild_cpp.ps1opython setup.py build_ext --inplace - Ejecutar:
python main.py roms/tetris.gb - Analizar salida: Buscar líneas con
[SNIPER]en la consola
Lo que buscamos:
- Si el código lee `0xFF04` (DIV) y compara, es un problema de Timer.
- Si el código lee `0xFF00` (Joypad), está esperando un botón.
- Si es un salto incondicional `JR -1`, es un cuelgue explícito (Game Over del emulador).
- Si el opcode se repite constantemente, es un bucle infinito.
Fuentes Consultadas
- Pan Docs: Game Boy Pan Docs - Especificación del hardware
- Implementación basada en conocimiento general de arquitectura LR35902 y técnicas de debugging de emuladores.
Integridad Educativa
Lo que Entiendo Ahora
- Fase de Arranque: La CPU ejecuta código de la BIOS primero, luego transfiere el control al cartucho.
- Zona Alta de ROM: Las direcciones 0x0100+ contienen código del juego. Si PC está en 0x2B15, el juego ya tomó el control.
- Bloqueo en Inicialización: Los juegos pueden detenerse esperando hardware (Timer, Interrupciones, Joypad) que no responde correctamente.
Lo que Falta Confirmar
- Opcode en 0x2B15: Qué instrucción está ejecutando el juego en ese punto.
- Registros Consultados: Si el juego está leyendo DIV, Joypad u otros registros de hardware.
- Patrón de Ejecución: Si es un bucle infinito o una espera activa.
Hipótesis y Suposiciones
Hipótesis Principal: El juego está esperando el Timer (DIV) para avanzar, pero el Timer no está incrementando correctamente, o el juego está esperando una interrupción que no se está generando. El trazado quirúrgico confirmará o refutará esta hipótesis.
Próximos Pasos
- [ ] Ejecutar el emulador y analizar la salida del Francotirador
- [ ] Identificar el opcode y el patrón de ejecución en 0x2B15
- [ ] Verificar si el Timer (DIV) está avanzando correctamente
- [ ] Determinar si el bloqueo es por Timer, Interrupciones o Joypad
- [ ] Implementar el fix correspondiente según el diagnóstico