Eccezioni ed Interruzioni nel MIPS
[Lezione di Laboratorio di Architetture; ho deciso di trattare questo argomento, vista la sua difficoltà]
Interruzioni ed eccezioni sono eventi che alterano il normale svolgimento del programma.
Quando si verificano, il programma viene interrotto e il controllo passa ad un programma di servizio che decide cosa fare.
Le eccezioni sono causate dal programma utente in esecuzione ed in genere segnalano che l'istruzione corrente ha creato problemi al processore mentre tentava di eseguirla. Le interruzioni
sono dovute, al contrario, a cause esterne ed in genere vengono utilizzate per l'I\O su periferiche.
L'architettura del MIPS prevede un apposito coprocessore - detto coprocessore zero - per gestire le interruzioni\eccezioni (reagisce ai segnali di interruzione\eccezione, memorizza nei
suoi registri se si tratta di una interruzione o di una eccezione, memorizza la periferica che l'ha generata nel caso di interruzioni, ecc.).
SPIM simula soltanto 4 registri di questo coprocessore:
-
status ($12): abilita o meno il coprocessore a servire le interruzioni\eccezioni;
il bit meno significativo è detto interrupt enable e se è alzato abilita le interruzioni;
il bit successivo è detto kernel\user e stabilisce se l'interruzione è avvenuta in modalità utente o sistema operativo; esistono dunque due livelli di
priorità: kernel ad alta priorità e user a bassa priorità. Quando la CPU sta servendo una interruzione kernel disabilita automaticamente tutte le interruzioni;
questi due bit vengono ripeturi 3 volte, tenendo una traccia storica delle interruzioni, shiftata via via a sinistra di due posizioni (LIFO).
nei bit dal 10 al 15 si trova la interrupt mask: ogni bit corrisponde all'abilitazione o meno delle interruzioni di una certa periferica; tastiera e schermo corrispondono ai due
bit meno significativi (forse).
-
cause ($13): identifica il tipo di interruzione e maschera le eccezioni;
i bit dal decimo al quindicesimo contengono le pending interrupt ovvero quelle interruzioni che si sono verificate mentre erano disabilitate le interruzioni e che quindi non
sono state ancora servite (maschera le interruzioni);
i bit dal 2 al 5 contengono l'exception code: un numero che identifica il tipo di interruzione\eccezione che si è verificata
Ad esempio:
0->interruzione: interruzione da periferica
4->eccezione: accesso ad un indirizzo di memoria inesistente con load
5->eccezione: accesso ad un indirizzo di memoria inesistente con store
6,7->eccezione: problemi col bus
8->eccezione: syscall
12->eccezione: overflow
In genere: se è zero è una interruzione, altrimenti è una eccezione. E' necessario distinguere i due casi, poichè vengono trattati in modo leggermente
diverso fra loro.
-
epc ($14): (exception program counter) contiene l'indirizzo di memoria dell'istruzione che ha causato l'eccezione\durante la quale si è verificata l'interruzione
-
baddvaddr ($8): (bad virtual address) se l'eccezione è stata causata da una istruzione che ha tentato di accedere ad un indirizzo di memoria non esistente, questo registro
contiene tale indirizzo.
A questi registri si accede tramite le istruzioni:
-
mfc0 rdest,rsrc : (move from coprocessor 0) copia il contenuto del registro rsrc del coprocessore 0 al registro rdest del processore principale
-
mtc0 rsrc,rdest : (move to coprocessor 0) viceversa
-
lwc0 rdest,address : analogo a lw
-
swc0 rsrc,address : analogo a sw
L'istruzione rfe (return from exception) ripristina il contenuto registro status del coprocessore zero al termine della gestione di una interruzione\eccezione.
Le direttive .ktext e .kdata sono analoghe a .text e .data , ma agiscono nell'area di memoria che finora abbiamo definito riservata al
kernel e quindi servono per scrivere il programma di servizio.
Il programma di servizio per interruzioni ed eccezioni è unico qualsiasi tipo esse siano (interruzioni ed eccezioni non sono vettorizzate: il programma in esecuzione salta allo
stesso entry point) ed è contenuto in un opportuno file.
In SPIM il file è "trap.handler" e gestisce solo le eccezioni.
In realtà, questo file svolge le veci di sistema operativo della macchina MIPS, gestendo eccezioni, caricando il programma che si vuole eseguire e chiudendolo. Per questo,
quando viene lanciato, SPIM carica "trap.handler" nella zona di memoria a partire dall'indirizzo 0x80000080 che finora abbiamo detto essere riservata al kernel.
Per gestire le eccezioni (non sono sicuro che sia giusto):
-
viene interrotta l'esecuzione dell'istruzione che ha causato l'eccezione
-
si passa a modo sistema operativo e il controllo va al programma di servizio nel quale bisogna:
-
salvare in EPC il conteuto del PC più quattro (è necessario tornare all'istruzione successiva a quella che ha causato l'eccezione, altrimenti si avrebbe di nuovo
l'eccezione)
-
salvare in memoria centrale il registro di stato del coprocessore zero; nota: non si può usare lo stack perchè l'eccezione potrebbe essere stata causata proprio da
un'errore sullo stack
-
caricare nei bit dal 2 al 5 del registro cause del coprocessore zero il codice dell'eccezione verificatasi
-
caricare nel PC della CPU l'indirizzo di "trap.handler"
-
servire l'eccezione
-
tornare al programma che era in esecuzione: rfe...i registri $k1 e $k0 della CPU...
oppure, in caso di errore irreversibile, terminare l'esecuzione del programma
Per gestire le interruzioni:
-
viene interrotta l'esecuzione dell'istruzione che ha causato l'eccezione
-
si passa a modo sistema operativo e il controllo va al programma di servizio nel quale bisogna:
-
caricare in EPC il contenuto del PC (non è necessario tornare all'istruzione successiva a quella durante la quale si è verificata l'interruzione - ATTENZIONE: per un
errore in trap.handler, anche in questo caso viene sommato 4)
-
salvare in memoria centrale il registro di stato del coprocessore zero
-
disattivare tutte le interruzioni: mettere a zero il bit del registro status
-
caricare nei bit dal 2 al 5 del registro cause del coprocessore zero il codice dell'interruzione verificatasi
-
caricare nella maschera del registro cause gli opportuni valori
-
caricare nel PC della CPU l'indirizzo di "trap.handler"
-
servire l'interruzione
-
tornare al programma che era in esecuzione: rfe...i registri $k1 e $k0 della CPU...
SPIM simula due periferiche che utilizzano l'I\O con interruzioni: tastiera (input) e schermo (output).
Queste funzionano tramite una estenzione all'esterno della memoria centrale (ai loro registri si accede tramite indirizzi di memoria centrale). ATTENZIONE: perchè ciò avvenga
bisogna attivare l'opzione "mapped I\O" del programma.
La tastiera lancia una interruzione subito dopo che è stato premuto un tasto.
I registri della tastiera che vengono simulati sono:
-
reciver control (0xffff0000):
il bit meno significativo è detto ready flag e, se è zero, indica che è stato digitato un carattere e che questo non è ancora stato letto; durante
questa fase, il carattere da leggere si trova nel registro reciver data;
il bit successivo indica se questa periferica può lanciare o meno interruzioni: non basta abilitare le interruzioni nel coporcessore zero, ma occorre abilitarle anche nella
periferica; ATTENZIONE: una volta deciso che alla tastiera si accede tramite interruzioni (alzando questo bit), non vi si può più accedere con la syscall
-
reciver data (0xffff0004):
il byte meno significativo contiene il carattere da leggere; appena viene letto, il ready flag del registro control viene alzato; ATTENZIONE: SPIM simula anche i ritardi nel
trsferimento di dati tastiera-calcolatore
Il monitor lancia una interruzione quando l'operazione di scrittura su schermo è terminata.
I registri dello schermo che vengono simulati sono:
-
transmitter control (0xffff0008):
il bit meno significativo è detto ready flag e, se è basso, indica che l'operazione di stampa a video è ancora in corso; durante questa fase, il carattere
da scrivere si trova nel registro transmitter data; quando è uno, la periferica è pronta ad accettare un nuovo carattere;
il bit successivo indica se questa periferica può lanciare o meno interruzioni: non basta abilitare le interruzioni nel coporcessore zero, ma occorre abilitarle anche nella
periferica; ATTENZIONE: una volta deciso che allo schermo si accede tramite interruzioni (alzando questo bit), non vi si può più accedere con la syscall
-
transmitter data (0xffff000c):
il byte meno significativo contiene il carattere da stampare; appena viene letto, il ready flag del registro control viene alzato; ATTENZIONE: SPIM simula anche i ritardi nel
trsferimento di dati calcolatore-schermo
|