Guide Retrocomputing

CrossDev64: Cross-development assembly per C64 su Linux

“Do you pine for the nice days of minix-1.1, when
men were men and wrote their own device drivers?”
Linus Torvalds in comp.os.minix
5 ottobre 1991, 11:53am

di Cercamon

Avvertenze per l’uso.
Attenzione! Prima di cominciare a leggere l’articolo che segue mi corre l’obbligo di informarvi che alcuni di voi potrebbero precipitare in un vortice di ricordi nostalgici che spesso porta a stati mentali di profonda ansia e persino ad una vera e propria sindrome molto frequente fra gli over 35 di tutto il mondo: il retro-computing! Forme estreme di questa malattia portano all’allontanamento parziale o totale dall’affetto dei propri cari, completa indifferenza nei confronti del mondo reale, totale impermeabilità ad ogni forma di occupazione, lavoro e impegno in altre attività. Siete avvisati. Procedete solo a vostro rischio e pericolo. L’autore declina ogni responsabilità per eventuali danni o disagi derivanti direttamente o indirettamente dal contenuto che segue.

In questo articolo cercherò di portare alla vostra attenzione uno degli aspetti del retrocomputing che, per certi versi, rappresenta uno di quelli meno comprensibili ad una prima occhiata: la programmazione in assembly per Commodore 64 attraverso il cosiddetto cross-development, un metodo di sviluppo che consiste nel programmare in assembly, o in qualsiasi altro linguaggio, su una piattaforma diversa da quella “target”. Ciò comporta anche compilare il codice scritto sulla piattaforma di sviluppo con strumenti e tool adatti ed efficaci e infine ottenere il programma eseguibile completo, pronto ad essere trasferito sulla macchina target per l’esecuzione vera e propria. Nel caso che trattiamo, la piattaforma di sviluppo è il nostro amato Linux (userò una distribuzione Ubuntu) mentre quella target, come accennato, è il buon vecchio C64, praticamente senza modifiche, emulato per l’occasione utilizzando VICE, un potente emulatore di tutti i modelli di computer Commodore a 8 bit. Questo significa che per cominciare a lavorare non avrete bisogno di un vero C64 in chip, plastica e silicio (il breadbin, come è soprannominato), ma solo di un PC basato su Ubuntu Linux, un po’ di software, per lo più open source, e, ingrediente fondamentale, un po’ di nostalgia per i vecchi tempi! Gli stessi risultati si possono ottenere anche allestendo un ambiente di cross-development su altre piattaforme (come Windows e Mac OS X), con altri emulatori e differenti strumenti di programmazione. Persino il metodo per fare cross-development qui illustrato può essere variato sulla stessa piattaforma in base agli strumenti (editor, cross-compiler, emulatore C64) che decidete di usare. E la scelta sulla Rete è davvero ricchissima. Googlare per credere.

Ricapitolando, per programmare in assembly su PC Linux per il C64 senza avere un C64, lavorando su una qualsiasi piattaforma o sistema operativo moderni, avremo bisogno di:

  • un emulatore per il C64 (per far girare i nostri esempi)
  • un compilatore (ed eventualmente un linker) per il codice sorgente
  • un editor di testo (magari con qualche funzione macro per simulare un piccolo IDE)

Allora andiamo con ordine e costruiamo il nostro ambiente di lavoro.

Emulare con VICE

Su Linux il miglior emulatore di sistemi C64 è senza dubbio VICE, acronimo di VersatIle Commodore Emulator. Questo software è in realtà in grado di emulare tutti i computer a 8 bit della Commodore (a partire da tutti i modelli PET, compreso il CBM-II, passando per il VIC-20, C64, C16, Plus/4 ed il C128). La versione 3.5, l’ultima uscita al momento in cui scrivo, è molto accurata e potente ed è rilasciata con licenza GNU GPL. Fino a poco tempo fa, nel pacchetto di distribuzione erano incluse anche le ROM dei vari modelli emulati. Oggi non è più così per problemi legati al copyright delle stesse ROM, attualmente di proprietà della società olandese Tulip Computers) ed occorre scaricarle a parte. Per l’installazione dell’emulator engine su Ubuntu non c’è nulla di più semplice. Apriamo un terminale e digitiamo:

cercamon@linuxbox:~$ sudo apt-get install vice

