26/08/2021

Pac-Man Emulator Postmortem

Parece que una persona de bien, el Sr. Volcano Bytes, decidió acudir a Cepeceros para alabar ese viejo proyecto y preguntar sobre que magias se esconden tras los bits. Por supuesto, es imposible no sentirse halagado y aprovechando que se cumplen casi 10 años de cuando comencé aquel proyecto, pues nada mejor que aprovechar ese momento para reflexionar en voz alta... además, de que después de mostrar el mini-guión a Chema, nos dimos cuenta de que nos podían dar 2 horas mínimo :P, por lo que vamos a intentar descargar buena parte del contenido por aquí ó no seremos capaz de grabar ese pospodcast en un tiempo razonable :P

Mi relación con emuladores es bien temprana, de hecho ya ha finales de los 80, fue en mi antiguo Amiga 500 donde tuve contacto por primera vez con este tipo de programas; había varios de C64 (bastante cutrecillos, que servían prácticamente para pasar el contenido de discos), uno de ST (no mucho mejor) y otro de Macintosh (ese si era medio decente). Me pareció algo tan loco poder disfrutar de software de otras máquinas; y recuerdo darles una caña tremenda a uno de Spectrum y otro de Apple II, que corrían muy bien en mi A500.


Uno de mis pocos discos originales de Amiga

En la primera mitad de los 90, mientras echaba una mano a Kevin con su emulador de CPC para Amiga, empecé a interesarme por los primeros emuladores de recres y recuerdo bajarme unos cuantos de MS-Dos para analizarlos. Uno de los que más me impresionó fue el System16, el cual emulaba recres clásicas de Sega, entre ellas el Shinobi.

Ya bien metidos en la segunda mitad de los 90, mientras curioseaba en uno de esos ftps temporales que aparecían de la nada y desaparecían inclusive más rápido, me topé con unos documentos donde se iban comentando detalles técnicos y tipos de encriptaciones usadas en sistemas arcades, como el System16 de Sega. Y como el Shinobi de Amiga era terrible, empecé a darle vueltas a sobre como llevar al Amiga una de mis recres favoritas sin pagar el fuerte peaje por emular la recre en un sistema tan débil como el Amiga.


¿Cómo llevar eso al Amiga?

Por lo que comencé a desencriptar las ROMS del Shinobi, para a continuación intentar desensamblarlas, así como extraer todos los recursos gráficos, mapas, sonidos, ... La idea era crear una especie de traductor para que mientras se ejecutaba el código de la ROM iríamos interceptando todas las llamadas de gráficos y sonidos, para así redirigirlas a mis propias rutinas que accederían directamente al hardware del Amiga, permitiendo correr el juego a una velocidad aceptable...

... hasta que en medio del proyecto mi amiga murió :P

Después del consabido año de luto, ó mejor dicho, durante ese año de luto, me volví de lleno al CPC, que había tenido una segunda mitad de los 90 bastante más tranquila, casi jubilado programativamente hablando; y se me ocurrió intentar llevar aquella idea loca del Shinobi al CPC. Por supuesto, la primera máquina con z80 que se me ocurrió fue el Pac-Man.

Aunque ese primer intento no llegó a buen puerto, por la dificultad añadida de tener que desensamblar y comentar la rom de la recre con el monam de CPC (tengo la certeza absoluta de que yo debía estar mal de la cabeza ó soltero para intentar algo así xDDD); aunque como esa era la parte más pesado pues pronto perdí la motivación (ó dejé de estar soltero xDDDD).


Tengo certeza absoluta de que me faltaba un tornillo ó dos

