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

Fix de Compatibilidad API MMU y Numpy

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

Resumen

Al ejecutar el emulador con el núcleo C++ migrado, aparecieron dos errores críticos: (1) `ModuleNotFoundError: No module named 'numpy'` al intentar usar el framebuffer Zero-Copy, y (2) `AttributeError: 'viboy_core.PyMMU' object has no attribute 'read_byte'` porque el wrapper Cython expone métodos `read()`/`write()` pero el código Python espera `read_byte()`/`write_byte()`. Se implementaron métodos de compatibilidad (aliases) en el wrapper PyMMU y se verificó la instalación de numpy para mantener retrocompatibilidad con el código Python existente.

Concepto de Hardware

Este fix no está relacionado directamente con el hardware del Game Boy, sino con la arquitectura híbrida Python-C++ del proyecto. Durante la migración del núcleo a C++, se creó un wrapper Cython (`PyMMU`) que expone la clase C++ `MMU` a Python.

El problema surge cuando el código Python existente (como `renderer.py`) fue escrito para trabajar con la MMU Python original, que tenía métodos `read_byte()`, `write_byte()`, `read_word()` y `write_word()`. El nuevo wrapper Cython expuso métodos más simples (`read()` y `write()`), rompiendo la compatibilidad con el código legacy.

Retrocompatibilidad en arquitecturas híbridas: Cuando se migra código de un lenguaje a otro, es crucial mantener la API pública compatible para evitar tener que reescribir todo el código que depende de ella. Los métodos "alias" son una técnica común para mantener compatibilidad mientras se refactoriza internamente.

Implementación

Se añadieron cuatro métodos de compatibilidad al wrapper `PyMMU` en `src/core/cython/mmu.pyx`:

Métodos de Compatibilidad Añadidos

  • read_byte(addr): Alias de read(addr) para compatibilidad con código Python antiguo.
  • write_byte(addr, value): Alias de write(addr, value).
  • read_word(addr): Lee 16 bits usando Little-Endian (LSB en addr, MSB en addr+1).
  • write_word(addr, value): Escribe 16 bits usando Little-Endian.

Implementación de read_word/write_word

Los métodos `read_word()` y `write_word()` implementan correctamente el orden Little-Endian de la Game Boy:

def read_word(self, uint16_t addr):
    # Leer LSB (menos significativo) en addr
    cdef uint8_t lsb = self.read(addr)
    
    # Leer MSB (más significativo) en addr+1 (con wrap-around)
    cdef uint8_t msb = self.read((addr + 1) & 0xFFFF)
    
    # Combinar en Little-Endian: (MSB << 8) | LSB
    return ((msb << 8) | lsb) & 0xFFFF

def write_word(self, uint16_t addr, uint16_t value):
    # Extraer LSB y MSB
    cdef uint8_t lsb = value & 0xFF
    cdef uint8_t msb = (value >> 8) & 0xFF
    
    # Escribir en orden Little-Endian
    self.write(addr, lsb)
    self.write((addr + 1) & 0xFFFF, msb)

Dependencia Numpy

Numpy ya estaba en `requirements.txt` pero no estaba instalado en el entorno virtual. Se verificó su instalación y se confirmó que está disponible. Numpy es necesario para el framebuffer Zero-Copy que permite transferir el buffer de píxeles de C++ a Pygame sin copias de memoria.

Decisiones de Diseño

  • Alias en lugar de renombrar: Se optó por mantener ambos nombres de métodos (`read()` y `read_byte()`) para no romper código existente ni código nuevo que use la API simplificada.
  • Implementación en Cython: Los métodos `read_word()` y `write_word()` se implementaron en Cython usando los métodos base `read()` y `write()`, evitando duplicar lógica en C++.
  • Tipado estático: Se usaron tipos C (`cdef uint8_t`, `cdef uint16_t`) para mantener el rendimiento sin overhead de Python.

Archivos Afectados

  • src/core/cython/mmu.pyx - Añadidos métodos de compatibilidad (read_byte, write_byte, read_word, write_word)
  • requirements.txt - Verificado que numpy>=1.24.0 está presente

Tests y Verificación

La verificación se realizó mediante:

  • Compilación exitosa: El módulo Cython se recompiló sin errores usando python setup.py build_ext --inplace.
  • Validación de sintaxis: No se encontraron errores de linter en el archivo modificado.
  • Numpy instalado: Se confirmó que numpy está disponible en el entorno virtual.

Próxima verificación: Ejecutar el emulador con una ROM para confirmar que el renderer puede acceder a la MMU sin errores de atributos faltantes.

Fuentes Consultadas

Nota: Este fix es principalmente sobre arquitectura de software e interoperabilidad Python-C++, no sobre hardware del Game Boy.

Integridad Educativa

Lo que Entiendo Ahora

  • Retrocompatibilidad en wrappers: Cuando se crea un wrapper de C++ a Python, es crucial mantener la API compatible con el código existente. Los métodos alias son una solución elegante que no añade overhead significativo.
  • Little-Endian en Game Boy: La implementación de `read_word()` y `write_word()` confirma que la Game Boy usa Little-Endian, donde el byte menos significativo se almacena en la dirección más baja.
  • Zero-Copy con Numpy: Numpy es esencial para transferir buffers de memoria entre C++ y Python sin copias, usando memoryviews que apuntan directamente a la memoria nativa.

Lo que Falta Confirmar

  • Rendimiento de los alias: Aunque los métodos alias son simples wrappers, sería útil medir si hay algún overhead medible comparado con llamar directamente a `read()`/`write()`.
  • Uso en el código: Verificar que todos los lugares que usan `read_byte()`/`write_byte()` ahora funcionan correctamente con el wrapper C++.

Hipótesis y Suposiciones

Se asume que el código Python existente no usa características avanzadas de la MMU Python que no estén disponibles en la versión C++. Si aparecen más incompatibilidades, se añadirán métodos de compatibilidad adicionales según sea necesario.

Próximos Pasos

  • [ ] Ejecutar el emulador con una ROM y verificar que el renderer funciona sin errores
  • [ ] Verificar que el framebuffer Zero-Copy funciona correctamente con numpy
  • [ ] Si aparecen más incompatibilidades de API, añadir métodos de compatibilidad adicionales
  • [ ] Considerar crear una suite de tests específica para validar la compatibilidad del wrapper PyMMU