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.
Corrección de Detección de Tiles y Renderizado
Resumen
Este step corrige la verificación de tiles reales para revisar TODO el rango de VRAM (0x8000-0x97FF) en lugar de solo los primeros 2048 bytes, investiga por qué el tilemap no apunta a los tiles reales que se cargan, y mejora la lógica de renderizado para usar tiles reales cuando están disponibles.
Se implementaron monitores adicionales para rastrear cambios en el tilemap, análisis de correspondencia entre tilemap y tiles reales, verificación del cálculo de direcciones de tiles, y mejora de la detección de tiles vacíos para verificar todo el tile (16 bytes) antes de considerarlo vacío.
Concepto de Hardware
VRAM Completo (0x8000-0x97FF)
VRAM tiene un rango total de 6144 bytes (384 tiles × 16 bytes). El direccionamiento puede ser:
- Unsigned addressing (base 0x8000): Tiles 0-255 en 0x8000-0x8FFF
- Signed addressing (base 0x9000): Tiles -128 a 127 en 0x8800-0x97FF
En signed addressing:
- Tile 0 está en 0x9000
- Tile -1 (0xFF) está en 0x8FF0
- Tile -128 (0x80) está en 0x8800
- Tile 127 (0x7F) está en 0x9FF0
Fuente: Pan Docs - "Tile Data"
Tilemap y Correspondencia con Tiles
El tilemap contiene tile IDs que apuntan a tiles en VRAM. Si el tilemap no se actualiza después de cargar tiles, apunta a tiles vacíos. Los juegos deben actualizar el tilemap para apuntar a los tiles reales cargados. Si el tilemap apunta a tiles vacíos, se renderiza blanco o patrón de prueba.
Fuente: Pan Docs - "Tile Map"
Detección de Tiles Vacíos
Un tile está completamente vacío si todas sus 8 líneas (16 bytes) son 0x0000. Algunos tiles legítimos pueden tener líneas con 0x0000 (transparentes). Solo se debe usar patrón de prueba si TODO el tile está vacío.
Fuente: Pan Docs - "Tile Data"
Implementación
1. Corrección de Verificación de Tiles Reales
Se modificó la verificación en PPU::render_scanline() para revisar TODO VRAM (0x8000-0x97FF = 6144 bytes) en lugar de solo los primeros 2048 bytes. Esto cubre tanto signed como unsigned addressing.
El umbral se ajustó de 100 bytes no-cero a 500 bytes no-cero (aprox. 31 tiles completos) porque ahora revisamos 3x más bytes.
// Verificar TODO VRAM (0x8000-0x97FF = 6144 bytes = 384 tiles)
for (uint16_t i = 0; i < 6144; i++) {
uint8_t byte = mmu_->read(0x8000 + i);
if (byte != 0x00) {
non_zero_bytes++;
}
}
bool has_tiles_now = (non_zero_bytes > 500);
2. Monitor de Cambios en Tilemap
Se mejoró el monitor en MMU::write() para detectar cuando el juego actualiza el tilemap. El monitor loggea los primeros 100 cambios y cuando hay cambios significativos (de 0x00 a un valor no-cero).
if ((addr >= 0x9800 && addr <= 0x9BFF) || (addr >= 0x9C00 && addr <= 0x9FFF)) {
static int tilemap_update_count = 0;
static uint8_t last_tilemap_value = 0xFF;
if (tilemap_update_count < 100 || (value != 0x00 && last_tilemap_value == 0x00)) {
printf("[TILEMAP-UPDATE] PC:0x%04X | Addr:0x%04X | TileID:0x%02X\n",
debug_current_pc, addr, value);
tilemap_update_count++;
}
}
3. Análisis de Correspondencia Tilemap-Tiles
Se agregó un análisis en PPU::render_scanline() que verifica si el tilemap apunta a tiles con datos reales cuando se detectan tiles en VRAM. El análisis verifica los primeros 32 tile IDs del tilemap y cuenta cuántos apuntan a tiles con datos y cuántos apuntan a tiles vacíos.
if (vram_has_tiles && ly_ == 0 && tilemap_tiles_analysis_count < 5 && (frame_counter_ % 60 == 0)) {
int tiles_pointing_to_real_data = 0;
int tiles_pointing_to_empty = 0;
for (int i = 0; i < 32; i++) {
uint8_t tile_id = mmu_->read(tile_map_base + i);
// Calcular dirección del tile según el direccionamiento
// Verificar si el tile tiene datos
if (tile_byte1 != 0x00 || tile_byte2 != 0x00) {
tiles_pointing_to_real_data++;
} else {
tiles_pointing_to_empty++;
}
}
}
4. Verificación de Cálculo de Dirección de Tile
Se agregó una verificación que confirma que el cálculo de dirección de tile es correcto para signed/unsigned addressing. La verificación muestra ejemplos de tile IDs y direcciones calculadas.
if (signed_addressing) {
int8_t signed_id = static_cast(sample_tile_id);
calculated_addr = tile_data_base + ((int8_t)sample_tile_id * 16);
printf("[PPU-TILE-ADDR-VERIFY] TileID: 0x%02X (signed: %d) | Base: 0x%04X | Calculado: 0x%04X\n",
sample_tile_id, signed_id, tile_data_base, calculated_addr);
} else {
calculated_addr = tile_data_base + (sample_tile_id * 16);
printf("[PPU-TILE-ADDR-VERIFY] TileID: 0x%02X (unsigned) | Base: 0x%04X | Calculado: 0x%04X\n",
sample_tile_id, tile_data_base, calculated_addr);
}
5. Mejora de Detección de Tiles Vacíos
Se mejoró la lógica de renderizado para verificar TODO el tile (16 bytes) antes de considerarlo vacío. Esto evita que tiles legítimos con algunas líneas en 0x0000 sean considerados vacíos.
bool tile_is_empty = true;
// Verificar si TODO el tile está vacío (todas las 8 líneas = 16 bytes)
for (uint8_t line_check = 0; line_check < 8; line_check++) {
uint16_t check_addr = tile_addr + (line_check * 2);
uint8_t check_byte1 = mmu_->read(check_addr);
uint8_t check_byte2 = mmu_->read(check_addr + 1);
if (check_byte1 != 0x00 || check_byte2 != 0x00) {
tile_is_empty = false;
break;
}
}
Tests y Verificación
Compilación
El módulo C++ se recompiló exitosamente sin errores (solo warnings menores de formato).
$ python3 setup.py build_ext --inplace
running build_ext
building 'viboy_core' extension
...
copying build/lib.linux-x86_64-cpython-312/viboy_core.cpython-312-x86_64-linux-gnu.so ->
Pruebas con ROMs
Se ejecutaron pruebas con las 3 ROMs (pkmn.gb, tetris.gb, mario.gbc) durante 2.5 minutos cada una. Los logs muestran:
- ✅ Detección de tiles completamente vacíos funcionando correctamente
- ✅ Monitor de cambios en tilemap capturando actualizaciones
- ✅ Verificación de tiles reales revisando TODO VRAM
Validación de Módulo Compilado C++
El módulo compilado se carga correctamente y las funciones C++ se ejecutan sin errores. Los monitores y verificaciones implementadas están activos y generan logs cuando se cumplen las condiciones.
Resultados
Correcciones Implementadas
- ✅ Verificación de tiles reales ahora revisa TODO VRAM (6144 bytes) en lugar de solo 2048 bytes
- ✅ Monitor de cambios en tilemap mejorado para capturar actualizaciones
- ✅ Análisis de correspondencia tilemap-tiles implementado
- ✅ Verificación de cálculo de dirección de tile implementada
- ✅ Detección de tiles vacíos mejorada para verificar todo el tile antes de considerarlo vacío
Hallazgos
- Los juegos escriben en el tilemap (se detectan actualizaciones en PC:0x129F para mario.gbc)
- La detección de tiles vacíos funciona correctamente (se detectan tiles completamente vacíos en 0x8000)
- El código compila y ejecuta sin errores
Próximos Pasos
Si el renderizado funciona correctamente:
- Step 0326: Verificación final de controles y compatibilidad
- Step 0327: Evaluación final del plan estratégico
Si el problema persiste:
- Step 0326: Análisis más profundo del tilemap y solución alternativa
- Investigar si hay problemas en la sincronización o timing