Se da ragazzino hai digitato qualche listato Basic sul tuo C64, del tipo di quelli contenuti su qualche rivista specializzata (io lo facevo spesso), probabilmente ti sarai chiesto almeno una volta 'Dove vanno a finire le linee Basic che digito?'. In altre parole 'Dove e con che criterio il C64 memorizza i programmi Basic digitati?'.
Cerchiamo di capirlo insieme.
Il C64 memorizza i listati Basic (come pure i programmi utente scritti in linguaggio macchina) nella sua RAM, cioè nella parte di memoria in cui è possibile scrivere dati.
All'accensione il C64 dispone di 38911 bytes atti a contenere programmi Basic (questa informazione, tra l'altro, è contenuta nella testata dell'interprete Basic stesso). Ora, all'accensione la RAM del C64 è organizzata circa in questo modo:
area testo basic -> area delle variabili (non array) -> area delle variabili (array) -> area RAM libera -> area stringhe dirette
Dopo aver acceso il nostro 64, digitiamo la seguente istruzione
PRINT PEEK(43):PRINT PEEK(44):PRINT PEEK(45):PRINT PEEK(46)
*
Che stampa a schermo il contenuto delle locazioni di memoria da 43 a 46 ($2B-$2E in esadecimale). Il risultato a schermo sarà:
1
8
3
8
Cosa significano queste cifre?
Le prime due cifre costituiscono l'indirizzo iniziale dell'area di memoria contenente il testo basic, mentre le altre due costituiscono l'indirizzo iniziale dell'area di tutte le variabili non array.
Da cui si ricavano i seguenti indirizzi:
43-44 ( puntatore ind. iniziale testo basic ) ->
1*1 + 8*256 = 1 + 2048 = 2049 ($0801 esadecimale)
45-46 ( puntatore ind. iniziale area variabili ) ->
3*1 + 8*256 = 3 + 2048 = 2051 ($0803 esadecimale)
Ciò significa che, all'accensione, il C64 memorizza il testo dei programmi Basic (cioè i listati che noi digitiamo a schermo) a partire dalla locazione n. 2049, mentre l'area che contiene la definizione delle variabili inizia subito dopo la fine del testo Basic (all'accensione della macchina, alla locazione n. 2051). Com'e' facile immaginare, i valori di queste locazioni cambieranno non appena digiteremo una qualunque riga basic in memoria.
Digitiamo ora:
PRINT PEEK(47):PRINT PEEK(48):PRINT PEEK(49):PRINT PEEK(50)
Avremo a schermo:
3
8
3
8
Queste locazioni contengono, rispettivamente, l'indirizzo d'inizio dell'area riservata a contenere le informazioni sulle variabili array, e l'indirizzo d'inizio della RAM libera, cioè non occupata da bytes riguardanti programmi Basic.
Da qui ricaviamo che, all'accensione, i puntatori al testo dei programmi Basic, alle variabili (normali e array), e alla RAM libera coincidono alla locazione 2051.
Queste locazioni punteranno ad indirizzi diversi tra loro, non appena definiremo delle variabili all'interno del nostro programma Basic.
Infine, digitiamo:
PRINT PEEK(51):PRINT PEEK(52)
Avremo stavolta:
0
160
Queste ultime due locazioni puntano all'indirizzo iniziale dell'area che gestisce le stringhe temporanee immesse in modo diretto (cioè non in modo programma). Ad esempio, l'istruzione
PRINT "COMMODORE 64"
memorizza una stringa temporanea (cioè non associata ad una variabile stringa) in modo diretto (cioè non dall'interno di una riga di programma).
Al contrario delle altre variabili, le stringhe temporanee dirette vengono allocate "dall'alto verso il basso", cioè a partire dalla locazione puntata dalle locazioni 49-50, in giù.
Deduciamo perciò che, all'accensione, le stringhe temporanee dirette vengono allocate a partire dalla locazione 40960 in giù( 0*1 + 160*256 ).
Questa è, di default, l'ultima locazione usata dai programmi Basic.
Digitiamo ora il seguente programma
10 A$="ALBERTO"
20 N%=1
30 PRINT "ESEMPIO"
40 DEF FN F(X)=X*2
50 FOR I=1 TO 2: A%(I)=I+1 : NEXT
Scrivendo queste righe, abbiamo inserito in memoria, a partire dalla locazione 2049, del testo Basic. Non solo;abbiamo anche definito una variabile stringa una variabile intera, una stringa temporanea indiretta, una variabile funzione, un array di interi non dimensionato ( formato quindi da 11 elementi ). Digitiamo di nuovo le istruzioni *, **, ***.
Scopriremo i seguenti valori:
43 ($2B) -> 1
44 ($2C) -> 8
45 ($2D) -> 91
46 ($2E) -> 8
47 ($2F) -> 91
48 ($30) -> 8
49 ($31) -> 91
50 ($32) -> 8
51 ($33) -> 0
52 ($34) -> 160
Il puntatore all'area delle variabili non array è stato spostato alla locazione 2139;ciò significa che il testo Basic, in memoria, si trova compreso tra la locazione 2049 ($0801) e la locazione 2138 ($085A).
Notiamo però che, nonostante abbiamo definito variabili normali e di tipo array, i puntatori all'area variabili e alla RAM libera coincidono ancora. . . com'e' possibile tutto ciò?
Il motivo è semplice;l'interprete Basic del C64 alloca variabili in memoria 'a Run-Time', cioè solo quando il programma Basic viene mandato in esecuzione.
Perciò, diamo ora RUN, e digitiamo ancora una volta *, **, ***.
I valori delle locazioni d'interesse sono ora:
43 ($2B) -> 1
44 ($2C) -> 8
45 ($2D) -> 91
46 ($2E) -> 8
47 ($2F) -> 126
48 ($30) -> 8
49 ($31) -> 155
50 ($32) -> 8
51 ($33) -> 0
52 ($34) -> 160
Da cui ricaviamo che le variabili non array sono state allocate nelle locazioni 2139-2173, mentre l'array è stato allocato nelle locazioni 2174-2202.
La RAM libera comincia dunque a partire dall'indirizzo 2203.
Il puntatore all'area delle stringhe temporanee dirette, invece, è rimasto invariato, in quanto l'unica stringa temporanea presente in memoria è contenuta nel nostro programma.
Adesso, disassembliamo il contenuto delle locazioni $0801-$085A con un qualsiasi programma monitor.
ATTENZIONE!!!IL MONITOR DEVE ESSERE CARICATO A PARTIRE DA UNA LOCAZIONE SUPERIORE ALLA 2202, ALTRIMENTI IL CONTENUTO DEL PROGRAMMA BASIC DIGITATO VERRA' SOVRASCRITTO
Ecco il dump esadecimale del testo del nostro programma
12 08 0A 00 41 24 B2 22 41 4C 42 45 52 54 4F 22 00 1B 08 14 00 4E 25 B2 31 00 2B 08 1E 00 99 20 22 45 53 45 4D 50 49 4F 22 00 3C 08 28 00 96 20 A5 20 46 28 58 29 B2 58 AC 32 00 59 08 32 00 81 20 49 B2 31 20 A4 20 32 3A 20 41 25 28 49 29 B2 49 AA 31 20 3A 20 82 00 00 00
I primi 2 byte di ogni istruzione indicano l'indirizzo d'inizio ( formato byte basso/alto ) della prossima istruzione in memoria.
I 2 byte successivi identificano la riga basic dell'istruzione ( formato byte basso/alto ).
Ogni istruzione termina col byte teminatore 0.
Tenendo conto di queste considerazioni, possiamo facilmente estrarre le righe che identificano ogni istruzione
CODICE NUMERICO ISTRUZIONE | CODICE BASIC ISTRUZIONE | NOTE |
12 08 0A 00 41 24 B2 22 41 4C 42 45 52 54 4F 22 | 10 A$="ALBERTO" | $22 è il codice Ascii di ", $24 di $ |
1B 08 14 00 4E 25 B2 31 | 20 N%=1 | $25 è il cod. Ascii di %, $B2 è il cod. Ascii di = |
2B 08 1E 00 99 20 22 45 53 45 4D 50 49 4F 22 | 30 PRINT "ESEMPIO" | $99 è il codice operativo dell'istruzione PRINT |
3C 08 28 00 96 20 A5 20 46 28 58 29 B2 58 AC 32 | 40 DEF FN F(X)=X*2 | $96 è il cod. operativo di DEF, $A5 è il cod. operativo di FN |
59 08 32 00 81 20 49 B2 31 20 A4 20 32 3A 20 41 25 28 49 29 B2 49 AA 31 20 3A 20 82 | 50 FOR I=1 TO 2: A%(I)=I+1 : NEXT | $81 è il cod. op. di FOR, A4 è il cod. operativo di TO, $3A è il cod. Ascii di :, $28 è il cod. Ascii di (, $29 è il cod. Ascii di ), $82 è il cod. operativo di NEXT |
I due 0 finali indicano al C64 un link a una linea basic inesistente;questo significa che il testo del programma Basic termina qui (ed è un informazione preziosa per le operazioni di LIST, di GOTO e di GOSUB).
Analizziamo ora l'area delle variabili non array (locazioni $085B-$087D). Il dump risulta essere
41 80 07 09 08 00 00 CE 80 00 01 00 00 00 C6 00 38 08
72 08 58 58 00 00 00 00 00 00 49 00 82 40 00 00 00
Sapendo che ogni variabile non array occupa 7 bytes, e che i primi 2 byte del descrittore contengono i primi 2 caratteri del nome della variabile stessa, si ha
DESCRITTORE VARIABILE | VARIABILE BASIC | NOTE |
41 80 07 09 08 00 00 | A | il secondo byte ha il bit 7 settato, perciò A è una stringa;07 indica la lunghezza della stringa;gli altri 2 byte indicano l'indirizzo di partenza della stringa nell'area del testo basic ( formato byte basso/alto ) |
CE 80 00 01 00 00 00 | N | i primi 2 byte hanno il bit 7 settato, quindi N è un numero intero;i due byte successivi indicano il valore della variabile intera ( formato byte basso/alto ) |
C6 00 38 08 72 08 58 | F | il primo byte ha il bit 7 settato, perciò F è una funzione;il terzo e quarto byte indicano l'indirizzo in cui è definita la funzione;i due bytes successivi indicano l'indirizzo di partenza del descrittore della variabile indipendente;l'ultimo byte indica il nome della variabile indipendente |
58 00 00 00 00 00 00 | X | i primi due byte indicano il nome della variabile |
49 00 82 40 00 00 00 | I | i primi due byte indicano il nome della variabile;i 2 byte successivi indicano che si tratta di una variabile di conteggio intera con valore finale 2 |
E ora, passiamo ad esaminare il contenuto dell'area delle variabili array (locazioni $087E-$089A)
C1 80 1D 00 01 00 0B 00 00 00 02 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Anche i descrittori degli array occupano 7 bytes in memoria, per cui
DESCRITTORE ARRAY | ARRAY BASIC | NOTE |
C1 80 1D 00 01 00 0B | A | I primi 2 byte hanno il bit 7 settato, quindi si tratta di un array di numeri interi;i 2 byte successivi indicano lo spiazzamento del prossimo array in quest'area ( formato byte basso/alto );il byte successivo indica il numero di dimensioni dell'array;il sesto byte indica il numero di righe dell'array (matrice), l'ultimo byte indica il numero di colonne dell'array (array monodimensionale o matrice) |
Gli altri byte contengono i valori degli elementi dell'array ( formato byte alto/basso )
DESCRITTORE ELEMENTO ARRAY |
VARIABILE BASIC | NOTE |
00 00 | A(0) | valore = 0 |
00 02 | A(1) | valore = 2 |
00 03 | A(2) | valore = 3 |
00 00 | A(3) | valore = 0 |
00 00 | A(4) | valore = 0 |
00 00 | A(5) | valore = 0 |
00 00 | A(6) | valore = 0 |
00 00 | A(7) | valore = 0 |
00 00 | A(8) | valore = 0 |
00 00 | A(9) | valore = 0 |
00 00 | A(10) | valore = 0 |
Da questa analisi dei programmi Basic e dei puntatori alle sezioni di memoria che lo costituiscono, è possibile imparare alcune "dritte":
Insomma... hai capito che l'unico limite sta solo nella tua inventiva e nella tua curiosità!