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.
Bitácora del Proyecto Viboy Color
Registro educativo del desarrollo de un emulador de Game Boy Color en Python. Implementación clean-room basada en documentación técnica.
Entradas de la Bitácora
Las entradas están ordenadas por fecha, más recientes primero.
-
¡Hito crítico: El sistema ahora tiene "latido" gráfico! Se implementó el motor de timing de la PPU (Pixel Processing Unit), que permite que los juegos detecten el V-Blank y salgan de bucles infinitos de espera. La implementación incluye el registro LY (Línea actual) que cambia automáticamente cada 456 T-Cycles, la activación de la interrupción V-Blank cuando LY llega a 144, y el wrap-around de frame cuando LY supera 153. Sin esta funcionalidad, juegos como Tetris DX se quedaban esperando eternamente porque LY siempre devolvía 0. Ahora el sistema tiene el "reloj" necesario para que los juegos puedan sincronizarse y avanzar más allá de la inicialización. Suite completa de tests TDD (8 tests) validando todas las funcionalidades. Todos los tests pasan.
-
¡ISA (Instruction Set Architecture) de la CPU completada al 100%! Se implementaron los dos últimos opcodes faltantes: LD (C), A (0xE2) y LD A, (C) (0xF2). Estas instrucciones permiten acceso dinámico a registros de hardware usando C como offset, útiles para bucles de inicialización. Además, se mejoró significativamente la visibilidad del sistema añadiendo constantes para todos los registros de hardware (LCDC, STAT, BGP, etc.) y mejorando el logging de la MMU para mostrar nombres de registros en lugar de direcciones hexadecimales. Con esto, el emulador puede ejecutar código completo de juegos reales y los logs ahora muestran información legible como "IO WRITE: LCDC = 0x91". Suite completa de tests TDD (6 tests) validando todas las funcionalidades. Todos los tests pasan.
-
¡Hito histórico! Se completó al 100% el set de instrucciones de la CPU LR35902 implementando las últimas instrucciones misceláneas: DAA (Decimal Adjust Accumulator), CPL (Complement), SCF (Set Carry Flag), CCF (Complement Carry Flag) y los 8 vectores RST (Restart). Con esto, la CPU tiene implementados los 500+ opcodes de la Game Boy (incluyendo el prefijo CB). DAA es especialmente importante porque permite trabajar con BCD para puntuaciones en pantalla. RST es vital porque las interrupciones hardware lo usan para saltar a sus manejadores. Suite completa de tests TDD (12 tests) validando todas las operaciones. Todos los tests pasan.
-
Se completó al 100% la tabla CB del prefijo extendido implementando las tres cuartas partes restantes: BIT (0x40-0x7F), RES (0x80-0xBF) y SET (0xC0-0xFF). Estas instrucciones son fundamentales para la manipulación de bits, que es una operación extremadamente común en los juegos de Game Boy. Por ejemplo, Tetris usa constantemente RES 7, (HL) para marcar que un bloque ha dejado de caer. La implementación completa cubre 192 opcodes CB adicionales (64 por operación), completando así las 256 instrucciones del prefijo CB. Suite completa de tests TDD (8 tests) validando todas las operaciones. Todos los tests pasan.
-
Se implementó el primer cuarto de la tabla CB (rango 0x00-0x3F) con todas las operaciones de rotación, desplazamiento y SWAP. Estas instrucciones son "la salsa secreta" de la Game Boy: se usan para animaciones, físicas, compresión de datos y generación de números aleatorios. La implementación incluye 8 operaciones (RLC, RRC, RL, RR, SLA, SRA, SRL, SWAP) aplicables a 8 destinos (B, C, D, E, H, L, (HL), A), generando 64 opcodes CB en total. La diferencia crítica con las rotaciones rápidas (RLCA, etc.) es que las versiones CB SÍ calculan el flag Z según el resultado, mientras que las rotaciones rápidas siempre ponen Z=0. Suite completa de tests TDD (12 tests) validando todas las operaciones. Todos los tests pasan.
-
Se completó la familia de cargas inmediatas de 8 bits implementando los opcodes faltantes: LD C, d8 (0x0E), LD D, d8 (0x16), LD E, d8 (0x1E), LD H, d8 (0x26), LD L, d8 (0x2E) y LD (HL), d8 (0x36). Estas instrucciones son fundamentales para inicializar contadores de bucles, constantes y buffers de memoria. El emulador se detenía en 0x0E (LD C, d8) cuando ejecutaba Tetris DX, lo que confirmaba que faltaban estas cargas inmediatas. Con esta implementación, la CPU ahora puede cargar valores inmediatos en todos los registros de 8 bits y escribir directamente en memoria indirecta, cubriendo el 90% de la lógica de propósito general de un programa. Suite completa de tests TDD (6 tests) validando todas las cargas inmediatas. Todos los tests pasan.
-
Se completó el conjunto de operaciones ALU inmediatas (con operandos de 8 bits embebidos en el código), implementando ADC A, d8 (0xCE), SBC A, d8 (0xDE), AND d8 (0xE6), XOR d8 (0xEE) y OR d8 (0xF6). Estas instrucciones son críticas porque permiten operar con constantes directamente del código, sin necesidad de cargar valores en registros primero. La implementación reutiliza los helpers genéricos ya existentes (_adc, _sbc, _and, _xor, _or), siguiendo el principio DRY. Con esto, la CPU ahora tiene capacidad computacional completa para operaciones de 8 bits, lo que permite que juegos como Tetris DX avancen más allá de la inicialización. Suite completa de tests TDD (5 tests) validando todas las operaciones inmediatas. Todos los tests pasan.
-
Se completó el manejo del Stack (Pila) implementando PUSH/POP para todos los pares de registros (AF, DE, HL), y se añadieron las rotaciones rápidas del acumulador (RLCA, RRCA, RLA, RRA). La implementación de POP AF incluye la máscara crítica 0xF0 para los bits bajos del registro F, simulando el comportamiento del hardware real. Las rotaciones rápidas tienen un comportamiento especial con los flags: Z siempre es 0, incluso si el resultado es cero. Esta es una diferencia clave con las rotaciones del prefijo CB. Todos los tests pasan (17 tests en total). Estas instrucciones son fundamentales para que juegos como Tetris puedan generar números aleatorios y restaurar el estado de flags después de interrupciones.
-
Implementación del bloque completo de la ALU (Unidad Aritmética Lógica) del rango 0x80-0xBF, cubriendo 64 opcodes que incluyen todas las operaciones aritméticas y lógicas principales: ADD, ADC (Add with Carry), SUB, SBC (Subtract with Carry), AND, XOR, OR y CP (Compare). Se implementaron helpers genéricos para cada operación y se documentó el comportamiento especial del flag H en la operación AND (quirk del hardware: siempre se pone a 1). Suite completa de tests TDD (8 tests) validando todas las funcionalidades, incluyendo ADC/SBC con carry y el quirk del flag H. Todos los tests pasan. El emulador ahora puede ejecutar el opcode 0xB3 (OR A, E) que Tetris DX pide en 0x1389, permitiendo que el juego avance más allá de la inicialización.
-
Implementación del bloque completo de transferencias de 8 bits (LD r, r') del rango 0x40-0x7F, cubriendo 63 opcodes nuevos que permiten mover datos entre registros y memoria. Se implementó también la instrucción HALT (0x76) que pone la CPU en modo de bajo consumo. El bloque es crítico porque permite que el emulador ejecute código real de juegos que necesita transferir datos entre registros. Se usó inicialización lazy de handlers para evitar problemas de orden de definición. Suite completa de tests TDD (8 tests) validando todas las funcionalidades. Todos los tests pasan. El emulador ahora puede ejecutar transferencias de datos, un paso fundamental para que los juegos puedan funcionar correctamente.
-
Implementación de aritmética de 16 bits (INC/DEC de registros pares y ADD HL, rr) y retornos condicionales (RET NZ, RET Z, RET NC, RET C). Peculiaridad crítica: INC/DEC de 16 bits NO afectan a ningún flag (a diferencia de los de 8 bits), esencial para bucles que decrementan contadores sin corromper flags. ADD HL, rr actualiza flags H y C pero NO toca Z, otro comportamiento especial del hardware LR35902. Los retornos condicionales consumen 5 M-Cycles cuando se toman y 2 M-Cycles cuando no. Suite completa de tests TDD (24 tests) validando todas las funcionalidades. El emulador ahora puede ejecutar bucles complejos como los de inicialización de Tetris DX.
-
Implementación de cargas inmediatas de 16 bits para los registros BC y DE, almacenamiento indirecto usando BC y DE como punteros, y la instrucción crítica de comparación CP (Compare). Se añadió el helper _cp() que realiza una "resta fantasma" (actualiza flags sin modificar A) y se implementaron los opcodes LD BC, d16 (0x01), LD DE, d16 (0x11), LD (BC), A (0x02), LD (DE), A (0x12), CP d8 (0xFE) y CP (HL) (0xBE). Estas instrucciones son esenciales para que el emulador pueda avanzar más allá de la inicialización, permitiendo cargar constantes en registros pares y tomar decisiones condicionales. Suite completa de tests TDD (9 tests) validando todas las funcionalidades. También se corrigió un bug en la MMU donde el área de ROM devolvía 0xFF cuando no había cartucho.
-
Implementación de acceso a registros de hardware (I/O Ports) mediante instrucciones LDH y el sistema de prefijo CB para instrucciones extendidas. Se implementaron los opcodes LDH (n), A (0xE0) y LDH A, (n) (0xF0) para escribir y leer del área I/O (0xFF00-0xFFFF). Se añadió el manejo del prefijo CB (0xCB) con una segunda tabla de despacho que permite acceder a 256 instrucciones adicionales. Se implementó la instrucción BIT 7, H (CB 0x7C) con un helper genérico _bit() que actualiza flags correctamente. Estas instrucciones son críticas para que Tetris DX pueda configurar el hardware y ejecutar bucles de limpieza de memoria. Suite completa de tests TDD (7 tests) validando todas las funcionalidades.
-
Implementación de direccionamiento indirecto usando HL como puntero de memoria, operaciones LDI/LDD (incremento/decremento automático del puntero) y operaciones unarias de incremento/decremento (INC/DEC) con manejo correcto de flags. Se implementaron helpers críticos _inc_n y _dec_n que actualizan flags Z, N, H pero NO tocan el flag C (Carry), una peculiaridad importante del hardware LR35902. Estos opcodes son esenciales para bucles de limpieza de memoria que los juegos ejecutan al inicio (memset). Suite completa de tests TDD validando memoria indirecta y flags.
-
Implementación de instrucciones críticas de control de sistema y operaciones lógicas necesarias para que Tetris DX continúe ejecutándose. Se añadió el atributo IME (Interrupt Master Enable) a la CPU para controlar las interrupciones. Se implementaron los opcodes DI (0xF3) y EI (0xFB) para desactivar/activar interrupciones, XOR A (0xAF) como optimización para poner el registro A a cero, y las instrucciones de carga inmediata de 16 bits LD SP, d16 (0x31) y LD HL, d16 (0x21). Estas instrucciones son esenciales para la inicialización del sistema. Suite completa de tests TDD (13 tests).
-
Implementación de la clase Viboy que actúa como la "placa base" del emulador, integrando todos los componentes (CPU, MMU, Cartridge) en un sistema unificado. Creación del bucle principal (Game Loop) que ejecuta instrucciones continuamente, simulando el funcionamiento de la Game Boy real a 4.194304 MHz. El sistema ahora puede ejecutar código real de ROMs, aunque se detendrá cuando encuentre opcodes no implementados. Modo debug implementado para mostrar trazas detalladas de cada instrucción ejecutada. Sin este bucle, la CPU no puede "vivir" y procesar código de juegos. Suite completa de tests de integración (8 tests).
-
Implementación de la clase Cartridge que carga archivos ROM (`.gb` o `.gbc`) y parsea el Header del cartucho para extraer información crítica (título, tipo de cartucho, tamaño de ROM/RAM). Integración del cartucho en la MMU para mapear la ROM en el espacio de direcciones (0x0000 - 0x7FFF). Actualización de main.py para aceptar argumentos de línea de comandos y cargar ROMs reales. Sin esta funcionalidad, el emulador no puede ejecutar código de juegos reales. Suite completa de tests TDD (6 tests) validando carga, parsing y casos edge.
-
Implementación completa del Stack (Pila) de la CPU, incluyendo helpers para PUSH/POP de bytes y palabras, y opcodes críticos para subrutinas: PUSH BC (0xC5), POP BC (0xC1), CALL nn (0xCD) y RET (0xC9). La pila es la memoria a corto plazo que permite a la CPU recordar "dónde estaba" cuando llama a funciones. Concepto crítico: la pila crece hacia abajo (SP decrece en PUSH). Implementación con orden correcto de bytes (Little-Endian) validada con suite completa de tests TDD (5 tests).
-
Añadida licencia MIT al proyecto para proteger el trabajo educativo y definir claramente cómo otros pueden usar, modificar y distribuir el código. Creado archivo LICENSE con el texto oficial de la licencia MIT (año 2025). Actualizado README.md con badge de licencia y sección mejorada. El proyecto ahora es oficialmente Open Source bajo licencia MIT.
-
Implementación de instrucciones de salto (JP nn, JR e, JR NZ,e) que permiten romper la ejecución lineal de la CPU, habilitando bucles y decisiones. Concepto crítico: conversión de enteros sin signo a con signo (Two's Complement) para offsets relativos negativos. Implementación de timing condicional (diferentes ciclos según si se toma o no el salto). Suite completa de tests TDD (11 tests) validando saltos positivos, negativos y condicionales.
-
Implementación de la ALU (Unidad Aritmética Lógica) con gestión correcta de flags, especialmente el Half-Carry (H) crítico para DAA. Refactorización de la CPU para usar tabla de despacho (dispatch table) en lugar de if/elif. Implementación de opcodes ADD A, d8 (0xC6) y SUB d8 (0xD6). Suite completa de tests TDD (5 tests) validando operaciones aritméticas y flags.
-
Implementación de la clase CPU que unifica Registros y MMU para crear el ciclo Fetch-Decode-Execute. Primeros 3 opcodes implementados (NOP, LD A,d8, LD B,d8). La CPU ahora puede ejecutar instrucciones secuencialmente, marcando el primer "latido" funcional del emulador. Suite completa de tests (6 tests pasando).
-
Implementación de la clase MMU (Memory Management Unit) que gestiona el espacio de direcciones de 16 bits de la Game Boy. Métodos para leer/escribir bytes y palabras con soporte correcto para Little-Endian. Suite completa de tests unitarios (13 tests pasando).
-
Implementación completa de la clase Registers con todos los registros de 8 y 16 bits, pares virtuales (AF, BC, DE, HL), peculiaridad hardware del registro F, y suite completa de tests unitarios (15 tests pasando).
-
Configuración inicial de la bitácora web estática con estructura HTML/CSS, plantilla base, y primera entrada. Sistema de documentación educativa para el proyecto Viboy Color.
Información del Proyecto
Sobre Viboy Color
Viboy Color es un emulador educativo de Game Boy Color escrito en Python 3.10+. El objetivo principal es aprender sobre emulación de hardware mediante una implementación clean-room, sin copiar código de otros emuladores existentes.
Principios del Proyecto
- Clean-Room: Implementación basada únicamente en documentación técnica y tests permitidas.
- Educativo: Priorizar comprensión y documentación del aprendizaje.
- Portabilidad: Compatible con Windows, Linux y macOS.
- Python Moderno: Uso de Python 3.10+ con tipado estricto y tests.
Estructura de las Entradas
Cada entrada de la bitácora incluye:
- Resumen: Descripción breve del paso
- Concepto de Hardware: Explicación educativa del concepto implementado
- Implementación: Qué se hizo y por qué
- Archivos Afectados: Lista de archivos creados/modificados
- Tests y Verificación: Cómo se validó la implementación
- Fuentes Consultadas: Referencias técnicas utilizadas
- Integridad Educativa: Lo que se entiende, lo que falta confirmar, hipótesis
- Próximos Pasos: Checklist de tareas siguientes