Quando vi viene chiesto, digitate la password dell’utente che state usando per avere i diritti necessari a installare il pacchetto sul sistema. Scarichiamo poi il package contenente le ROM dalla Rete con:

cercamon@linuxbox:~$ cd Scaricati/
cercamon@linuxbox:~/Scaricati$ wget https://www.retromagazine.net/download/crossdev64/vice-1.5-roms.tar.gz

Ora estraiamo nella cartella “Scaricati” il contenuto del pacchetto vice-1.5-roms.tar.gz.

cercamon@linuxbox:~/Scaricati# tar zxvf vice-1.5-roms.tar.gz

A questo punto avremo la cartella vice-1.5-roms all’interno della cartella Scaricati. Ora è necessario copiare i file che rappresentano le ROM dei diversi modelli di computer Commodore nelle cartelle dell’emulatore in modo che quest’ultimo le riconosca quando ne ha bisogno. Già che ci siamo montiamo tutte le ROM, non soltanto quella per il C64, anche se noi più avanti useremo solo quella.

cercamon@linuxbox:~/Scaricati# sudo -s
cercamon@linuxbox:~/Scaricati# cd vice-1.5-roms/data/
cercamon@linuxbox:~/Scaricati/vice-1.5-roms/data# cp -r C64 /usr/lib/vice
cercamon@linuxbox:~/Scaricati/vice-1.5-roms/data# cp -r C128 /usr/lib/vice
cercamon@linuxbox:~/Scaricati/vice-1.5-roms/data# cp -r CBM-II /usr/lib/vice
cercamon@linuxbox:~/Scaricati/vice-1.5-roms/data# cp -r DRIVES /usr/lib/vice
cercamon@linuxbox:~/Scaricati/vice-1.5-roms/data# cp -r PET /usr/lib/vice
cercamon@linuxbox:~/Scaricati/vice-1.5-roms/data# cp -r VIC20 /usr/lib/vice

Naturalmente i comandi di copia si possono condensare in un unico comando, a voi la scelta. La copia delle ROM termina la nostra installazione di VICE. Dovreste trovare il launcher dell’applicazione nel menù Applicazioni → Altro → Commodore 64. L’emulatore può essere lanciato anche da terminale semplicemente con il comando x64, ma noi eviteremo anche questo perché utilizzeremo una funzione macro del nostro editor di testo/codice sia per compilare i nostri programmi in assembly sia per lanciarne automaticamente l’esecuzione all’interno dell’emulatore.

Cross-compilare con 64Tass

Ci sono molti compilatori, o sarebbe meglio dire cross-compiler, di codice assembly 6502/6510 per i diversi e più diffusi sistemi operativi. Per generare i nostri programmi eseguibili sul C64 a partire da una piattaforma Linux, la nostra scelta è caduta su 64Tass per la semplicità d’uso abbinata ad una buona sintassi e alla disponibilità di costrutti e macro che aiutano la produttività e la riusabilità del codice. Molto in voga fra i coder attivi nella “scena” attuale del C64 sono i cross-compiler DASM e KickAssembler, che offrono, soprattutto il secondo, una sintassi molto evoluta ed una serie di utility che nulla hanno da invidiare ai compilatori di linguaggi “classici” come C/C++ o Java.

Nato come tool scritto da un programmatore ad uso di programmatori, 64Tass ha nel tempo maturato una sua evoluzione ed oggi supporta anche il processore 65816 (un replacement del 6510 a 4 Mhz con opcode specifici), la CPU64 (un 6510 “pompato” a 20MHz, set esteso di istruzioni per pilotare fino a 16 MB di RAM), il C64DTV e i cosiddetti “illegal opcodes”, cioè i codici mnemonici estesi del 6502/6510, talvolta usati nei demo per ottenere risultati grafici e prestazioni particolari. 64Tass supporta anche l’ottimizzazione del codice prodotto, la compilazione multi-pass ed altre caratteristiche, sempre aggiunte negli anni dai vari programmatori che si sono alternati nel suo sviluppo. Inoltre è compatibile con la sintassi del ben noto Turbo Assembler (il miglior assembler che gira direttamente sul C64) e basta aggiungere un CR+LF alla fine di ogni linea per portare il codice sorgente scritto su una macchina Commodore e compilarlo con 64Tass.

L’installazione è molto semplice. Cominciamo con lo scaricare il pacchetto software:

