C64 Bedtime Coding (ITA) – Primi Passi (#06)

(Articolo di Phaze101)

PRIMI PASSI

Con questo articolo abbiamo raggiunto finalmente il punto in cui passiamo dalla teoria alla pratica. Useremo CBM Prg Studio, ma non staremo qui a spiegare come fare a scaricarlo, installarlo e configurarlo visto che esistono già una moltitudine di video su YouTube che svolgono questo compito. Tutte quello che ci servirà lo spiegherò man mano che dovremo usarlo.

Potete scaricare CBM Prg Studio da qui:

http://www.ajordison.co.uk/

Ok, da ora in avanti ci sporcheremo le mani. I listati che proporrò saranno immagini, in modo che nessuno possa fare copia e incolla, perché ho bisogno che siate voi a digitare il codice. Solo facendo pratica digitando il codice come si faceva ai vecchi tempi quando si copiava i listati dalle riviste comprenderete quello che state facendo. Mi spiace se questo a qualcuno di voi non piacerà, ma è per il vostro bene: se veramente volete imparare l’assembly dovete avere la pazienza. Come ho detto nel primo articolo solo con la pazienza riuscirete ad imparare l’assembly. Ovviamente per chi di voi è già esperto potrebbe sembrare assurdo, ma questi articoli si rivolgono a chi muove i primi passi e vuole imparare seriamente l’assembly. E se volete impararlo seriamente dovrete fare qualche sacrificio: digitare i listati è uno di quelli.

Presto, quello che vedete come maestro, me, sarà sostituito da voi stessi. E quando questo accadrà, sarò fiero di voi e saprò che ho ottenuto quello che mi ero prefisso con questo corso. A quel punto sarò magari io a imparare da voi 😊

Tutto Insieme

Facciamo un riassunto veloce di quanto visto nelle ultime due puntate. Nella puntata 4 abbiamo spiegato le modalità di indirizzamento, e nella 5 il set di istruzioni.

Per chi di voi è ancora confuso, chiariamo il legame tra i due argomenti.

Prendiamo un’istruzione e vediamo come le modalità di indirizzamento influiscono.

Come esempio prendiamo LDA, che ormai dovreste sapere sta per LoaD Accumulator.

L’istruzione LDA può essere usata con i seguenti modi di indirizzamento:

  • Assoluto – LDA \$C000
  • Zero Page – LDA \$FA
  • Immediato – LDA #\$01
  • Assoluto indicizzato con X o Y – LDA \$C000,X
  • Indiretto pre indicizzato con X – LDA (\$FB,X)
  • Indiretto post indicizzato con Y – LDA (\$FB),Y
  • Indicizzato Zero Page – LDA \$FA,X

Dove ho preso tutte queste informazioni? Bè ho cercato su internet od in uno dei vari libri sul processore 6502. Non mi ricordo certo tutto a memoria, anche se col tempo alcune cose verranno naturali, ed è il motivo per cui insito che digitate i vostri listati.

Eccovi tre link che spiegano il set di istruzioni e le modalità di indirizzamento per ogni istruzion:

https://www.masswerk.at/6502/6502_instruction_set.html

http://www.obelisk.me.uk/6502/reference.html

http://www.my-testsite.co.uk/sites/cc/6502.html

Di seguito una schermata di uno dei sito dove spiega l’utilizzo di LDA che useremo come esempio per spiegare tutto il resto.

Nella riga in alto a sinistra, viene indicato che i contenuti vengono spostati dalla memoria nel registro A: M -> A

Nell’angolo in alto a destra, vediamo i flag del registro di stato che possono essere modificati da questa istruzione, in questo caso N e Z.

Nella tabelle vedete come abbiamo indicato anche noi precedentemente le modalità di indirizzamento supportate ed un esempio del funzionamento della specifica modalità.

Nella terza colonna trovate l’Opcode dell’istruzione, e cioè il numero esadecimale che vedete corrispondere all’istruzione se disassemblate un programma. Ogni modalità per la stessa istruzione ha un Opcode differente.

Le ultime due colonne servono per sapere come ottimizzare il codice e la velocità di esecuzione, ma per ora non approfondiremo questo discorso. Per completezza sappiate che la colonna “bytes” mostra quanta memoria occupa quel tipo di indirizzamento per l’istruzione, e la colonna “cycles” quanti cicli della cpu occorrono per eseguire l’istruzione con quella modalità.

Noterete proseguendo che alcune istruzioni supportano poche modalità di indirizzamento, e molte ne supportano solo una, quello implicito.

Quando avrete dei dubbi andate sempre a controllare con i tre link che vi ho fornito. Quando dovrete ottimizzare il codice, le informazioni sui byte ed i cicli saranno fondamentali.

Ottimizzazione del codice

Nell’ambito dei computer ad 8 bit si parla molto di ottimizzazione del codice e della velocità.

Lasciate che vi spieghi una cosa che potrebbe sorprendervi. Ignorate tutto cioè poiché siete neofiti. Mi avete sentito? Ignorate. Perché? Semplicemente perché a meno che non finite tutta la memoria o avete bisogno di risparmiare cicli della CPU per qualche effetto super figo, non avete bisogno di preoccuparvene. Non stiamo facendo gare e non sembrerete più bravi perché avete risparmiato 2 byte quanto avete ancora 30K liberi. Non sembrerete fighi se la vostra routine scrive del testo sullo schermo leggermente più velocemente di quella di qualcun altro. Ci saranno momenti in cui avrete effettivamente bisogno di maggiore velocità, ma fino ad allora non preoccupatevi. La cosa più importante è scrivere codice che funziona e senza bug. L’ottimizzazione viene dopo, se e quando serve. Sono sicuro che non tutti saranno d’accordo, ma questa è la mia opinione, e come principianti volete veramente sprecare tempo per ottimizzare del codice quando ancora state imparando a scriverlo?

Vi basti sapere che ci sono due tipi di ottimizzazione: della memoria e della velocità. A volte potete fare entrambi, ma per la maggior parte avrete successo con una o l’altra, a seconda del problema che dovete risolvere.

Concetti di Game Design

Un gioco è composto da varie parti, e queste parti possono essere divise in schermate per rendere le cose semplici.

Prendiamo come esempio un gioco semplice, avrete:

  1. La schermata di apertura dove normalmente si attende la pressione di un pulsante per iniziare
  2. La schermata di apertura può dare accesso ad una schermata di aiuto con le istruzioni su come giocare
  3. Premendo il pulsante previsto dalla schermata di aperture si accede al gioco
  4. Durante il gioco (ci si riferisce solitamente al game loop) accadono varie cose come il movimento del giocatore, del nemico, la gestione delle collisioni, e a seconda della collisione possono venir scatenate altre attività, come l’aggiornamento del punteggio o del numero di vite del giocatore, etc. Tutto questo continua fino a che le vite finiscono.
  5. Quando il gioco finisce compare la schermata di game over
  6. Dopo la schermata di game over può esserci la schermata dei punteggi migliori dopo di che si viene nuovamente portati alla schermata di apertura

Perché vi dico tutto questo? Perché con le prossime puntate vedremo come fare i punti 1,2,3,5,6.

Per ora non ci occuperemo del game loop, ma ci torneremo quando tutte le altre parti saranno chiare.

Programmare l’hardware Commodore

Durante le prossime lezioni accederemo spesso direttamente all’hardware. Questa è una cosa alla quale molti di voi saranno abituati grazie ai comandi Peek e Poke del Basic.

Quando lo faremo, cercherò sempre di spiegarvi le cose essenziali ma un libro di cui avrete costantemente bisogno è il Manuale di Riferimento del Commodore 64. Anche se di sicuro c’è chi si ricorda i registri hardware a memoria, non è una cosa necessaria per programmare. L’importante è capire cosa fanno.

Ok, ora basta parlare, e come promesso, iniziamo a programmare.

Il mio stile di programmazione

Il mio codice è pesantemente commentato, sono abituato addirittura a indicare il libro che ho usato per capire come scrivere una parte di codice se non addirittura la pagina.

Credo fermamente nell’utilità dei commenti, ma ovviamente quando dovrete digitare I listati proposti, non sarà necessario digitare anche quelli.

Inoltre, ci saranno pezzi di codice che dovrete digitare come sono, anche se non capirete per ora cosa stanno facendo. Ad esempio in questa lezione questo è il caso del codice che attende che venga premuto lo spazio (spacebar). Non perdete tempo cercando di capirlo, quando sarà il momento spiegheremo come gestire la tastiera.

Solitamente poi non amo usare le istruzioni JMP, così come non amo i GOTO in basic. Credo che (è solo la mia opinion) il GOTO ed il JMP possano troppo facilmente generare “spaghetti code”.

Quando possibile divide sempre tutto in piccole subroutine, e magari poi ancora in sub routine più piccole, quindi sono un pesante utilizzatore della JSR. A mio avviso il codice in questo modo è molto più ordinato.

Cosa intendo con questo? Se guardate il nostro primo esempio abbiamo una subroutine chiamata WaitForSpace. Avrei potuto inserire quel codice direttamente all’inizio di quello principale, ma preferisco averla separata in modo che nel codice principale mi posso concentrare sulle cose principali ed ignorare il codice della WaitForSpace. Eccone il codice:

Come ho detto prima, digitate questo codice senza i commenti e senza cercare di comprenderlo.

Vedrete che questo crea anche dei piccoli pezzi di codice che saranno (in futuro, per ora non lo faremo) molto più semplice da debuggare.

Il codice di questa sezione partirà sempre dalla locazione di memoria 49152 ($C000), quindi per eseguirlo dovrete digitare SYS 49152. Questo comando non verrà indicato ogni volta nei tutorial, che potete anche aggiungere autonomamente con CBM PRG Studio.

Perché la locazione $C000? Bè il C64 ha 4K di memoria protetta dal Basic, per ora i nostri programmi non saranno più grandi di 4K, per cui è comodo usarli.

Un’altra cosa, ignorero i miei stessi commenti e vi spiegherò solo il codice che serve spiegare. Starà a voi leggerli per comprendere meglio tutto.

Un avviso per chi non sa l’Inglese: I commenti non saranno tradotti. Per favore usate Google Translate, anche se le cose più importanti saranno comunque tradotte nell’articolo.

Come noterete mi piace usare dei blocchi di commenti delimitati da due righe di uguali (=), solitamente all’inizio di ogni blocco di codice.

Il mio stile di programmazione è dovuto alle mie preferenze, poi col tempo svilupperete il vostro stile, che non deve per forza essere come il mio. Ho voluto solo spiegarvi il mio.

I prossimi due capitoli non vi mostreranno nulla di spettacolare, ma serviranno per incominciare ad impratichirci con l’assembler.

Primo Programma – Code 01

Ecco il codice principale, che dovete digitare, leggere e comprendere.

Esaminiamolo e spieghiamolo tutto.

Prima di tutto, i commenti sono riportati in verde.

La prima cosa che noterete è la direttiva *. Questa non è un’istruzione per la CPU ma è quella che si chiama una direttiva per l’assembler. Sostanzialmente con questa stiamo dicendo all’Assembler da quale locazione di memoria in poi memorizzare il nostro codice, in questo caso dalla locazione $C000 o 49152. Per questo motivo il comando SYS 49152 eseguirà il nostro codice.

Subito dopo vedrete la label Start. Questa è una label che indica l’inizio del nostro programma. In questo caso è una label che non useremo, ma è una cosa che di solito faccio.

Le tre istruzioni successive sono molto interessante. La prima (LDA #\$0) carica il valore 0 nell’accumulatore. Stiamo usando l’indirizzamento immediato e il carattere hash (#) indica come abbiamo già spiegato nella quarta puntata che il valore seguente è da usare direttamente.

Le seconda e la terza sono molto semplici, se in BASIC avete già modificato altre volte il colore dello sfondo e del bordo riconoscerete la locazione \$D020 e \$D021 che, se convertite in decimale, sono rispettivamente la 53281 e 53280. Quindi, cosa stiamo facendo?

Abbiamo caricato nell’accumulatore il valore zero, equivalente al colore nero, e poi stiamo dicendo alla CPU di copiare quel valore nelle locazioni 53281 e 53280 rispettivamente, coma fareste in basic con un comando poke.

Continuando troviamo il commando JSR che salta ad una subroutine, che non fa altro che aspettare per noi che venga premuto lo spazio. Quando questo accade, si arriva all’istruzione RTS che riprenderà l’esecuzione da dopo la JSR e quindi dopo la SYS49152, tornando al BASIC. Il programma ha così finito la sua esecuzione.

Quando eseguiremo questo programma, da ora in poi sempre con SYS49152, otterremo quanto mostrato nella figura seguente. Il programma cambierà colore allo sfondo ed il bordo ed aspetterà che premiamo lo spazio, e poi tornerà il prompt READY.

Provate a modificare il programma per ottenere diversi colori per sfondo e bordo.

Ecco il istato completo (niente copia e incolla!)

Secondo Programma – Code 02

Passiamo al secondo listato.

Questo codice crea lo stesso effetto che si vede in molti loader. In realtà il codice è più semplice ancora di quello precedente.

Abbiamo una sola istruzione, e cioè INC \$D020. Praticamente incrementiamo il valore della locazione \$D020. Non importa se così facendo supereremo il numero 16, in quando il nibble alto del byte viene ignorato e quindi vengono usati solo i primi 4 bit, risultando in colori dallo 0 al 15. Quando il valore in \$D020 raggiungerà \$FF ripartirà da zero.

Ricordatevi che come sempre per eseguire il codice dovete dare il commando SYS49152, e che dovrete premere lo spazio per uscire dal programma.

Ed ecco il listato.

La prossima settimana

Per questa settimana è tutto. Questi semplici tutorial vi serviranno per incominciare ad abituarvi a digitare codice in assembly, imparare a formattarlo ed abituarvi a come l’assembler mostra gli errrori. Imparate ad usare l’help di CBM Prg Studio per comprenderne meglio il funzionamento.

La prossima settimana vedremo diverse modalità di creare la prima routine di cui avremo bisogno per il nostro gioco.

Come al solito, se avete problem, scrivetemi. Per ora è tutto.

Coding is Fun 😊

Phaze 101

Italian

Articolo 5
https://sys64738.org/2019/04/c64-bedtime-coding-ita-il-set-di-istruzioni/

Articolo 4

https://sys64738.org/2019/03/c64-bedtime-coding-ita-modalita-di-indirizzamento-04/

Articolo 3
https://sys64738.org/2019/03/c64-bedtime-coding-ita-i-registri-della-cpu-03/

Articolo 2
https://sys64738.org/2019/03/c64-bedtime-coding-ita-linguaggio-macchina-02/

Articolo 1
https://sys64738.org/2019/03/c64-bedtime-coding-introduzione-e-basi-01/