Assembly 6510: programmazione vintage

di Andrea Zani, in Imho,

Non sono passati trent'anni, ma quasi. Durante le scuole i miei genitori mi regalarono il Commodore 64: lo avevano per giocare alcuni amici, e lo volevo anche io per i suoi incredibili giochi. Dopo il primo periodo di sfogo videoludico ecco che in me nacque il desiderio di capirne di più. In edicola, ai tempi, si potevano trovare pochissime riviste di informatica (stiamo parlando della seconda metà degli anni '80) e per lo più si trovavano cassette ricolme di giochi e alcune riviste che approfondivano la programmazione. Grazie a queste riviste, una su tutte CCC, iniziai ad appassionarmi per la programmazione, inizialmente per il Basic, poi per l'assembly.

Viene quasi da sorridere pensando alla potenza dei computer dell'epoca. Il Commodore 64, un piccolo gioiello per l'epoca, era dotato di una CPU CMOS 6510 all'incredibile velocità di 1MHz, di un chip apposito per la gestione del sonoro, il sid 6581, di ben 64KB di ram, rom di 20kbyte (8k basic + 8k kernal + 4k set caratteri), uscita video RGB PAL con la risoluzione 320x200 a 16 colori in modalità grafica VIC-II. Tanta roba per l'anno di uscita, il 1982.

Il Basic V2 di cui era dotato era veramente minimale: utile per scopo didattico ma ridicolo per ottenere qualcosa di più serio. Già all'epoca, per usare le modalità grafiche e sprite, si doveva fare largo uso di comandi diretti per le modifiche di alcune celle di memoria - per chi è della mia epoca e conosce il Commodore 64, sicuramente sa cos'è il comando poke. Ad essere sinceri il passaggio all'Assembly non era una libera scelta, ma una necessità.

La semplicità tecnologica della CPU la si poteva constatare dalla sua tecnologia a 8 bit e all'indirizzamento di memoria a 16 bit (2^16 = 655536 = 64KB... ma va?) e soprattutto dall'esiguo e semplice numero di istruzioni dell'assembly; inoltre il numero di registri era limitato: Accumulator (A), X-Register (X), Y-Register (Y), Program Counter (PC) e Status Register. I primi tre erano utilizzabili direttamente durante la programmazione (si può pensare a questi tre registri come a delle variabili il cui valore, strettamente a 8 bit, poteva venire usato per modificare una cella di memoria); il Program Counter era il registro che puntava alla locazione di memoria dell'attuale istruzione in linguaggio macchina in esecuzione, e infine lo Status Register che impostava determinati bit dipendentemente dall'esecuzione del codice. Al giorno d'oggi la programmazione assembly è ormai solo per scopi super specialistici data la complessità a cui siamo giunti, ma all'epoca era sufficiente sapere che la locazione di memoria 53280 ($D020 in esadecimale) era utilizzata per impostare il colore del bordo dello schermo, per poter scrivere in assembly:

lda #$00
sta $d020
rts

Trasformato questo codice in puro linguaggio macchina e lanciato, ci si sentiva super programmatori nel vedere il bordo colorarsi di nero. Ricordo che qualche tempo dopo mi appassionai anche per la programmazione assembly per l'Amiga e il suo Motorola 68000, ma anche se lì i registri erano 15 (se non sbaglio) e tutto era molto più avanzato, non riprovai mai la stessa magia con l'assembly che sentivo con il Commodore 64.

Sarà l'effetto che siamo agli ultimi giorni dell'anno e ci si ritrova a pensare a quanto successo in quello trascorso, però tornare indietro di trent'anni è forse troppo. Eppure spesso mi ritrovo a pensare come all'epoca non solo la vita era più semplice, ma anche la programmazione! Ricordo il ritorno a casa da scuola e, nel pomeriggio, finiti gli obblighi dei compiti e altre cose, mi ritrovavo a provare, scrivere, modificare codice che trovavo sulle suddette riviste, e da lì partivo per esperimenti tutti miei che finivano spesso in fallimenti, ma in altre occasioni in scoperte che, all'epoca, sembravano fantascientifiche. Ricordo, per esempio, una problematica che mi ero posto all'epoca e che mi aveva tenuto in ballo per parecchi giorni per trovare una soluzione. Una cosa che odiavo (e odio tuttora quando uso gli emulatori) erano i source editor di codice. Forse perché sono abituato troppo bene adesso, odiavo lo scroll e la limitata visione di colonne e righe che avevano i computer dell'epoca (il Commodore 64 aveva, in modalità testuale, 40 colonne per 25 righe). Quando si doveva fare riferimento a determinati blocchi di codice o di dati, si perdeva un sacco di tempo solo per andarsi a cercare il tutto. Per esempio, volendo visualizzare un blocco di testo, si doveva scrivere alcune righe di codice che chiamavano alcune funzioni direttamente nella ROM del computer, e riempire una zona di memoria con il testo da utilizzare. Mi spiego con un esempio:

#pseudo codice
     lda {locazione di memoria "bassa" di msg1}
     ldx {locazione di memoria "alta" di msg1}
     jsr {locazione di memoria funzione kernel per visualizzare testo}
     ...
msg1 .text "Testo da visualizzare 1"
     .byte 0
msg2 .text "Testo da visualizzare 2"
     .byte 0
msg3 .text "Testo da visualizzare 3"
     .byte 0

Per limitare gli spostamenti nel codice e per un mio puro diletto, ricordo che provai a pensare ad un modo per raccogliere insieme il codice con i dati da utilizzare. Il mio obiettivo finale era qualcosa di questo tipo:

#pseudo codice
     jsr {mia funzione per visualizzare testo successivo}
     .text "Testo da visualizzare 1"
     .byte 0
     jsr {mia funzione per visualizzare testo successivo}
     .text "Testo da visualizzare 2"
     .byte 0
     jsr {mia funzione per visualizzare testo successivo}
     .text "Testo da visualizzare 3"
     .byte 0
     ...

Non ho mai scoperto se questa cosa mi sia stata veramente utile, ma ricordo che fu una sfida molto interessante all'epoca. Per non lasciare nessuno sulle spine, taglio dicendo che trovai la soluzione. Ci arrivai conoscendo il modo che usava il 6510 per richiamare funzioni (comando jsr come visto sopra, e rts che sarebbe come l'attuale return). Il Commodore 64, quando incontrava questo comando, salvava nello stack in due byte la locazione di memoria attuale; quindi saltava alla nuova locazione di memoria, quando incontrava il comando rts ripescava dallo stack la locazione di memoria da dove era partito, aggiungeva "uno", quindi impostava il Program Counter a questa locazione di memoria e continuava l'esecuzione. Fine, nulla di complesso: la mia soluzione fu quella di modificare l'indirizzo di memoria per fare in modo che, al comando rts, il programma continuasse dove volevo io.

Questa sfida e il modo con cui la superai all'epoca me la ricordo anche attualmente a distanza di tutti questi anni, ed eccomi con un emulatore a ripetere la sfida ben conoscendo però, la soluzione:

  *=25000
        jsr print
        .text "hello world!"
        .byte 0
        # resto del codice
        rts

print   pla
        sta $fb
        pla
        sta $fc
        ldy #0
print2  inc $fb
        bne print3
        inc $fc
print3  lda ($fb),y
        beq end
        jsr $ffd2
        bne print2
end     lda $fc
        pha
        lda $fb
        pha
        rts

Innanzitutto il codice è scritto direttamente con TurboAssembler (T-ASS). "*" specifica la locazione di memoria dove l'editor inserirà il codice inserito. Il tag ".text" e ".byte" sono codici dell'editor che permettono l'inserimento di testo o di byte. "print", "print2", "print3" e "end" sono dei segnalibro che possiamo usare nel codice per saltare in altre zone del codice. Se eseguo questo codice, quando il 6510 incontrerà l'istruzione jsr print accadrà quando descritto sopra: salverà l'attuale posizione nello stack e salterà alle istruzioni presenti al segnalibro "print". pla è un comando del 6510 che prende il contenuto dallo stack, e lo faccio per due volte salvandolo nelle locazioni di memoria $fb/$fc. Essi punteranno proprio nella zona di memoria dov'è presente il mio testo - hello world! - quindi, a grandi linee, il mio codice prende une byte per byte e li visualizza a schermo fino a quando incontrerà il valore zero. Quindi risalva la nuova locazione di memoria nello stack che sarà utilizzata dopo l'rts. Sarei troppo pignolo e sarebbe inutile, nel 2016 - quasi 2017 - a descrivere nel dettaglio tutti questi comandi, e rimando a questa wiki dove si potrà trovare tutto.

Ma funziona? Prima di tutto, ecco il codice all'interno dell'editor nell'emulatore - purtroppo non ho più un Commodore 64:

Ed eccolo eseguito:

Lo so, gli anni passano, i capelli in meno e tutto il resto mi fanno capire che non ho più 14 anni. Però una cosa è rimasta dell'epoca: la curiosità nel mondo della programmazione. Non è poco.

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Nella stessa categoria
I più letti del mese