cercamon@linuxbox:~/Scaricati# wget https://www.retromagazine.net/download/crossdev64/64tass_v1.46.tar.bz2

Per compilare basta eseguire i seguenti comandi:

cercamon@linuxbox:~/Scaricati# tar xjvf 64tass_v1.46.tar.bz2
cercamon@linuxbox:~/Scaricati# cd 64tass-1.46/
cercamon@linuxbox:~/Scaricati/64tass-1.46# make

Ora abbiamo il nostro cross-compiler pronto all’azione. Il file eseguibile prodotto dalla compilazione è 64tass. Per semplicità e comodità nel suo futuro utilizzo, lo copiamo in una delle directory incluse nel percorso $PATH della nostra installazione Ubuntu.

cercamon@linuxbox:~/Scaricati/64tass-1.46# chmod a+x 64tass
cercamon@linuxbox:~/Scaricati/64tass-1.46# sudo cp 64tass /usr/local/sbin/

Adesso siamo pronti a scrivere codice in assembly per il nostro amato C64, a compilarlo ed ottenere i programmi eseguibili per l’emulatore. Tutto senza mai togliere le mani dalla tastiera della nostra Linux box. Niente male, no? Sì, tutto molto bello, ma noi siamo dei veri geek e anche programmatori di un certo spessore… E soprattutto siamo molto pigri! Dovremmo forse scrivere codice assembly con un semplice editor di testo (come sublime text, kate, gedit, leafpad, scribes) e poi compilare “a mano”, debuggare, correggere il codice, ricompilare, verificare, testare il programma lanciando l’emulatore, ecc.? Insomma, dovremmo forse cacciarci nel loop pressoché infinito “edit-compile-execute”, con il solo aiuto fornito dall’history dei comandi immessi in un terminale bash o forse da un makefile (sì, con 64tass si possono usare i makefile e non è cosa da poco)? Non sia mai! Noi costruiremo il nostro ambiente di sviluppo!

“Codare” con Geany

Per scrivere codice assembly in maniera comoda e per costruire una sorta di ambiente di sviluppo di tipo IDE, configuriamo Geany, un editor molto conosciuto sulla piattaforma Linux. E’ davvero leggero, veloce e consente di usare macro, funzioni ed estensioni per semplificare il processo di scrittura – compilazione – esecuzione, tanto caro ai programmatori assembly e non. Ci aiuta anche con l’evidenziazione della sintassi e con il controllo di ogni parte del nostro codice, personalizzando al meglio colori e font di caratteri.
Utilizzare Geany come editor di codice è piuttosto semplice. Ma noi lo useremo anche per effettuare la compilazione e l’esecuzione dei nostri programmi all’interno dell’emulatore in maniera del tutto automatica. Ciò renderà molto rapido il processo di controllo e test delle applicazioni scritte in assembly, il che riveste una grande importanza per aumentare la nostra produttività. Quando si programma in assembly le comodità e i tool di ausilio non sono mai troppi e potremo concentrarci meglio sul codice e sui risultati delle nostre fatiche.
Se non lo avete già nella vostra installazione Ubuntu, procedete con l’installazione di Geany.

cercamon@linuxbox:~# sudo apt-get install geany

Per i nostri sorgenti assembly useremo l’estensione .asm. Per sfruttare l’evidenziazione della sintassi propria dei codici operativi del 6502/6510 installiamo il file specifico di definizione della sintassi e delle parole chiave per i file .asm.

cercamon@linuxbox:~/Scaricati# wget https://www.retromagazine.net/download/crossdev64/filetypes.asm

cercamon@linuxbox:~/Scaricati# wget https://www.retromagazine.net/download/crossdev64/filetypes.common

Questi due file vanno copiati nella directory di configurazione di Geany.

cercamon@linuxbox:~/Scaricati# cp filetypes.asm filetypes.common ~/.config/geany/filedefs/

