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

Configuración del Pipeline de Compilación Híbrido

Fecha: 2025-12-19 Step ID: 0101 Estado: Verified

Resumen

Se ha configurado la infraestructura completa de compilación híbrida (Python + C++/Cython) para la Fase 2. Se creó la estructura de directorios del núcleo, se implementó una prueba de concepto "Hello World" en C++, se configuró el sistema de build con setup.py y se verificó que el pipeline de compilación funciona correctamente en Windows. Este es el primer paso crítico antes de migrar cualquier componente de emulación al código compilado.

Concepto de Hardware

Nota: Esta entrada no trata directamente sobre hardware del Game Boy, sino sobre la infraestructura de compilación necesaria para emularlo eficientemente.

La emulación ciclo a ciclo de un sistema como el Game Boy requiere precisión de timing en el orden de microsegundos. Python, siendo un lenguaje interpretado, introduce overhead significativo en cada operación, lo que impide alcanzar la sincronización necesaria para jugabilidad fluida.

La solución adoptada es una arquitectura híbrida:

  • Python (Frontend): Maneja la interfaz de usuario, carga de archivos, eventos de input y orquestación de alto nivel. Mantiene la flexibilidad y facilidad de desarrollo.
  • C++ (Núcleo): Implementa la lógica crítica de emulación ciclo a ciclo (CPU, MMU, PPU, APU). Proporciona el rendimiento necesario para sincronización precisa.
  • Cython (Puente): Permite que Python llame a código C++ compilado sin overhead significativo. Cython genera código C que se compila a extensiones Python (.pyd en Windows, .so en Linux/macOS).

Esta arquitectura permite mantener los beneficios de Python (tests, documentación, desarrollo rápido) mientras se obtiene el rendimiento de código compilado en las rutas críticas.

Implementación

Se configuró completamente el sistema de compilación híbrido siguiendo las mejores prácticas de Cython y setuptools. La implementación incluye:

1. Gestión de Dependencias

Se actualizó requirements.txt con las dependencias necesarias:

  • cython>=3.0.0: Compilador Cython para generar código C/C++
  • setuptools>=68.0.0: Sistema de build para extensiones Python
  • numpy>=1.24.0: Para futuros usos de buffers de video/audio (MemoryViews)

2. Estructura de Directorios

Se creó la siguiente estructura para organizar el código del núcleo:

src/core/
├── __init__.py          # Módulo Python del núcleo
├── cpp/                 # Código C++ puro (.cpp, .hpp)
│   ├── NativeCore.hpp
│   └── NativeCore.cpp
└── cython/              # Wrappers Cython (.pyx, .pxd)
    └── native_core.pyx

3. Prueba de Concepto: NativeCore

Se implementó una clase C++ simple NativeCore con un método add(int a, int b) para verificar que el pipeline funciona. Esta clase será expandida en el futuro para contener la lógica de emulación.

Archivo C++ (NativeCore.hpp/cpp):

  • Clase simple con constructor, destructor y método add()
  • Estándar C++17 para compatibilidad moderna
  • Preparado para expansión futura

4. Wrapper Cython

Se creó el wrapper Cython native_core.pyx que:

  • Declara la clase C++ usando cdef extern
  • Expone una clase Python PyNativeCore que envuelve la clase C++
  • Gestiona memoria correctamente (constructor __cinit__ y destructor __dealloc__)
  • Permite llamar métodos C++ desde Python sin overhead

5. Sistema de Build (setup.py)

Se configuró setup.py con:

  • Extensiones Cython usando Cython.Build.cythonize
  • Configuración de compilador C++17 (compatible con Windows/Linux/macOS)
  • Directivas de optimización: boundscheck=False, wraparound=False
  • Include directories para headers C++ y numpy

6. Script de Verificación

Se creó test_build.py que:

  • Importa el módulo compilado viboy_core
  • Crea una instancia de PyNativeCore
  • Ejecuta la prueba: core.add(2, 2) == 4
  • Proporciona mensajes de error claros si la compilación falla

Decisiones de Diseño

  • Separación C++/Cython: El código C++ puro está en cpp/ y los wrappers en cython/. Esto permite reutilizar el código C++ en otros contextos si es necesario.
  • Naming: El módulo compilado se llama viboy_core para evitar conflictos con el módulo Python src/core.
  • Windows Compatibility: Se usa /std:c++17 para MSVC y -std=c++17 para GCC/Clang, detectando automáticamente la plataforma.

