C64 Bedtime Coding (ITA) – Cancellare lo schermo (#07)

(Articolo di Phaze101)

Cancellare lo schermo

 

Perché cancellare lo schermo è importante?

La pulizia dello schermo è un’operazione che si ripete spesso all’interno dei giochi. Cancellare lo schermo richiede del tempo. Se è necessario farlo più volte durante un gioco, allora può diventare un fattore importante e quindi c’è bisogno di una routine veloce.

Ci sono diversi metodi per compiere quest’operazione. Con alcuni di questi mi trovo d’accordo, altri non mi piacciono affatto. Inoltre, a volte una routine veloce non è affatto necessaria. Dipende sempre da quando deve essere eseguita la routine all’interno del gioco.

Come ho già dichiarato in altre occasioni, vorrei ricordare a tutti voi che non ho mai scritto giochi a livello professionale, quindi nei miei articoli non troverete routine ottimizzate e superveloci, anche se cercherò di occuparmene in parte. Detto questo, la serie di articoli è rivolta ai principianti ed in base al suo scopo didattico, cercare di capire i concetti della programmazione è più importante.

Metodo Uno – Utilizzare il Kernal

In termini di codice, questo è il metodo più semplice per cancellare lo schermo ma è anche il metodo più lento. Anche se è il metodo più lento, viene utilizzato più spesso di quanto si pensi. Un esempio di applicazione è quando ci si trova nella schermata principale di un gioco e si sceglie di passare alla schermata delle istruzioni. In questo caso, non c’è bisogno di una routine ultraveloce per cancellare lo schermo e visualizzare le istruzioni.

Il primo metodo di cui trattiamo utilizza il Kernal. Il Kernal è un blocco di codice che contiene numerose routine per gestire cose diverse del sistema.

Come definito nel sito Wiki dedicato al C64:

“Il Kernal è l’insieme di interfacce hardware di basso livello presente in tutta la serie di computer a 8 bit della Commodore, a cominciare dai Commodore PET.

Il Kernal consiste di trentanove (39) funzioni che vanno dal controllo di input/output alla gestione dei file, della memoria, della console e del tempo. Queste funzioni costituiscono la base per routine di livello superiore contenuti nella ROM BASIC come i comandi  LOAD, SAVE, INPUT e PRINT.

Le funzioni del Kernal sono accessibili tramite una tabella di salto situata alla fine della memoria indirizzabile (\$FF81-\$FFF3). La ROM del Kernal occupa solitamente gli ultimi 8KB di spazio di indirizzamento nei computer Commodore a 8-bit (\$E000-\$FFFF)”.

Ecco il link alla pagina Wiki del Kernal del C64:

https://www.c64-wiki.com/wiki/Kernal

La routine che utilizzerò non fa parte delle routine standard del Kernal che sono elencate nella tabella, ma è costruita all’interno di questa parte di codice di 8K del Kernal.

La routine per cancellare lo schermo si trova all’indirizzo \$E544. Tutto quello che si deve fare per cancellare lo schermo è quindi richiamarla usando l’istruzione JSR \$E544.

Ecco un listato d’esempio.

Ricordatevi di digitare SYS 49152 nell’emulatore e di premere la barra spaziatrice per uscire dal programma e tornare al messaggio READY. 😊

Ecco la schermata risultante dall’esecuzione. Come potete vedere, non c’è molto sullo schermo o non molto che si possa davvero vedere.

Metodo Due – La nostra versione

Invece di utilizzare le routine di sistema, è ora giunto il momento di scrivere la nostra routine.

Per coloro che non lo sanno, la memoria dello schermo a caratteri del Commodore 64 inizia alla locazione 1024 o \$0400. Lo schermo è composto da 25 righe e 40 caratteri per ciascuna riga. Se moltiplichiamo 25 x 40 otteniamo 1000. Ciò significa che lo schermo può contenere 1000 caratteri alla volta. Quindi la memoria dello schermo va da 1024 (\$0400) a 2023 (\$07E7). Il codice di schermo del carattere “spazio” è 32 o \$20. Quindi se riuscissimo ad inserire il codice schermo 32 in ciascuna di queste 1000 locazioni di memoria, otterremmo effettivamente la cancellazione dello schermo.

Ed è proprio questo che facciamo con questo metodo. Ecco il listato principale del codice:

Spiegazione

 

Linee da 43 a 45.

Queste linee dovrebbero suonarvi familiari. Inseriamo 0 (zero) che corrisponde al colore nero nei registri di sfondo e del bordo. Le linee erano incluse come revisione dell’articolo 6 di questa serie. 😊

Linee 47 e 48.

Inizializziamo l’accumulatore con il valore \$20 o 32, cioè il carattere spazio. Inoltre, impostiamo il registro X al valore 0 (zero).

Linea 49.

Mettiamo un’etichetta (un nome significativo) all’inizio del nostro ciclo. Avremmo potuto scrivere le linee 49 e 50 come segue:

Loop      STA        \$0400,X

ma preferisco che la label occupi una linea per renderla più visibile.

Linee da 50 a 54.

Cosa facciamo in queste righe? In pratica, memorizziamo il valore contenuto nell’accumulatore (che è \$20 o 32) nelle locazioni di memoria dello schermo attraverso l’indirizzamento indicizzato assoluto.

Quindi, se prendiamo in esame la sola linea 50, stiamo memorizzando il valore dell’accumulatore nella locazione di memoria \$0400 + X. Dal momento che X è pari a zero (linea 48), la prima volta che viene eseguito il ciclo, la locazione di memoria sarà \$0400. Il registro X verrà modificato più avanti nel programma. Se vale 1, allora memorizzeremo il valore 32 contenuto in A nella locazione \$0400 + 1 e cioè all’indirizzo di memoria \$0401. E così via per 200 volte.

Lo stesso accade nelle linee seguenti da 51 a 54 a partire dalle locazioni di memoria \$04c8, \$0590, \$0658 e \$0720. Ma perché facciamo la stessa cosa proprio in queste locazioni di memoria? Il registro X può contenere solo valori fra 0 e 255 ed abbiamo uno schermo che è composto da 1000 byte, perciò sarà capace di cancellare 256 caratteri dello schermo.

Avremmo potuto aggiungere 256 a \$0400 e questo significa che le locazioni di memoria successive sarebbero state \$0500, \$0600 and \$0700, ma 256 moltiplicato per 4 ci dà 1024 che è maggiore dei 1000 caratteri di cui abbiamo bisogno. Nella memoria del C64 dopo l’indirizzo \$07E7 (2023) abbiamo alcuni registri relativi agli sprite. Se cancellassimo 1024 byte invece di 1000, andremmo a sovrascrivere queste locazioni. In alcuni casi, ciò non ha molta importanza, ma in un gioco ce l’ha eccome, perché quasi sicuramente il gioco utilizza gli sprite. Così ho preso l’abitudine di evitare di cancellare le locazioni di memoria oltre l’indirizzo 2023.

Per superare il problema, invece di aggiungere 256 ci limitiamo a 200. Infatti 200 x 5 fa proprio 1000 che, come detto, è la dimensione della memoria schermo. Perciò gli indirizzi di memoria \$04c8, \$0590, \$0658 e \$0720 distano 200 byte fra loro e se usiamo X con valori fra 0 e 199 (200 caratteri) riusciremo a cancellare l’intero schermo coprendo i 1000 caratteri totali.

Linea 55.

Incrementiamo X di uno ogni volta che attraversiamo il ciclo.

Linea 56.

Ci assicuriamo di non aver raggiunto il valore di 200, perciò confrontiamo il registro X con 200.

Linea 57.
Se il valore di X non è uguale a 200, semplicemente torniamo ad inizio ciclo alla linea 49. Se invece X ha raggiunto il valore di 200, smettiamo di eseguire il ciclo e continuiamo con l’istruzione successiva che porta alla subroutine che controlla la pressione della barra spaziatrice.

Mettendo in esecuzione il programma verrà visualizzato uno schermo nero vuoto e vedrete il messaggio READY. dopo aver premuto il la barra spaziatrice.

Ecco un link alla lista completa dei codici di schermo del C64:

http://sta.c64.org/cbm64scr.html

 

Riempire lo schermo

Lo stesso semplice codice che cancella lo schermo potrebbe essere utilizzato per riempirlo. Passando un valore diverso da \$20 (spazio) nella linea 47 è possibile riempire lo schermo con qualsiasi carattere si voglia.

Che cosa accade se cambiassimo il valore nella linea 47 in un altro, ad esempio 0?

Quale codice di schermo ho utilizzato per riempire lo schermo e creare l’effetto qui sotto?

Qui di seguito il listato completo con il codice usato per il metodo 2.

Metodo Tre – Utilizzare la Pagina Zero

Questo metodo è lo stesso già visto nel metodo due, ma invece di usare l’indirizzamento indicizzato assoluto, ricorriamo alle risorse della Pagina Zero per cancellare lo schermo.

L’operazione oltrepassa i 1000 caratteri dello schermo e sovrascrive i registri degli sprite. Non è l’ideale quando si scrivono i giochi, ma ne fornisco comunque la versione per mostrare cosa si può fare con le locazioni di memoria della Pagina Zero.

Nell’articolo 8 rivelerò la mia tecnica di pulizia dello schermo che fa uso di variabili in Pagina Zero e che riguarda soltanto i 1000 caratteri dello schermo. Sarà anche una specie di revisione di questo articolo.

Ecco il codice principale:

La maggior parte delle locazioni in Pagina Zero viene utilizzata dal sistema e dal BASIC. Ci sono comunque 4 indirizzi che rimangono liberi ad uso del programmatore. Queste sono le locazioni \$FB, \$FC, \$FD e \$FE.

Se volete indagare per cosa sono usate tutte le altre locazioni di memoria in Pagina Zero, date un’occhiata al link seguente:

https://www.c64-wiki.com/wiki/Zeropage

Come detto in precedenza, notate come gli indirizzi liberi si trovino alla fine del banco di memoria in Pagina Zero. Inoltre alcune di queste locazioni di memoria sono davvero interessanti da investigare.

 

Spiegazione

 

Linee da 52 a 55.

Come già detto, la memoria dello schermo parte da \$0400. Così memorizziamo \$00 in \$FB e \$04 in \$FC. Ricordate che dobbiamo sempre memorizzare un indirizzo come byte basso e byte alto (\$LLHH). Questo argomento è stato trattato nell’articolo 4. Perché lo facciamo in questo modo? Perché è così che il 6502 tratta gli indirizzi di memoria. E se ricordate, questo è il metodo con cui gli indirizzi a 16 bit vanno inseriti in memoria.

Da notare anche che stiamo inizializzando X con il valore \$04 e inseriamo lo stesso valore di X in \$FC. Il valore di X verrà usato successivamente e questa è già una sorta di ottimizzazione. Avremmo potuto usare il registro A o Y ma lo facciamo così per una ragione che diventerà evidente in seguito.

Linea 56.

Poniamo il registro Y a zero (0). Avremmo potuto scrivere LDY #\$00 ma poiché sappiamo che il valore dell’accumulatore è già zero, abbiamo usato solo l’istruzione TAY che è un’istruzione più rapida. L’ho fatto che per mostrarvi l’ottimizzazione del codice.

Linea 57.

L’istruzione già vista nel metodo precedente che carica l’accumulatore col codice di schermo \$20 o 32 che corrisponde al carattere spazio.

Linea 59.

Questa è praticamente l’istruzione chiave del metodo che fa uso della pagina zero ed è ciò che rende la routine velocissima. Inseriamo il valore di A nell’indirizzo di memoria trovato in \$FB e \$FC più il valore del registro Y.

Qui utilizziamo l’indirizzamento post-indicizzato indiretto con Y. L’indirizzo di memoria cui ci riferiamo è \$0400 (ricordate che è memorizzato in ordine inverso in \$FB e \$FC). Aggiungiamo il contenuto del registro Y a \$0400 e poi inseriamo il valore di A nell’indirizzo di memoria ottenuto.

Linee 60 e 61.

Incrementiamo Y e, se non è uguale a 0, ripetiamo di nuovo il ciclo. Quando Y vale 255 e viene incrementato tornerà a 0 e così proseguiremo con l’istruzione successiva.

Linea 62.

Dopo aver cancellato i primi 256 caratteri, dobbiamo proseguire con i successivi 256. Quindi incrementiamo di uno ciò che si trova in \$FC (che diventa \$05). L’indirizzo puntato da \$FB e da \$FC non è più \$0400 ma \$0500 ed Y può iniziare a modificare (cancellare) questo intervallo di memoria schermo.

Linee 63 e 64.

Ricordate quello che ho detto prima a proposito di X. Bene, ecco il motivo per cui ho utilizzato il registro X. Per pulire lo schermo dobbiamo cambiare il valore all’indirizzo \$FC. Dobbiamo cambiarlo successivamente in \$05, \$06 e \$07. Usciremo dal ciclo quando X vale 0 e proseguiremo con l’istruzione successiva che corrisponde alla routine che attende la pressione della barra spaziatrice. Quando X vale 4, nelle locazioni \$FB e \$FC otteniamo l’indirizzo di memoria \$0400, quando X è 5, l’indirizzo è \$0500 e così via.

Come già detto, questa routine supera i 1000 caratteri della memoria dello schermo, quindi è meglio usarla con cautela. Se non utilizzate gli sprite, allora non c’è alcun pericolo.

Qui sotto una schermata del risultato e come sempre non dimenticate di usare SYS 49152 per eseguire il codice.

Segue il listato completo del metodo 3:

Prossimo Articolo – 11 maggio

Per questa settimana abbiamo terminato. Spero che abbiate potuto comprendere come la stessa routine può essere utilizzata per pulire e per riempire lo schermo. In pratica riempiamo la memoria dello schermo con il carattere spazio, il che in realtà avrà l’effetto di cancellarlo.

Il prossimo articolo purtroppo non uscirà la prossima settimana ma sabato 11 maggio. Il motivo è che ho alcuni impegni cui non posso mancare e a cui dovrò dare una certa priorità anche nelle settimane a venire.

Il prossimo argomento che tratteremo sarà la visualizzazione di caratteri sullo schermo.

Come al solito, se avete problemi con i listati o domande di altro genere vi prego di mandarmi un messaggio. Per il momento è tutto.

Coding is Fun 😊

Phaze 101

Traduzione in italiano di: David La Monaca/Cercamon, Arturo Dente e Davide Aldegheri

Hanno collaborato a questo numero di C64 Bedtime Coding: Colin Vella, Pinov Vox

Italian

Articolo 6
https://sys64738.org/2019/04/c64-bedtime-coding-ita-primi-passi-06/

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/

1 comment

  1. Pingback: C64 Bedtime Coding (ITA) – Stampare sullo schermo (#08) – SYS64738

Have your say