Así que esa vieja idea permaneció en el limbo por casi una década más, hasta que a comienzos de noviembre del 2011, mientras hojeaba algunas de mis cosas viejas, me dí de bruces con el viejo proyecto y mirando por las redes me dí cuenta de que había mucha más información publicada sobre el Pac-Man, de hecho se podía encontrar un desensamblado medio decente de la ROM. Pero lo mejor del todo es que alguién ya había conseguido llevar adelante ese viejo proyecto, ya que Simon Owen había llevado la recre al Sam Coupe. Así que fue un momento de esos de "no hay huevos de convertirlo a CPC" y habría sido muy estúpido no apoyarse en el proyecto de Simon, especialmente porque tenía una licencia que permitía hacer modificaciones y adaptarlo a otros sistemas; y aunque no usase nada al final, habría sido hasta inmoral no mencionar y agradecer su trabajo (lo más divertido es que hace poco el maldito se me ha vuelto a adelantar con otro de esos proyectos locos que siempre están en mi lista de futuribles XDDD).


Un nuevo comienzo...

Por aquel entonces estaba echándole una mano a Richard a finiquitar el R-Type; y le comenté que estaba pensando en ver si sería posible retomar alguno de mis viejos proyectos pendientes... y en un abrir y cerrar de ojos, el maldito ya había convertido los gráficos a mode 1 xDDD, así que no había vuelta atrás.


¡¡¡Ya tenemos gráficos para experimentar!!!

Eso fue en la segunda mitad de noviembre del 2011 y ya a comienzos de diciembre el juego estaba funcionando, aunque lentísimo, ahora venía la tarea más complicada y que no era otra que optimizar aquello para que fuese medianamente jugable. Ese proceso de optimización se produjo durante los primeros meses de 2012 hasta que lo publicamos el 1 de Abril de 2012 (ya sabeis cuanto me gustan esas tontadas, jejeje).


¡¡¡Proyecto publicado!!!

Aunque en cierto modo fue un pequeño éxito, no estaba muy conforme con el resultado final, porque para mi gusto le faltaba un poco de velocidad a pesar del gran esfuerzo de optimización. Pero debido a que el proyecto pareció gustar bastante, y también espoleados por haberlo podido llevar adelante tan rápido, pues comenzamos a discurrir sobre como podíamos aprovechar el esfuerzo para llevar a cabo otros proyectos.

Logicamente se nos abrían dos posibilidades, la primera era hacer una versión para CPC+ la cual nos permitiría resolver el problema de la falta de velocidad y que haría el juego practicamente indistingible de la recre.


¿Recre ó CPC+?

La otra idea, y la que nos parecía más atractiva, era la de convertir otros juegos corriendo en la misma placa: Ms. Pacman y Pengo



¡¡¡Dale caña Maikel!!!

Pero después del primer análisis, el sistema de paginación de memoria del CPC era del todo insuficiente para dar soporte a estas dos recres, al menos si queríamos aprovechar lo que ya teníamos hecho. En un cartucho de CPC+ la conversión habría sido inmediata, pero en aquel entonces eso de hacernos nuestros propios cartuchos de CPC+ no era tan fácil; y en cierto modo, no era mucho más difícil que crearnos nuestro propio sistema de cartuchos para toda la gama de CPC. Por lo que decidimos liarnos la manta a la cabeza y meternos a hacer hardware sin saber muy bien en lo que nos estabamos metiendo xDDDD

Comenzamos por lo básico, que no fue otra cosa que modernizar un proyecto viejo para así familiarizarnos con la forma de crear hardware para CPC e intentar siempre respetar el espíritu de la máquina. Ese primer proyecto fue el minibooster que nos permitió comunicarnos con el CPC a través de BT ó USB, facilitándonos mucho la tarea de pruebas.

Paso a paso y con cada miniproyecto fuimos ganando en confianza y ambición para crear el sistema de cartuchos que deseábamos. Que si una ampliación de ROMs; una de RAM para que los usuarios con 64 KBs pudiesen acceder al software del 6128; el generador de interrupciones programable para traer una de las mejores características del CPC+; idem con los puertos de controles analógicos y pistolas (que nos permitia usar pistolas de Master System facilmente); chips de sonido extras para facilitar el tener música y efectos de sonido de forma simultanea; ...