La scelta dei colori e del font è del tutto soggettiva, ma sappiate che i coder più nostalgici hanno ricreato in Geany la stessa atmosfera delle schermate del C64 con tanto di colori per sfondo, bordi, testo e font di caratteri TrueType “originale” (se anche voi non potete farne a meno: # wget https://www.retromagazine.net/download/crossdev64/CBM-64.TTF).
Adesso che abbiamo tutti i pezzi al loro posto (cross-compiler 64tass, emulatore VICE x64, editor IDE geany), quello che dobbiamo fare è “collegare” questi tre strumenti in modo che costituiscano la catena di compilazione ed esecuzione dei nostri programmi in assembly per il C64. E per fare questo vi basta lanciare geany e dal menu “Generate” selezionare “Set Build Commands”. Nella prima riga della finestra che compare al centro dello schermo, premete sul pulsante dell’etichetta e cambiatela in “Compile & Execute”. Nella casella di testo accanto inserite il comando:

64tass “%f” -o “%e.prg” | x64 “%e.prg”

e confermate la finestra con “OK”. La macro appena inserita è proprio quello che ci occorre per compilare il nostro codice sorgente assembly ed ottenere nella stessa directory il file eseguibile per C64 con estensione .prg (di default per il sistema operativo del Commodore 64). L’eseguibile .prg viene poi lanciato da linea di comando direttamente all’interno dell’emulatore VICE x64. Il risultato di tutto questo è che con un semplice comando da menu o con la pressione di un tasto (associando per esempio la macro ad un tasto funzione) il programma per C64 su cui abbiamo lavorato viene eseguito nell’emulatore, consentendoci un rapido test e tutti i controlli necessari per un eventuale debug. È davvero utile: possiamo compilare ed eseguire in VICE il codice sorgente in meno di 3 secondi e se qualcosa non va possiamo chiudere VICE con Alt+Q o Alt+F4 e tornare velocemente a Geany per correggere o proseguire con lo sviluppo.
Adesso siamo davvero pronti per cominciare a scrivere il nostro primo programma assembly per C64.

Hello Linuxare!

Potevamo sfuggire alla dura legge che impone come primo programma da compilare per qualsiasi linguaggio che sia stato concepito da mente umana il famigerato “Hello World!”? Certo che no! Ma almeno usiamo “l’esempio degli esempi” per imparare (o ripassare) un po’ di sintassi Turbo Assembler (per noi 64Tass). Ecco qua un semplice programmino per stampare sullo schermo vuoto una stringa di caratteri.

Filename: hello_linuxare.asm

;--- 
;--- header: costruisce la riga BASIC con il comando SYS per lanciare il programma
;--- in modo automatico all'interno dell'emulatore VICE x64

			* = $0801				; locazione di memoria 2049
									; scriviamo il comando SYS del BASIC
			.word ss,2005			; seguito dal comando RUN
			.null $9e,^2064			; riga con il comando SYS 2064
ss			.word 0
;----------------------------------------------------------------------------------

			* = $0810					; il programma inizia alla locazione $0810 = 2064

			ldy #$00					; registro Y = 0, lo usiamo come contatore
print		lda mystr,y					; carichiamo un carattere dalla sequenza “mystr” nel registro A
			jsr $ffd2					; lo stampiamo sul video con una routine standard della ROM
			iny							; incrementiamo Y – prossimo carattere
			cpy #numch					; confronta Y con il numero dei caratteri di “mystr”
			bne print					; se Y non è uguale all'ultimo carattere torna a stampare
			rts							; altrimenti esci dal programma

mystr		.byte 147					; codice 147 = $93 – passato alla routine $FFD2 CHROUT serve
										; a cancellare lo schermo a caratteri
			.text "HELLO LINUXARE!"	; la stringa da stampare

numch	= *-mystr	; questo è un piccolo hack consentito dal compilatore
					; serve a ricavare la lunghezza della stringa
					; * = indirizzo di inizio programma in memoria
					; mystr = indirizzo di inizio stringa in memoria
					; (* - mystr) sottraendo i due indirizzi si trova
					; lunghezza della stringa da stampare (var. numch)

Il programma, pur nella sua semplicità, fornisce molte informazioni su come scrivere codice assembly per il C64. La parte contrassegnata con “header” ci permette di far precedere il programma vero e proprio da un mini-listato in linguaggio BASIC per il C64, che come molti ricorderanno, è praticamente “fuso” con il sistema operativo, nel senso che per la gestione di file da cassetta o disco, dell’input/output, delle periferiche si fa ricorso a routine, comandi e istruzioni che fanno parte dell’interprete BASIC integrato nelle ROM della macchina. Il listato BASIC risultante dalle prime righe del nostro codice sarà semplicemente:

2005 SYS2064

Dopo la compilazione con 64Tass avremo ottenuto il programma hello_linuxare.prg che è un eseguibile per C64. Esso contiene il codice macchina che stampa la stringa “Hello Linuxare!” a video ed il mini listato BASIC che in pratica lo esegue automaticamente dopo che questo è stato caricato dall’emulatore VICE x64. Ricordate la macro che abbiamo abilitato in Geany? Questa eseguirà la compilazione del codice e lo lancerà all’interno di VICE. All’apertura, l’emulatore si occuperà di caricare ed eseguire automaticamente il programma hello_linuxare.prg con RUN, il comando BASIC del C64 per lanciare applicazioni. Comodo, no? Il resto del codice è ampiamente commentato e per chi abbia almeno un’infarinatura di assembly per qualunque sistema non dovrebbe presentare alcun problema.

Conclusioni

Naturalmente il vantaggio di disporre di un ambiente di cross-development come quello descritto finora è poter costruire e mantenere applicazioni ben più complesse e senza dubbio più accattivanti di un banale “Hello World”. Nello sterminato mondo del software per C64 potete trovare davvero di tutto: migliaia di giochi, centinaia di applicazioni per ufficio (persino un ambiente grafico a finestre come Geos64), strumenti per la grafica e per il suono, software didattico e demo, intro, cracktro, ecc. Ancora oggi molti programmatori attivi continuano a sfornare software per ciascuna delle categorie appena menzionate, oltre a creare i tool di sviluppo per semplificare il lavoro altrui su diverse piattaforme oltre che sullo stesso C64. Basti pensare che anche nel campo hardware sono state prodotte estensioni per aumentare la potenza del piccolo home computer, dalla CPU all’uso di dischi IDE, schede e cavi per collegarlo facilmente ad un PC, interfacce per connetterlo alla rete Internet, cartridge per far girare un sistema operativo Unix-like e mille altri hack per utilizzare l’amato home computer in ogni ambito e contesto.

Uno dei filoni ancor oggi fra i più attivi nella scena legata al C64 è senza dubbio quello connesso alla programmazione di demo, un campo di applicazione per i 64-coder di tutto il mondo dove il divertimento si sposa in pieno con il fattore sociale di cui abbiamo parlato all’inizio di questo articolo. In Rete i programmatori si incontrano e si confrontano, riuniti in gruppi dalla decennale esperienza, per mostrare agli altri il proprio lavoro, frutto di tecniche di programmazione avanzate e della collaborazione di grafici, musicisti e maghi del codice.

Lo spazio qui a disposizione non è certamente sufficiente per approfondire con qualche esempio la programmazione di demo, né per rivedere insieme la sintassi e le caratteristiche dell’assembly applicato ad una macchina come il C64. Per saperne di più, potete intanto fare riferimento alla bibliografia in calce all’articolo, volutamente stringata. Le risorse in rete ed i riferimenti bibliografici, al pari delle considerazioni viste in precedenza per la quantità di software reperibile, sono virtualmente interminabili. E poi potete scrivere al Blog Linuxare per richiedere informazioni specifiche, assistenza e, perché no?, inviare i vostri migliori lavori in codice assembly per il C64. E’ stupefacente cosa si riesce a tirar fuori da una CPU a 8-bit e 1Mhz, 64 kilobyte di RAM, un chip per la grafica ed uno per il suono e con tanta passione, impegno e altrettanto divertimento! Vi auguro allora happy 64-coding!

Cercamon

Credits: Cercamon / RetroMagazine World (www.retromagazine.net). Un ringraziamento particolare va a Hermit e ad Ice00 per la loro disponibilità.

Bibliografia essenziale di risorse web per il C64

[CSDB] Commodore 64 Scene DataBase: http://csdb.dk
C64.com: http://www.c64.com/
Lemon64: http://www.lemon64.com/
CodeBase64: http://codebase64.org/doku.php
C64.org: http://www.c64.org/
JaC64: http://www.jac64.com/
SIDRipAlliance: http://www.sidripalliance.com/
Games That Weren’t: http://www.gamesthatwerent.com/
CBM8Bit: http://www.cbm8bit.com/
Cache64: http://www.cache64.com/
GameBase64: http://www.gamebase64.com/
Ready64: https://www.ready64.org/
VICE Team: https://vice-emu.sourceforge.io/
64Tass: http://sourceforge.net/projects/tass64/
Pouet: http://www.pouet.net/

About the author

Matteo