Articolo pubblicato sul n. 63 di MCmicrocomputer (Edizioni Technimedia Srl - Roma) nel maggio 1987
Commodore 128: MMU sta per Memory Management Unit. Nella sua accezione più classica, una MMU serve . per tradurre un indirizzo logico in un indirizzo fisico. Molte volte, per motivi di praticità, sono demandati alla MMU altri compiti sempre inerenti la gestione della memoria. Con questo articolo vedremo cosa fa la MMU all'interno 128, oltre naturalmente a gestire i banchi di memoria discussi alcuni numeri fa.
Cos'è una MMU
Prima di entrare nel merito centovetttotesimo desideriamo dare alcuni chiarimenti circa l'accezione classica di MMU. Come descritto in Appunti di Informatica di MC numero 53 i calcolatori veri dispongono del meccanismo della memoria virtuale. Ciò al fine di ottimizzare l'utilizzo della memoria fisica, da parte dei vari processi in esecuzione. Semplicisticamente parlando, per ogni programma in esecuzione non è mantenuto in memoria centrale tutto il codice e tutti i dati, ma solo un sottoinsieme di questi necessari per l'elaborazione in quel momento. Se un determinato dato o un pezzo di codice è richiesto, ma non è contenuto in memoria, il sistema provvede a prelevarlo dalla memoria secondaria (dischi) eventualmente scaricando qualcos'altro per «fare posto». A causa di questo fatto, lo spazio di indirizzamento logico di un processo è in generale diverso dai veri e propri indirizzi di memoria e quindi (generalmente a tempo di esecuzione) si rende necessario un meccanismo di traduzione {indirizzo logico}/{indirizzo fisico}, per poter accedere al dato necessario. Se ad esempio il calcolatore in questione implementa la sua memoria virtuale a pagine, un processo in esecuzione potrebbe riferire un dato contenuto nella pagina logica 3, posizione 100. Dal momento che tale pagina logica, sempreché sia presente in memoria, potrebbe essere locata nella pagina fisica 5, l'indirizzo effettivo per prelevare il dato sarà pagina 5 locazione 100. Per attuare questa traduzione nel più breve tempo possibile (ogni accesso alla memoria deve essere tradotto) tale compito è interamente demandato ad una unità specializzata interposta tra processore e memoria denominata appunto MMU. Essa riceve l'indirizzo logico dal processore, esegue immediatamente la traduzione in indirizzo fisico, richiede il dato alla memoria e lo invia al processore che continua l'elaborazione normalmente, non essendosi accorto di nulla (per lui è stato un normale accesso in memoria). Oltre a questo, una MMU che si rispetti si occupa anche di smistare indirizzamenti a periferiche I/O memory mapped, a segnalare eventuali fault di pagina o di segmento, a gestire le interruzioni (questo assieme al processore).
L'MMU del 128
L'utilizzo di una MMU nel 128 non è certamente necessaria per i motivi sopra esposti. Trova la sua ragion d'essere dato che, tutti ormai lo sanno il processore di questo è capace di indirizzare solo 64 k, mentre la memoria disponibile tra ram e rom è molta di più. Come nel caso dei veri calcolatori avremo che un riferimento logico ad u!1a cella di memoria è dato dalla coppia (banco, posizione) mentre l'indirizzamento fisico... beh, quello proprio non è identificabile dato che la memoria fisica del 128 è sparsa per tutta la macchina sottoforma di· due banchi ram da 64 k l'uno, 16 k rom del sistema operativo, 32 k rom del Basic + monitor, generatore dei caratteri, memory mapped I/O ecc. Purtroppo, a livello hardware non è possibile che un programma locato in un banco possa fare riferimenti ad altri banchi, se non comandato alla MMU una commutazione di banco. Fortunatamente al livello di sistema operativo ciò non accade essendo disponibili delle apposite routine che permettono. di accedere a qualunque locazione di qualsiasi banco semplicemente effettuando opportune chiamate (cfr. MC n. 57, 128 da zero).
12 registri
Per impartire ordini alla MMU, che come vedremo non si occupa solo dei banchi nudi e crudi, si utilizzano 12 registri mappati a partire dall'indirizzo esadecimale $D500 del banco 15 (figura 1). In quella zona, come più volte ripetuto, è mappato l'I/O della macchina compreso quindi i registri per il suono, per i CIA, per il video ecc. I primi 5 registri della MMU sono inoltre mappati a partire dall'indirizzo esadecimale $FF00 di ogni banco: ciò per evitare che, una volta commutato un determinato banco di memoria, non sapremmo più come tornare indietro. Del primo registro, $FF00 o $0500, ne abbiamo già parlato nel numero 57, ed è lì che vi rimandiamo per maggiori chiarimenti. Esso è la vera cloche di comando della memoria dato che settando o resettando i suoi bit si può impostare qualsiasi configurazione, anche non prevista dal comando BANK del Basic. In figura 2 è mostrato tale registro e il significato dei suoi bit. I registri 1-4, locati a $D501-$0504 del banco 14, e disponibili solo in lettura anche a $FF01...04, servono per impostare delle preconfigurazioni di memoria, quelle che più useremo, richiamabili semplicemente accedendo ai registri copia corrispondenti. Ovvero, una volta settate le nostre configurazioni preferite a partire da $0501, per effettuare una commutazione sarà sufficiente accedere in scrittura nel registro copia corrispondente ($FF01 .. 04) ed essere così catapultati nella nuova configurazione di memoria. Il primo dei registri non disponibili sottoforma di copia è registro Modo di Configurazione (MCR) ed è raffigurato in figura 3. In esso possiamo leggere alcune informazioni a dire il vero non troppo interessanti: ad esempio se all'accensione il tasto 40/80 colonne era premuto o meno. Il bit O sembra l'unico degno di nota dato che controlla quale processore è attualmente al lavoro (Z80 o 8502). A partire dall'indirizzo $0506 le cose si fanno sempre più interessanti. Con questo primo registro (Registro Configurazione Ram, figura 4) è possibile configurare la memoria secondo altri punti di vista. Ad esempio possiamo cambiare la ram visibile dal Video Interface Chip.(40 colonne) impostando il banco l. E così possibile effettuare rapidi swap di schermo, sia in bassa che in alta risoluzione (oppure swap di sprite ... ) semplicemente allocando lo stesso spazio di memoria video sia nel banco O che nel banco l. Per effettuare lo swap sarà sufficiente comunicare alla MMU quale banco deve essere visibile dal VIC e il gioco è fatto. Sempre nel registro RCR troviamo la possibilità di definire aree comuni ai due banchi in testa o in coda, di dimensioni pari a 1,4,8 o 16 k byte. Per default, come detto sempre alcuni numeri fa, l'area di memoria comune assomma a l k, allocato a inizio memoria. Grazie a questo artificio, un programma giacente in una zona di memoria comune può ordinare commutazioni di configurazione alla MMU senza perdere il controllo del flusso.
Puntatori di pagina
Tramite la MMU del 128 è possibile definire pagine (non banchi, attenzione) O e l in qualsiasi punto della memoria del 128. Come si sa, il processore 8502 permette alcuni modi di indirizzamento solo in pagina O mentre lo stack di sistema è sempre allocato in pagina l. Ad esempio, per spostare grosse aree di memoria, chiunque abbia usato solo un po' il linguaggio macchina, conoscerà il modo di indirizzamento: LDA ($PP), Y dove $PP è un indirizzo in pagina O. Chi invece il linguaggio macchina lo usa spesso e volentieri, avrà notato come le locazioni libere in pagina O sono sempre poche (sono quasi tutte adoperate dal sistema) e occorre ricorrere a vari artifizi per rubarne qualcuna. in più. Utilizzando opportunamente la MMU possiamo tagliare la testa al toro definendo una nuova pagina O, ad esempio a partire dall'indirizzo $1000 e disporre così di 256 locazioni di tale tipo, tutte libere per noi. Ovvero, dopo aver impostato opportunamente la MMU, scrivendo:
STA $03
immetteremo il contenuto dell'accumulatore nella locazione $1003 e un accesso del tipo:
LDA ($03), Y
equivale a un LOA ($1003), addirittura non disponibile normalmente. Come detto prima, è possibile fare lo stesso giochetto anche per lo stack (pagina l) nel qual caso potremmo implementarne uno nuovo in qualsiasi punto della memoria. Ciò può essere utile non tanto come nuovo stack, ma come indirizzamento rapido di una qualsiasi area di memoria. Ad esempio per azzerare 256 byte a partire da $1000 allochiamo lì in nostro nuovo stack e, caricato nell'accumulatore il valore 0, non ci resta che dare 256 PHA per essere accontentati. Si noti che un «PHA» è ben più rapido di un normale «STA 1000, X» dato che il primo richiede 3 cicli di clock il secondo 5. In figura 5 sono mostrati i registri interessati, per la pagina 0 e 1. Le rispettive parti basse indicano la pagina riferita come pagina 0 o 1, mentre delle parti alte interessa solo il bit meno significativo nel quale indicheremo se ci riferiamo al banco 0 o 1 della ram. Attenzione a rimettere a posto stack, stack pointer e pagina 0 dopo l'uso: avremmo sicuramente effetti catastrofici dimenticandocene. Per finire, in figura 6, è mostrato il registro Versione, nel quale possiamo leggere (l) quanti banchi ram possiede il nostro 128 e, addirittura!, la versione della nostra MMU. Il massimo.
Kernal di I/O di Asnaghi Adriano - Mestre (VE)
La routine presente in questa sezione permette di definire i file sui quali l'utente intende operare. Per utilizzare un file in C 128 occorre passare alle routine specializzate il nome del file, i parametri di modo, il banco dove prelevare il nome stesso ed il banco dove prelevare (SA VE) o mettere (LO AD) il file stesso. Questi lavori sono eseguiti dalle seguenti routine. 1) Definisce il BANCO per il NOME e l'AREA di memoria. La routine è locata a $FF68 con salto a $F73F. I parametri da fornire sono: Accumulatore - indice di configurazione del banco per l'area di memoria; Reg. Y - indice di configurazione del banco per il nome del file. L'utente può anche fare a meno di utilizzare la routine se memorizza nelle locazioni di pagina zero $C6 e $C7 rispettivamente il banco per il nome del file e quello per l'area di memoria. 2) Definisce i PARAMETRI del file. La routine è locata a $FFBA con un salto a $F738. Essa utilizza i seguenti parametri: Accumulatore - numero logico del file; Reg. X - indirizzo device; Reg. Y - indirizzo secondario. I valori possono essere memorizzati direttamente dall'utente nelle posizioni $B8, $BA e $B9 di pagina zero. Per l'indirizzo di device si ha la seguente assegnazione: 0-3 tastiera, tape, user-port (RSS232), screen; 4-7 printer; 8-11 disk drive. Per l'indirizzo secondario si devono consultare i manuali relativi ai dispositivi usati. Per esempio un indirizzo secondario 0 per la stampante specifica il modo upper/graphic, ecc. 3) Definisce il NOME del file. La routine è locata a $FFBD con un salto a $F731. Essa utilizza i seguenti parametri: Accumulatore - lunghezza del nome del file; Reg. X - indirizzo basso del nome del file; Reg. Y - indirizzo alto del nome del file. I valori possono essere memorizzati direttamente dall'utente nelle posizioni $B7, $BB e $BC di pagina zero. 4) APRE il file. La routine è locata a $FFCO con un salto indiretto a $031 A che contiene l'indirizzo $EFBD. Nessun parametro è richiesto. Finché questa routine non è eseguita, non è possibile aprire canali di Input o Output. 5) Apre un canale di INPUT o di OUTPUT. Esiste una routine per l'INPUT 100cata a $FFC6 con salto indiretto a $031 E che contiene l'indirizzo $Fl06 ed una per l'OUTPUT locata a $FFC9 con salto relativo a $0320 che contiene l'indirizzo $FI4C. I parametri da passare sono: Reg. X - numero logico del file. Le routine ritornano un indicatore di errore nel Carry. Se esso è O l'operazione è avvenuta correttamente. 6) LEGGE un carattere dal canale di INPUT. La routine è locata a $FFCF con salto indiretto a $0324 che contiene l'indirizzo $EF06. La routine legge un carattere del caanale di input definito con la routine in 5). Nessun parametro deve essere passato. La routine ritorna il carattere letto nell'Accumulatore. 7) SCRIVE un carattere nel canale di OUTPUT. La routine è locata a $FFD2 con salto indiretto a $0326 che contiene l'indirizzo $EF79. La routine manda il carattere al canale di output definito con la routine in 5). Il carattere da scrivere deve essere passato nell'Accumulatore. Se si desidera invece mandare un carattere direttamente sul video, alla posizione corrente del cursore, basta utilizzare la routine locata a $C72D. 8) CHIUDE il file. La routine è locata a $FFC3 con salto indiretto a $031 C che contiene l'indirizzo $FFI8. La routine chiude il file logico il cui valore è specificato nell' Accumulatore. La routine ritorna un indicatore di errore nel Carry. Se esso è a O l'operazione si è conclusa correttamente. 9) CARICA un file in MEMORIA. La routine è locata a $FFD5 con salto a $F265. Prima di chiamare questa routine devono essere definiti i banchi per il nome del file e per l'area di memoria, il numero logico del file ed il nome del file stesso. I parametri da passare alla routine sono: Reg. X - indirizzo basso dell'area di memoria dove verrà caricato il file; Reg. Y - indirizzo alto dell'area di memoria dove verrà caricato il file. Nella figura A pubblichiamo un esempio di caricamento: 10) SALVA la memoria su di un FILE. La routine è locata a $FFD8 con salto a $F53E. Come per la routine precedente, anche questa deve essere chiamata dopo aver definito il banco per l'area di memoria, per il nome del file, ecc. I parametri da passare alla routine sono: Accumulatore - indirizzo di pagina zero di due byte contenenti rispettivamente l'indirizzo basso e alto indicanti l'indirizzo dell'inizio dell'area da salvare; Reg. X - indirizzo basso della fine dell' area da salvare; Reg. Y - indirizzo alto della fine dell'area da salvare. Nella figura B possiamo vedere un esempio di salvataggio.
Impaginato originale... Articolo pubblicato su www.digiTANTO.it - per ulteriori informazioni clicca qui |