Si hay que golfear fisicamente, pues se golfea

Si la 32X es un armatoste, asombraros ante nuestro ¡¡¡Kaiju!!!

Y la estrella del proyecto, el slot de cartuchos que gracias a los colegas de Watermelon estaría basado en megadrive, para así poder usar su molde de cartuchos.


Un cofre del tesoro de prototipos del CPC

La culminación del proyecto sería el concurso de juegos de 16 KBs en ROM que hicimos en el cpcwiki en 2013... y aquí tocaría escribir otro artículo incluso mayor, que vamos a dejar para otro día, ya que entre otras cosas, ese año fue cuando di mi salto al otro lado del charco y la vida nunca más fue la misma.

Volviendo al Pac-Man, todas esas aventuras con hardware me distrajeron de mirar posibles alternativas para mejorar el emulador original... hasta que a mediados del 2014, 40crisis publicó un parche que mejoraba el rendimiento parcheando la rom de la recre. En ese instante, no iba a permitir que me hicieran una francesada, así que le dí un arreón; esta vez mirando lo que no había mirado todavía, el própio código de la recre y conseguí optimizar todo un 10% más, lo que eliminó todos esos problemas de velocidad. Esa es la versión 1.1 y el resultado final ya si que me dejó más contento.

Ahora vamos a responder algunas preguntas antes de dar un breve repaso a nivel técnico del proyecto.

¿Por qué es un emulador?

Porque de hecho estamos emulando los sistemas de vídeo, audio y entradas del jugador de la recre original.

¿Cómo funciona realmente?

Pues se basa en la misma idea del traductor original del Shinobi; para ello nos aprovechamos de que usamos la misma cpu que la recre, por lo que parcheamos la ROM original (y el pórque funcionan muchos clones y hacks que corren sobre la placa original de la recre es porque las zonas que parcheamos son comunes a todas, el pueblo no se cortaba un pelo a la hora de piratear recres) para que el código funcione en el CPC. Por ejemplo, el watchdog, las rutinas de protección, las de inicialización, los accesos a puertos de E/S de la recre, ... para que salten a una rutina nuestra que los trate.

Entonces el primer paso es que ese código original corra sin que corrompa la memoria y se autodestruya (por ejemplo, una protección muy típica era intentar escribir encima de donde debería estar la ROM, por si el juego estaba corriendo sobre RAM y así machacarlo).

A partir de ahí empezamos a añadir cosas para que podamos ver, oír e interactuar con ese programa. Por ejemplo, si metemos una moneda, pues hay un código nuestro que marca a la recre que sucedió ese evento.

Pero como aquí no hay multitarea, ni un z80 extra, ¿cuándo se ejecuta ese código nuestro? Bueno, estas primeras recres están muy ligadas a la frecuencia del refresco. Por lo que nuestro código lo hemos colgado al final de la rutina de interrupción del refresco de la recre.

Entonces cada vez que ocurre esa interrupción, nuestro código se lanza y se dedica a pintar sprites, tiles, reproducir sonido, leer las entradas del jugador, ... y pasar a la recre esa nueva información para que el juego siga su curso.

¿Por qué necesita 128 KBs de memoria?

El mapa de memoria es:

Como podéis apreciar, estamos usando la memoria al máximo y tenemos por ejemplo, una copia de los primeros 8 KBs de la recre sin modificar, ya que la rutina que genera números aleatorios usa esa parte de la ROM para ello; y si no es idéntica, entonces los comportamientos de los fantasmas, bonus y demás no serían exactos a los de la recre.

También se ve que hacemos uso de una tabla de 8 KBs para poder convertir los sonidos de la recre a nuestro querido PSG de la forma más rápida posible. Otra cosa interesante es que tuvimos que dividir los tiles de los sprites; y estos últimos viven en la última página de RAM del CPC, y a pesar de eso, tuvimos que optimizarlos para no pasarnos de 16 KBs, porque no teniamos donde meterlos y el sistema de video que habíamos montado dependia de ello.

