Izquierda: prototipo presentado aquí; derecha: nuevo prototipo en ensamblador.
Recientemente he terminado de portar todo el código del prototipo de Last Crown Warriors mostrado en este blog a ensamblador. Sentía que el programa original, realizado con una combinación de C y ASM, no garantizaba un rendimiento óptimo, y que no sería la mejor base sobre la que fundamentar el resto del programa: tarde o temprano iba a terminar recurriendo a las virtudes de la programación de bajo nivel, y las herramientas que estaba usando, a pesar de ofrecer la posibilidad de añadir rutinas en ensamblador al programa, no presentaban las mismas ventajas que ofrece un programa realizado íntegramente en lenguaje ensamblador.
Por eso, aprovechando la ocasión de tener dos programas de resultado casi idéntico (uno en ASM, otro en C+ASM) para Game Boy, me he decidido a realizar una sencilla comparativa de rendimiento en ambos.
No es mi objetivo hacer un análisis en profundidad y concienzudo, ni mucho menos, pero sí sacar a la luz cuál es el resultado real que se obtiene cuando se desarrolla haciendo uso de las principales herramientas de las que la escena de Game Boy actualmente dispone.
C+ASM versus ASM
Antes de comenzar, creo conveniente aclarar por qué en este caso no se encuentra representada la opción de sólo C. Sencillamente, la desestimé. El deseo de tener un gran número de enemigos en pantalla con un rendimiento óptimo se contradecía con mi experiencia previa en desarrollos basados únicamente en C y orientados al sistema de marras.
Para empezar, toca concretar qué herramientas se han usado para la elaboración de la ROM en cada uno de los casos: Para el programa de C y ensamblador usé GBDK (Game Boy Development Kit), una versión modificada del SDCC (Small Device C Compiler) orientada a la Game Boy con librerías dedicadas y ejemplos. Decir que lleva sin actualizarse desde mediados de 2002.
En este programa el código en C, si bien no busca la optimización más absoluta, si se encuentra realizado siguiendo las directrices recomendadas por la herramienta. Se delegan además la operaciones matemáticas complejas y las funciones grandes recurrentes o relativamente simples a rutinas en ASM. Concretamente en este lenguaje de bajo nivel se cumplen los siguientes procesos:
- actualización y posprocesado de sprites;
- inteligencia artificial de los enemigos;
- detección de entorno y procesado de hierba;
- multiplicaciones y divisiones con resto;
- generación de números aleatorios;
- actualización gráfica durante el VBLANK.
Cabe destacar que el rendimiento de las rutinas mencionadas en el programa basado en C es menor que el de sus homónimas en el programa completamente en ensamblador. La razón es simple, en bajo nivel cuando queremos acceder a un dato lo hacemos directamente a través de su dirección, en C la memoria se maneja de manera dinámica y por lo tanto no es viable acceder a un dato de esta forma. A menos, claro está, que también decidamos controlar las direcciones de cada una de las variables, perdiendo así una de las ventajas que C nos ofrece. En el caso del prototipo se pasan todos los parámetros en forma de variables a través de una pila, apilando todos los datos de referencia que necesitamos primero para luego desapilarlos en la rutina de ASM antes de gestionarlos. Este proceso adicional perjudica ligeramente a la rapidez de dichas rutinas.
Resultado, hasta cinco enemigos moviéndose simultáneamente en pantalla sin ralentizaciones de ningún tipo. La barra verde a la derecha de la imágen indica la carga del procesador, si el verde claro sobrepasase el alto de la barra significaría que existe una carga de trabajo por frame mayor a la que el procesador puede hacer frente y surgirían ralentizaciones.
Programa en C+ASM.
Y aquí tenemos ese mismo resultado con el programa elaborado enteramente en ASM con RGBDS (Rednex Game Boy Development System), un ensamblador que hoy día sigue recibiendo actualizaciones. En este programa se ha realizado una transición de la lógica original a este lenguaje, priorizando en todo momento la optimización de recursos y procesamiento.
Programa en ASM puro.
Programa en ASM puro, con número de enemigos máximizado.
Así que, ensamblador en Game Boy, ¿es necesario? Creo que depende del proyecto que se quiera desarrollar. Para Last Crown Warriors, un juego que pretende mostrar de manera simultánea el mayor número posible de personajes distintos en movimiento, definitivamente sí.