Uno de los programadores mas prol铆ficos y que mas jugo le est谩n sacando al C64 a un ritmo vertiginoso y cada vez con mas exquisitez es nuestro invitado Dr MortalWombat, conocido por su amplio cat谩logo videojueguil y seguramente mas por el compilador de C para nuestro sistema, el Oscar64, que no para de optimizar, actualizar y que cada vez mas gente usa para sus propios proyectos. Hablar de DMW es hacerlo de un programador nato, que desde muy joven tuvo claro lo que le gustaba y su historia, sus inicios y como muchas veces nuestra profesi贸n va ligada a nuestros hobbys.
–Os dejamos con el propio DrMortalWombat:
–Mis primeros recuerdos de programaci贸n son escribiendo ensamblador en tarjetas perforadas para un sistema IBM /360. Nada complejo, deb铆a de estar en la escuela primaria por aquel entonces, as铆 que era el equivalente a BASIC de una l铆nea, pero con una impresora de cinta de acero como salida. Mi padre era el administrador de un centro inform谩tico local, as铆 que tuve acceso a 茅l.
En el 82 consegu铆 mi propio VIC20 y, como era de esperar, qued茅 asombrado por los gr谩ficos y el sonido, pero completamente decepcionado por el lento BASIC. As铆 que, naturalmente, escrib铆 mi propio ensamblador en BASIC para aprovechar la «potencia» del lenguaje de m谩quina del 6502. Esta peque帽a CPU me impresion贸 m谩s que el gran mainframe. La cantidad de potencia de c谩lculo en este peque帽o chip era y es simplemente asombrosa; Vend铆 varios juegos peque帽os a revistas de inform谩tica y utilic茅 el dinero para actualizarlo a un C128 (que todav铆a tengo y utilizo) a finales del 85.
Por aquel entonces, mi cerebro funcionaba de forma nativa con el ensamblador 6502 y no con mi lenguaje natural, as铆 que siempre me inquietaba ver c贸mo mis amigos ten铆an dificultades con el ensamblador, pero no ten铆an grandes problemas con BASIC. As铆 que empec茅 a escribir compiladores de BASIC cada vez m谩s potentes. Tambi茅n hice algunos peque帽os trabajos en ensamblador x86 para la tienda de mi padre en aquella 茅poca, y esto inici贸 un odio eterno hacia todo lo que tuviera una herencia 8080.
Durante mi 茅poca en el ej茅rcito, a partir del 88, conoc铆 Turbo Pascal y me enamor茅 inmediatamente de 茅l. En mi primer semestre universitario aprendimos Modula2 y tuvimos el compilador MacMETH en un Mac. Por aquel entonces ten铆a un Amiga, que programaba en ensamblador de 68K. Me encantaba el lenguaje Modula2 y la velocidad del compilador, pero el c贸digo compilado no era lo suficientemente bueno para m铆 - as铆 que us茅 este compilador para arrancar mi propio compilador Modula2 e IDE integrado - para el Amiga. Esto lo convert铆 en un producto comercial.
Entr茅 en contacto con GVP (uno de los mayores fabricantes estadounidenses de perif茅ricos para Amiga) y empec茅 a trabajar para ellos durante mis a帽os universitarios. Muchos antiguos ingenieros de Commodore trabajaban all铆, as铆 que tuve el placer de conocer y trabajar codo con codo con algunos de los tipos que desarrollaron el hardware que todos amamos.
En el 95, con el fin de la era Amiga, algunos de mis amigos y algunas de las personas principales de GVP establecieron nuevas empresas que ahora hacen productos de v铆deo digital para el PC. Aqu铆 es donde tuve que abandonar dos de mis plataformas amadas 68k y Modula2 y trabajar en el lado oscuro de x86 y C++ - y esto no ha cambiado desde entonces.
Obtuve mi doctorado en inform谩tica en 2000 y trabajo como aut贸nomo desde 2005. Actualmente me dedico sobre todo a la ingenier铆a de rendimiento y al c贸digo DSP, pero he construido sistemas de entretenimiento de consumo integrados, sistemas de IA, motores de juegos de ordenador, plataformas de servidores, compiladores, software de an谩lisis de datos y un largo etc茅tera.
Durante la pandemia empec茅 a limpiar el s贸tano y encontr茅 mi viejo C128 de nuevo... bueno y el resto es historia.
Constru铆 los dos primeros juegos nuevos («Plekthora» y «Gates of the Ancient») en ensamblador con el IDE C64Studio, pero decid铆 utilizar algo m谩s potente para el siguiente juego («Shallow Domains»).
Los compiladores existentes parec铆an problem谩ticos, KickC no era realmente C y el c贸digo generado por CC65 no estaba a la altura del rendimiento y tama帽o que necesitar铆a para mi juego planeado. As铆 que decid铆 construir mi propio compilador para el 6502. Estuve dudando entre Modula2 y C durante un tiempo, pero luego me decid铆 por C porque era el lenguaje de m谩s bajo nivel.
![]() |
Gates of the Ancient |
Rebusqu茅 en viejos proyectos y encontr茅 dos que pod铆an servirme de base para el compilador: un analizador de Javascript y el backend x64 de un compilador en el que hab铆a trabajado hace unos 15 a帽os.
En ese momento yo estaba bajo la suposici贸n que el 6502 no ser铆a un buen objetivo para cualquier lenguaje de nivel superior, debido a la falta de una pila de valores suficientes y la falta de instrucciones de 16 bits. La idea era tener dos generadores de c贸digo, uno generando un c贸digo byte que ser铆a interpretado para las partes no cr铆ticas en tiempo, para ahorrar tama帽o de c贸digo y un generador nativo para las zonas calientes.
El proyecto se inici贸 el 21 de agosto de 2021 y los primeros programas compilados en C64 comenzaron a ejecutarse el 29 de agosto. Con el compilador y el interprete de c贸digo byte funcionando, comenc茅 con el generador de c贸digo nativo el 7 de septiembre y alcanc茅 el mismo nivel funcional el 11 de septiembre. Al principio, la ventaja en tama帽o de c贸digo del c贸digo byte era bastante significativa, pero cuanto m谩s tiempo dedicaba a mejorar el optimizador de c贸digo nativo m谩s se acercaban los dos - y finalmente el generador de c贸digo nativo super贸 al de c贸digo byte.
As铆 que, por el momento, el generador de c贸digo byte s贸lo se utiliza con fines de validaci贸n y ya no tiene ninguna aplicaci贸n en el mundo real.
Resulta que el 6502 es un gran objetivo para un compilador de C, si el optimizador y el generador de c贸digo est谩n dise帽ados de principio a fin para trabajar con sus puntos fuertes y no con sus debilidades. Las tres mayores mejoras en la calidad del c贸digo vinieron de:
- El an谩lisis est谩tico del gr谩fico de llamadas se utiliza para eliminar la pila de llamadas siempre que sea posible y utilizar la p谩gina cero o el direccionamiento absoluto para las variables locales y los par谩metros. S贸lo los punteros de funci贸n y la recursividad pueden acabar utilizando la pila de valores.
- El an谩lisis est谩tico del rango de enteros permite simplificar muchas operaciones de 16 bits a operaciones de 8 bits. El compilador puede simplemente probar que los valores no superan el rango m谩s peque帽o.
- Conversi贸n de direccionamiento indirecto a direccionamiento indexado cuando la aritm茅tica de punteros o la indexaci贸n de matrices cabe en un 煤nico registro de 铆ndice.
![]() |
Portal Buster |
Con cada nuevo juego que escribo, el compilador sigue mejorando. Dedico alrededor del 25% de mi tiempo de desarrollo para cada juego a conseguir que el compilador genere c贸digo m谩s r谩pido o m谩s peque帽o.
Intento evitar cualquier tipo de ensamblador en mis juegos (aunque el compilador soporta una integraci贸n fluida de ensamblador en l铆nea y c贸digo C). Siempre que siento la necesidad de a帽adir una secci贸n de ensamblador, mejoro el compilador para no tener que a帽adirla - y esta pol铆tica ha funcionado muy bien hasta ahora.
Oscar64 es un compilador y enlazador combinado. Compila, optimiza, enlaza y genera un archivo ejecutable (ya sea un .prg o un cartucho .crt) con una simple invocaci贸n, sin necesidad de pasos adicionales de compilaci贸n. As铆 que supongamos que tenemos un archivo fuente en C «hola.c» llamando al compilador con «oscar64 hola.c» generar谩 un «hola.prg» que puede ser iniciado con, por ejemplo, el Vice. Esta compilaci贸n de todo el programa no s贸lo es conveniente al eliminar la necesidad de un makefile, sino que tambi茅n permite al compilador invocar optimizaciones m谩s complejas. Esta es una de las ventajas de la compilaci贸n cruzada en un ordenador que es 贸rdenes de magnitud m谩s potente en velocidad y tama帽o de memoria que el sistema de destino.
Programar juegos para un microordenador como el C64 implica frecuentes accesos directos a la memoria o a los registros IO. En BASIC esto se har铆a con PEEK o POKE, en ensamblador con direccionamiento absoluto. En C la forma natural es utilizar punteros:
static char * const Screen = (char *)0x400; for(char i=0; i<40; i++) Screen[i] = 81;
Este bucle llenar谩 la primera l铆nea de memoria de pantalla con c铆rculos.
Para los registros IO es m谩s f谩cil usar las estructuras predefinidas en la librer铆a como por ejemplo:
#include <c64/vic.h> vic.color_back = 2; vic.color_border = 3;
Frecuentemente hay tres formas de acceder a los componentes de hardware con Oscar64, se puede meter directamente con un puntero, se pueden utilizar los registros definidos en los archivos de cabecera o utilizar funciones de nivel superior definidas en esos archivos de cabecera, para por ejemplo la manipulaci贸n de sprites:
void vic_sprxy(byte s, int x, int y);
Existen m茅todos de biblioteca similares para leer la entrada del usuario desde el joystick, el teclado, los paddles o el rat贸n.
La siguiente cuesti贸n importante es c贸mo introducir recursos, como fuentes, gr谩ficos o sprites en el programa. Oscar64 admite el comando de preprocesador #embed, que traduce los archivos binarios a n煤meros separados por comas, que pueden utilizarse f谩cilmente como inicializadores literales constantes:
const char MilitaryFont[] = { #embed "../Resources/militaryfont.bin" }
Oscar64 va incluso m谩s all谩 proporcionando compresi贸n y analizador sint谩ctico (parsers) para recursos comunes de C64 como archivos Charpad o Spritepad.
static const char BeltChars[] = { #embed ctm_chars lzo "belt.ctm" };
Otro elemento frecuente en la programaci贸n de juegos de C64 son las interrupciones del barrido de pantalla (raster). En Oscar64 se puede declarar una funci贸n como «interrupt», lo que asegurar谩 que guarde todas las localizaciones de p谩gina cero que utilice para el proceso. Un concepto de nivel superior se implementa en la biblioteca rasterirq, que proporciona una especie de copper. La librer铆a hace la clasificaci贸n y el manejo de las interrupciones y el usuario de la librer铆a simplemente tiene que especificar las l铆neas raster y los registros IO a cambiar. Esta librer铆a es tambi茅n la base de la librer铆a sprite multiplexer.
El 煤ltimo tema que quiero tocar aqu铆 es la biblioteca de ejemplos/tutoriales espec铆ficos de juegos en github: https://github.com/drmortalwombat/OscarTutorials
Adem谩s de los archivos .prg o .crt Oscar64 genera otros archivos durante la compilaci贸n que ayudan con la depuraci贸n y la creaci贸n de perfiles. El archivo .map proporciona un desglose del tama帽o y ubicaci贸n de todas las funciones y variables globales para obtener una visi贸n general del uso de memoria. Un listado m谩s detallado, mostrando el tama帽o del c贸digo de cada l铆nea fuente se genera como un archivo .csz con la opci贸n -gp. Este archivo asigna a cada l铆nea de c贸digo fuente de su programa una direcci贸n de memoria y un tama帽o en bytes.
A la inversa, el archivo .asm asigna las direcciones de memoria al c贸digo fuente e incluye referencias al n煤mero de l铆nea si se genera con las opciones -g o -gp. Hacer uso de este archivo requiere alg煤n conocimiento del 6502 para entender qu茅 y por qu茅 el compilador gener贸 varias secuencias de c贸digo.
Cuando se utiliza Vice para emulaci贸n y depuraci贸n, el archivo .lbl ser谩 muy 煤til, ya que proporciona s铆mbolos para el programa y permite as铆 cierto nivel de depuraci贸n simb贸lica. Puede cargarse en Vice con el argumento de l铆nea de comandos -moncommands.
El compilador intenta generar un c贸digo 贸ptimo, pero est谩 limitado por las reglas del lenguaje C, el 6502 y el c贸digo fuente de tu juego. Si crees que el c贸digo generado no est谩 a la altura, hay varias formas de mejorarlo. El primer paso es comprobar los niveles del optimizador. El nivel por defecto es O1 que ya hace muchas optimizaciones locales, pero est谩 limitado en la cantidad de intercalado de c贸digo ("inlining") autom谩tico que realiza. El nivel principal del optimizador O2 intercala el c贸digo ("inline") con la mayor铆a de las funciones que parecen ser beneficiosas en tama帽o y velocidad. Tambi茅n realiza muchas optimizaciones entre procedimientos. El modo m谩s agresivo O3 desenrolla muchos bucles y tambi茅n intercala el c贸digo ("inlines") de funciones, aunque el tama帽o del c贸digo aumente.
Se puede conseguir a煤n m谩s ayudando al compilador. Elegir el tipo de dato correcto ayuda mucho - si un valor cabe en un byte, usa un char en lugar de un int. El compilador hace un an谩lisis est谩tico del rango de valores para predecir el rango potencial de valores de cada expresi贸n entera, pero no puede saberlo cuando carga un valor de la memoria o lo obtiene como argumento de una funci贸n. La sentencia __assume puede ayudar al compilador a conocer el rango potencial de un valor, por ejemplo para coordenadas de pantalla:
static const char BeltChars[] = { #embed ctm_chars lzo "belt.ctm" };
Otro uso potencial de __assume es marcar c贸digo inalcanzable con __assume(false) para evitar que se genere c贸digo para 茅l.
Otra sugerencia de optimizaci贸n controlada por el programador es el desenrollado de bucles. Esto puede ser controlado con un #pragma para desenrollar completamente (tambi茅n conocido como speedcode), desenrollar en trozos de n 贸 desenrollar de manera que la variable de 铆ndice se convierta en un solo byte y por lo tanto quepa en el registro x o y.
El 煤ltimo tema que quiero tratar aqu铆 es la disposici贸n de la memoria. La disposici贸n com煤n de un array de structs coloca un struct completo tras otro en la memoria. Esto tiene dos desventajas cuando se accede a elementos individuales del array, primero calcular la direcci贸n requiere una multiplicaci贸n y segundo acceder necesita direccionamiento indirecto y aritm茅tica de punteros. Por otro lado, una estructura de matrices cortas s贸lo necesitar铆a un direccionamiento indexado absoluto. Oscar64 soporta la traducci贸n f谩cil y transparente de un array de structs como un struct de arrays con el calificador de almacenamiento __striped.
–Para finalizar y a modo de despedida, le preguntamos a DrMortalwombat las razones por las que usar Oscar64. Su respuesta fue:
–Entonces, ¿por qu茅 utilizar C para escribir juegos para el C64?
- Si es nuevo en el C64 pero un veterano en C tienes una entrada menos dolorosa
- Si es nuevo en el C64 y nuevo en C esta es la entrada ideal a uno de los principales ancestros de la mayor铆a de los lenguajes modernos
- Si es un veterano en el C64 y un gran hacker del ensamblador 6502, puede ahorrar mucho tiempo de desarrollo utilizando un lenguaje de m谩s alto nivel
- Si es un desarrollador competente de C64 pero un desastre con el ensamblador 6502 puede dejar que el compilador haga la parte complicada.
–¡Muchas gracias DrMortalwombat por responder a nuestras preguntas!
Enlaces:
- Pod茅is ir al Itch.io de DMW en ESTE enlace
- Pod茅is visitar su Ghitub en ESTE enlace
- Pod茅is visitar nuestro TYOLJ dedicado a 茅l en ESTE enlace
- English version: Oscar64, with DrMortalWombat [EN]
6 Comentarios
¡¡Lectura imprescindible!!!
ResponderEliminarArt铆culo muy interesante. Enhorabuena!
ResponderEliminarFelicidades por el articulazo!
ResponderEliminarQue gran art铆culo. Enhorabuena! A ver si promueve el uso de esta excelente herramienta de DMW.
ResponderEliminar¡Excelente entrevista Bieno y entrevistado! Da gusto leer estas historias de los genios que siguen creando juegos para nuestro querido C64 y en el caso de 茅l aportando a la comunidad con el fabuloso compiladore Oscar 64.馃憣馃暪️馃懢
ResponderEliminarSuper interesante Bieno, felicidades. Increible como nuestro C64 nos sigue sorprendiendo.
ResponderEliminar