También tenemos que mencionar que se usan casi todos los modos de paginación de RAM del CPC, incluidos los más exóticos:

PAL y NTSC

Digamos que todas las recres clásicas estaban en NTSC, solo cuando llegaron las primeras recres vectoriales y especialmente al final de los recres cuando aparecieron la Naomi y demás, se empezó a ver monitores que refrescaban a otra frecuencia, normalmente VGA. Claro que hubo recres que usaban otro refresco en la época pero eran casos raros (la serie System24 de Sega con el Hot Rod es uno de esos sistemas que no son NTSC).

Porqué es importante hablar de PAL y NTSC, porque PAL es un 17% más lento que NTSC y en juegos donde la temporización depende de la frecuencia de la señal de vídeo esa diferencia es vital.

Con respecto al soporte de NTSC, pues la verdad es que el CRTC permite poner la imagen en NTSC, y nadie había hecho eso antes, y mi TV por euroconector lo soportaba. Además, de que en la versión 1.0 el juego iba mucho más suave en NTSC porque tiene un framerate fijo de 30 fps en NTSC; mientras que en PAL a pesar ó por culpa de todas las optimizaciones, el framerate fluctuaba entre 50 y 25 fps dependiendo de cuanto estuviese ocurriendo en pantalla. Por eso mismo, lo de ese regusto medio amargo, ya que después de todo el trabajo duro, el juego no iba tan bien como me gustaría Por culpa de esos pequeños acelerones y desacelerones continuos.

Volviendo a cuando me hicieron aquella francesada (y que conste que a 40crisis lo aprecio y nos hemos ayudado mutuamente en muchos proyectos) durante aquel mosqueo/pataleo descubrí que la recre se quedaba en un punto del código esperando tiempo, porque iba más sobrada de lo que originalmente creí. Así que la idea feliz fue desactivar las interrupciones, y cuando el código de la recre llegase a ese punto, pues esperaba al refresco del CPC, ejecutaba el código de la recre y luego nuestro código específico; con eso y otras ideas locas más, conseguí un 10% más de rendimiento, lo cual permitió que el juego en PAL pudiese ir ahora a unos solidos 50 frames por segundo... y ahora en ntsc variaba :P

Y esa es la mayor diferencia con respecto a la recre, la recre va a unos solidos 60 fps, mientras que nosotros vamos a 50 fps. De hecho si pones emuladores, como WinApe, al 120% veréis que ya no existe una diferencia de velocidad con la recre.

Optimizando que es gerundio

Aquí vamos a comentar un poco por encima todas esas optimizaciones que hicieron posible que el juego fuese jugable. Ya que el hardware de la recre del Pacman es considerablemente más potente que el del CPC a nivel gráfico; el z80 de la recre va a 3 MHz, pero logicamente lo que dió más quebraderos de cabeza fue adaptar ese sistema de tiles y sprites que es una forma de aceleración gráfica a las rutinas software para el CPC.

Siempre comparo el proceso de optimización del Pacman con la llegada de Willy Fog/Phineas Fog a Liverpool en el vapor, donde no tenemos más carbón para quemar y solo nos queda comenzar a tirar todo lo que sobra del barco a la caldera. Así que todo lo que sea prescindible, vamos a prescindir de ello. Un ejemplo de eso es porque no se pintan en los laterales las frutas de bonus que has cogido, ya que es algo cosmético.

Porque no es que estemos al límite sino que teóricamente es imposible que podamos pintar la pantalla a la misma velocidad de la recre. La recre solo tiene que reescribir alrededor de 1 KB de datos en cada frame para pintar la pantalla y nosotros tenemos que pintar 16 KBs; por lo que el z80 del CPC precisaría ir a 50 MHz para que aquello fuese posible.