Archivos Afectados

  • requirements.txt - Añadidas dependencias Cython, setuptools, numpy
  • src/core/__init__.py - Módulo Python del núcleo (nuevo)
  • src/core/cpp/NativeCore.hpp - Header C++ de prueba (nuevo)
  • src/core/cpp/NativeCore.cpp - Implementación C++ de prueba (nuevo)
  • src/core/cython/native_core.pyx - Wrapper Cython (nuevo)
  • setup.py - Sistema de build para extensiones (nuevo)
  • test_build.py - Script de verificación (nuevo)

Tests y Verificación

La verificación se realizó mediante el script test_build.py:

  1. Compilación: Ejecutar python setup.py build_ext --inplace genera el archivo viboy_core.pyd (o viboy_core.so en Linux/macOS) en el directorio raíz.
  2. Importación: El módulo se importa correctamente desde Python.
  3. Instanciación: Se puede crear una instancia de PyNativeCore sin errores.
  4. Funcionalidad: El método add(2, 2) retorna correctamente 4.

Comando de compilación:

python setup.py build_ext --inplace

Comando de verificación:

python test_build.py

Nota: Si la compilación falla, puede ser necesario instalar Visual Studio Build Tools en Windows o las herramientas de desarrollo en Linux/macOS.

Resultados de Verificación Realizados

La compilación y verificación se ejecutaron exitosamente en Windows 10 con Python 3.13:

  • Dependencias instaladas: Cython 3.2.3, setuptools 75.1.0, numpy 2.2.6
  • Compilador detectado: Visual Studio 2022 Community (MSVC 14.44.35207)
  • Archivo generado: viboy_core.cp313-win_amd64.pyd (44 KB)
  • Estándar C++: C++17 habilitado correctamente
  • Warnings: Algunos warnings menores de Cython (normales, no afectan funcionalidad)
  • Importación: Módulo importado correctamente desde Python
  • Instanciación: PyNativeCore() creada sin errores
  • Funcionalidad: core.add(2, 2) retorna 4 correctamente

Conclusión: El pipeline de compilación híbrido está completamente funcional y listo para comenzar la migración de componentes reales de emulación.

Fuentes Consultadas

Nota: Esta implementación es estándar y no requiere documentación específica de hardware del Game Boy. Se basa en conocimiento general de interoperabilidad Python/C++ mediante Cython.

Integridad Educativa

Lo que Entiendo Ahora

  • Cython como puente: Cython permite escribir código "casi Python" que se compila a C, generando extensiones Python que pueden llamar código C++ directamente. El overhead de llamadas es mínimo comparado con ctypes o cffi.
  • Gestión de memoria: Las clases Cython que envuelven objetos C++ deben gestionar memoria manualmente en __cinit__ y __dealloc__. Esto es crítico para evitar memory leaks.
  • Tipos estáticos: Cython permite usar tipos estáticos de C (cdef int, cdef unsigned char) que evitan el overhead de objetos Python en rutas críticas.
  • MemoryViews: Para buffers grandes (video/audio), Cython puede usar MemoryViews de numpy que permiten acceso directo a memoria sin copias.

Lo que Falta Confirmar

  • Rendimiento real: Aunque el pipeline funciona, falta medir el rendimiento real comparado con Python puro. Esto se validará al migrar componentes reales de emulación.
  • Compatibilidad cross-platform: La compilación se probó en Windows. Falta verificar que funciona correctamente en Linux y macOS.
  • Debugging: Falta explorar herramientas de debugging para código C++ compilado desde Python (gdb, Visual Studio Debugger, etc.).

Hipótesis y Suposiciones

Se asume que el compilador C++ está disponible en el sistema. En Windows, esto requiere Visual Studio Build Tools o Visual Studio con componentes de C++. Si no está disponible, el usuario deberá instalarlo.

Se asume que la arquitectura híbrida será suficiente para alcanzar 60 FPS estables. Si no es así, puede ser necesario optimizar más agresivamente o considerar otras estrategias (JIT compilation, etc.).

Próximos Pasos

  • [ ] Migrar CPU (LR35902) a C++/Cython
  • [ ] Migrar MMU a código compilado
  • [ ] Migrar PPU a código compilado
  • [ ] Implementar APU (Audio Processing Unit) en C++
  • [ ] Optimizar sincronización ciclo a ciclo
  • [ ] Validar rendimiento con juegos sensibles al timing