Entonces tenemos multitud de rutinas de pintado:

El juego usa doble buffer para evitar tearing y parpadeos de los sprites, el motivo principal es porque no tenemos ningún control del tiempo ya que nuestro código solo toma el control cuando la rom del pacman termina de procesar el equivalente a 1 frame. Ésto nos produce una complicación extra ya que acabamos de pasar a tener que actualizar 32 KBs de memoria de vídeo en el CPC, osea necesitaríamos un z80 a 100 MHz para ir al ritmo de la recre :P

Si le dais al famoso martillito del RVM, veréis un borde negro de 16 pixeles a cada lado de la pantalla, pero esta hecho de forma proposital, para que la pantalla tenga un ancho de 256 pixeles, mejor dicho 64 bytes, lo cual ayuda a acelerar los cálculos a la hora de descubrir en que dirección de memoria toca pintar algo.

Pero la mayor de las magias a nivel gráfico es la actualización de la pantalla. Como hemos visto es imposible actualizar la pantalla al completo en un tiempo que no nos robe toda la velocidad y diversión; y mucho menos debido al uso del doble buffer.

Entonces la idea feliz fue dividir la actualización de la pantalla en varios frames, en este caso en 5 frames; para ello lo que se hace es analizar los cambios en el tilemap de la recre por columnas, en el primer frame miramos las 6 columnas de más a la izquierda, después las 5 siguientes, 6, 5 y 6. Entonces cada vez que un tile ha cambiado lo repintamos; y si no cambió, pues pasamos al próximo, porque la mejor optimización es no tener que pintar.

Por lo que aunque internamente todo va al frame, visualmente tenemos un pequeño retraso que puede ser de hasta 5 frames. Como estamos usando doble buffer pues multiplicamos eso por dos. Y eso explica los glitches que comentaba el invitado, especialmente visibles en los intermedios, por eso de que existen muchas más diferencias con respecto a una pantalla de juego, ya que el laberinto desaparece por completo. También se puede ver como en los puntos a veces hay algún glitch porque los dos buffers no están perfectamente sincronizados, en el sentido de que un buffer puede haber actualizado alguna de las columnas de los puntos y el otro no.

Lo importante es que no es perfecto pero da el pego durante el juego, porque en realidad lo que suele cambiar es los puntos y el coco que Pacman se acabe de comer. Osea usamos un método ingenioso para ahorrarnos 97 MHz XDDD

En emuladores da mucho más el cante, como el tramado de los sprites y demás. Pero lo importante es que todos estos trucos ó compromisos empleados dan el pego en la máquina real en su monitor de tubo. De hecho todas las pruebas fueron hechas en mi CPC enchufado por Euroconector a una TV Samsung de 14" para tener certeza de que los cambios no afectaban a la jugabilidad.

Extras y Huevos de pascua

Además de ser el primer juego de CPC con soporte de NTSC, también damos soporte a joysticks de 3 botones y es que estaréis cansados de escucharme decir cuanto adoro controles alternativos y fabricarme mis propios joysticks. Por lo que el juego es totalmente controlable usando un joystick con 3 disparos, menú de configuración incluido. Vamos que solo necesitáis tocar el teclado para cargar el juego ó introducir los trucos :P


Er Monstruo usado para las pruebas

El error de que no tienes suficiente memoria es un guiño a los gurus del Amiga.


Ouroboros ó el mito del eterno retorno

Cuando Geco me pidió permiso y ayuda para hacer la conversión a Enterprise, decidimos añadir algunas de las características de la versión no publicada para CPC+, como el raster para cambiar el color de los puntos a blanco.

¿Cuál fue el legado?

Esta parte va a quedar pendiente hasta que se cumplan los 10 años, pero algunas notas sobre lo que irá aquí:

Efímero -> Disfruta del desarrollo

Opensource

Rutina de impresión de tiles


-*-