Dal busy-wait all’interrupt
Tecniche di interazione con periferiche di I/O finora studiate sono:
Polling
Busy-waiting
Entrambe nella categoria sincrona.
Adesso analizzeremo per la categoria asincrona, la metodologia ad interrupt
Interrupt = interruzione.
La periferica, una volta avviata, procederà in maniera autonoma fino a che non avrà
completato la sua elaborazione ed interromperà il processore per avvertire che ha
terminato.
IL PROCESSORE DOPO AVER AVVIATO LA PERIFERICA CONTINUA LA
SUA NORMALE ESECUZIONE.
Ridurre overhead
Idea : utilizzare un meccanismo per segnalare al processore quando un
dispositivo di I/O richiede la sua attenzione=> le interruzioni.
Problemi:
1 - Evitare che il verificarsi di un’interruzione non provochi
interferenze indesiderate con il programma interrotto. =>
Salvataggio del contesto
2 - Una CPU può colloquiare con diversi devices, i quali devono essere
gestiti tramite routine specifiche => necessità di identificare
l’origine dell’interruzione
3 - Gestire richieste concorrenti di interruzione o interruzioni che
pervengono al processore mentre è già in corso un’interruzione (si
dovrà interrompere la routine di servizio del primo interrupt?).
=>definizione della gerarchia di priorità.
Fasi per la gestione dell’interrupt
a. Salvare lo stato del processo in esecuzione;
a. Identificare il programma
all'interruzione (driver);
di
servizio
a. Eseguire il programma di servizio;
a. Riprendere le attività lasciate in sospeso.
relativo
Context switch
Il contesto su cui opera un programma è costituito da:
•Il registo PC: contiene l’indirizzo dell’istruzione da cui dovrà essere ripresa
l’esecuzione del programma interrotto
•Il registro di stato
•I registri del modulo ALU, compresi i bit di condizione, che possono contenere
valori che il programma interrotto non ha terminato di elaborare. Gestendo
l’interruzione solo prima della fase di fetch, quando l’esecuzione dell’istruzione
precedente è completamente conclusa, possiamo evitare di memorizzare sia questi
registri, che lo stato del microprogramma.
Quando si verifica un’interruzione avviene una commutazione dal contesto del
programma interrotto a quello della routine di servizio.
Analogamente il contesto del programma interrotto deve essere ripristinato una volta
conclusa la routine di servizio.
Context switch 2
Occorre impedire che si verifichino altre interruzioni mentre sono in corso le
operazioni di commutazione, pena possibili incongruenze tra i valori presenti nei
registri di un contesto commutato solo parzialmente. Per fare ciò quando, al termine
dell’esecuzione di un’istruzione, il segnale IRQ=0 assume valore 1, il flip-flop I
viene settato a 0 via firmware. Inoltre il PD32 provvede a salvare nello stack lo SR e
il PC. Infine, nel PC è caricato l’indirizzo della routine di servizio del device che ha
richiesto l’interruzione.
Vcc
CPU
INT
IRQi-1
IRQi
IRQi+1
I
Modulo
interfaccia i-1
Modulo
interfaccia i
Modulo
interfaccia i+1
Riconoscimento interruzioni (IVN)
Periferica
Indirizzo
0
iniziale
1
2 prog.servizio
3 prima perife.
Indirizzo
4
iniziale
5
6 prog.servizio
7 seconda perife.
.
.
.
Indirizzo
4*i
iniziale
4*i+1
4*i+2 prog.servizio
4*i+3 perife. i-esima
INT
IACK
identificazione
periferica
PUSH …
.
.
.
Identificativo
Periferica x 4
POP
RTI
CPU
Priorità nella gestione interrupt
Introdurre una gerarchia per la gestione delle interruzioni consiste
essenzialmente nel definire dei meccanismi per:
•
•
Stabilire quale dispositivo debba essere servito per primo nel
caso di richieste contemporanee.
Consentire che il servizio di una interruzione possa essere a sua
volta interrotto da dispositivi più prioritari.
Tali meccanismi possono essere implementati via hardware (vedi
controllore interruzione a priorità) o, nel caso in cui non via un
supporto hardware dedicato, via software.
Priorità tra dispositivi
SERVIZIO
LIVELLO 2
FINE
INTERR.
PRIORITA’ CRESCENTE
SERVIZIO
LIVELLO 1
FINE
SERVIZIO
LIVELLO 0
FINE
INTERR.
RIPRESA
PROGRAMMA
PRINCIPALE
PROGRAMMA
PRINCIPALE
IR0
RIPRESA
SERVIZIO
IR2 IR1
t
Implementazione gerarchia
Gestire la gerarchia di priorità
delle interruzioni via software
Gestione priorità / 1
1) Stabilire quale dispositivo debba essere servito per
primo nel caso di richieste contemporanee.
Soluzione Hardware: si utilizza il segnale di IACK propagato in
daisy-chain per il riconoscimento dell’origine dell’interruzione. Così
facendo si introduce una priorità che è funzione della “distanza” dal
processore (la periferica più vicina ha priorità max).
Una soluzione alternativa implementabile via software è di
interrogare una dopo l’altro le periferiche (polling). L’ordine di
interrogazione definisce la priorità nella gestione delle interruzioni.
2) Consentire che il servizio di una interruzione possa essere
a sua volta interrotto da dispositivi più prioritari.
Abbiamo già studiato una soluzione hw a tale scopo.
Una possibile alternativa implementabile completamente tramite
software prevede che:
1. Ogni routine di servizio che prevede di essere interrotta (di priorità non max)
debba rendere il processore nuovamente interrompibile (SETI).
2. Per inibire i dispositivi a priorità minore, prima della SETI devono essere
opportunamente mascherati i flip-flop IM dei devices presenti, cosi’ da stabilire
da quali di questi, la routine di servizio possa essere interrotta.
3. Lo stato di interrompibilità, definito dai valori dei registri IM dei dispositivi al
momento dell’interruzione, fa parte del contesto del programma e va ripristinato
prima della RTI.
4. Prima di rendere interrompibile il processore deve essere rimossa la causa
dell’interruzione stessa, per evitare lo stack overflow. Si può raggiungere questo
scopo impedendo alla periferica di generare altre interruzioni con CLRIM.
Anche resettando il flip-flop di status (START,CLEAR) , rimuoviamo la causa
dell’interruzione, ma non inibiamo la periferica a generarne altri. Di
conseguenza possono sorgere problemi nel caso in cui un driver sia interrotto da
una nuova richiesta di interruzione a cui è associato lo stesso driver! Conflitti
sui dati e sul codice!
Gestione priorità / 3
2) Consentire che il servizio di una interruzione possa
essere a sua volta interrotto da dispositivi più prioritari.
5) Il ripristino del contesto deve avvenire con il processore non interrompibile, per
evitare le incongruenze che potrebbero sorgere a causa di una commutazione
incompleta.
Ad esempio, si consideri il driver periferica di priorità “media” (interrompibile
solo da device con priorità “alta” e non da device con priorità “bassa”)
…; codice del driver per device con priorità media
SET I; il processore è interrompibile
… ; fine codice, inizio ripristino contesto
setim dev_low_priority;
Se arriva un’interruzione da parte
pop …; altre op. ripristino contesto
del device a bassa priorità, questa
pop …;
viene subito servita ed è violata la
rti
gerarchia di priorità!
Gestione priorità / Esempio
3 rilevatori di movimento sono connessi al PD32. Quando viene
rilevato un movimento, i sensori generano una richiesta di
interruzione. Si vuole servire le interruzioni provenienti dai
sensori con la seguente priorità : Sensore0
Priorità
Sensore1
crescente
Sensore2
Driver sensore 0:
SETIM Sensore1
SETIM Sensore2
CLRIM Sensore0
SETI
….
….
CLRI
SETIM Sensore0
RTI
Driver sensore 1:
SETIM Sensore2
CLRIM Sensore1
CLRIM Sensore0
SETI
….
….
CLRI
SETIM Sensore0
SETIM Sensore1
RTI
Driver sensore 2:
….
….
RTI
Interruzioni & PD32
CODICE
CLEAR
OPERANDI
dev
CNZV P I
------
COMMENTO
Viene azzerato il flipflop STATUS del dev e
senza avviare
l'operazione.
SETIM
dev
------
Viene abilitato il device
dev ad inviare
interruzioni: IM=1
CLRIM
dev
------
JIM
dev, D1
------
JNIM
dev, D1
------
Viene disabilitato il
device dev ad inviare
interruzioni: IM=0
Se IM=1 salta alla
destinazione D1
Se IM=0 salta alla
destinazione D1
Riassumendo interruzioni PD32
• Periferica attiva il segnale di interruzione sul Control Bus di I/O
• Prima della fase di fetch il PD32 si preoccupa di controllare se ci
sono richieste pendenti di interruzione
• Legge l’IVN della periferica che ha lanciato l’interruzione, lo
moltiplica per 4 ed accedere all’area di memoria in cui è memorizzata
la routine di servizio (driver)
• All’attivazione del driver viene fatto un cambio di contesto, salvando
SR e PC. Viene effettuata l’istruzione CLRI inibendo la ricezione di
eventuali nuove interruzioni
• All’esecuzione del comando RTI al termine della routine viene fatta
automaticamente un ripristino di PC e SR
Progettiamo la nuova periferica per le
interruzioni tenendo presente il F/F di
mascheramento
Generica interfaccia di Input
Esercizio Interruzioni
Scambio di dati da periferica di input e periferica
di output
Si vuole realizzare lo scambio dei dati, in formato byte, tra una
periferica di input e una di output. Lo scambio avverrà attraverso
l’uso di un buffer, di un byte, allocato in RAM. La periferica di input
caricherà il buffer con il dato “prodotto”, quella di output lo scaricherà
“consumandolo”.
Si deve inoltre impedire che la periferica di input possa inviare un
nuovo dato, fino a che il buffer non sarà vuoto. Analogamente la
periferica di output non potrà consumare dati se il buffer è vuoto.
Salva R0 nello stack
Salva R0 nello stack
si
si
Buffer vuoto
Buffer pieno
no
Setta flag:
buffer pieno
INB input,buffer
START input
Output device ha
IM abilitato?
si
Ripristina contesto
ed esci
Inibisce INPUT dev
CLRIM input
Ripristina contesto
ed esci
no
SETIM output
no
Resetta flag:
buffer vuoto
OUTB buffer,output
START output
INPUT device ha
IM abilitato?
si
Ripristina contesto
ed esci
Inibisce OUTPUT dev
CLRIM output
Ripristina contesto
ed esci
no
SETIM input
; PROGRAMMA DIMOSTRATIVO SULL'USO DEI DEVICES
; Una periferica di input invia dati in un buffer di 1byte con il meccanismo degli
; interrupt, la periferica di output preleva il dato dal suddetto buffer
; Nel simulatore è necessario installare due periferiche:
; INPUT:
I/O=I, ind=30h, IVN=2
; OUTPUT:
I/O=O, ind=56h, IVN=7
org 400h
;INIZIO PROGRAMMA
input
equ 30h
;indirizzo periferica input
output equ 56h
;indiririzzo periferica output
flag
db 0
;flag =0 buffer vuoto, flag=1 buffer pieno
buffer equ 500h
;indirizzo buffer di scambio
code
;inizio istruzioni
seti
;abilita PD32 ad accettare interruzioni
setim input
;abilita periferica di input ad accettare interruzioni
setim output
;abilita periferica di output ad accettare interruzioni
start input
; avvio produzione del dato
start output
; avvio consumo del dato
main:
jmp main
; progr. Principale = loop infinito
;DRIVER DI INPUT
;Invia dati al buffer se questo e' pieno pone in attesa la periferica
;di input 0->IM, sblocca (se in attesa) la periferica di output 1->IM
driver 2, 600h
;Il driver della periferica con IVN=2
;inizia dall'ind. 600h
pinput: push r0
;salva contenuto di R0
movb flag,r0
;carica flag in R0
cmpb #1,r0
;controlla se buffer pieno
jz inibisci
;se pieno pongo in attesa la periferica di input
accetta:
;altrimenti invia dato
movb #1,flag
;pongo il flag=1 (buffer pieno)
inb input,buffer
;carico dato nel buffer
start input
;abilito device a generare un nuovo dato
jnim output,sbloccato
;se periferica di output e' in attesa la sblocco
jmp fineinp
;termina
inibisci: clrim input
;pone perif. input in attesa (buffer pieno)
fineinp: pop r0
;fine driver
rti
;ritorno da interruzione
sbloccato:setim output
;sblocco periferica output
jmp fineinp
;FINE DRIVER DI INPUT
;DRIVER DI OUTPUT
;Preleva dati dal buffer se questo e' vuoto pone in attesa la periferica
;di output 0->IM, sblocca (se in attesa) la periferica di input 1->IM
driver 7,700h
;Il driver della periferica di IVN=7
;inizia dall'indirizzo 700h
poutput:push r0
;salva contenuto di R0
movb flag,r0
;carica flag in R0
cmpb #0,r0
;il buffer e' vuoto?
jz blocca
;se vuoto pongo in attesa la periferica di output
consuma:
outb buffer,output
;altrimenti invio dato alla periferica di output
movb #0,flag
;pongo flag=0 (buffer vuoto)
start output
;abilito perif. output a consumare il dato
jnim input,sblocca
;se perif. di input 'in attesa' la sblocco
jmp esci
;termina
blocca: clrim output
;blocco perif. output (buffer vuoto)
esci:
pop r0
;termina prog.
rti
;ritorna da interruzione
sblocca:setim input
;sblocco input
jmp esci
;FINE DRIVER DI OUTPUT
end
;FINE PROGRAMMA
Costo aggiuntivo di un’operazione di I/O gestita
tramite interruzioni
Come nel precedente esempio, si ha un processore a 2GHZ e un hard
disk che trasferisce dati in blocchi da 4 longwords con un
throughput max di 16 MB/s. Si ipotizzi che il costo aggiuntivo per
ogni trasferimento, tenendo conto delle interruzioni, è pari a 500 cicli
di clock. Si trovi la frazione del processore utilizzata nel caso in cui
l’hard disk stia trasferendo dati per il 5% del suo tempo.
Frequenza di interrogazione=16 Mb/sec
16 byte/accesso
Cicli per secondo spesi= 500 * 106
% processore utilizzato= 500 * 106
2000 * 106
=1 M=10 6 accessi/sec
= 25%
Frazione del processore utilizzata in media=25 % * 5 %= 1,25%
La gestione dell’I/O tramite interrupts
solleva il processore dal peso di attendere
il verificarsi degli eventi di I/O.
Il costo aggiuntivo può essere comunque
intollerabile se i dispositivi con cui si
interagisce hanno a disposizione una
elevata larghezza di banda.
Un esempio
Una stanza e’ monitorata da 4 sensori di temperatura, i quali sono
pilotati da un PD32. Quest’ultimo controlla costantemente che il
valor medio della temperatura rilevata nella stanza sia compreso tra i
valori [Tmin-Tmax]. Nel caso in cui il valor medio della temperatura
non cada in tale intervallo, il microprocessore inviera’ un segnale di
allarme su un’apposita periferica (ALARM). Il segnale d’allarme
utilizzato e’ il valore 1 codificato con 8 bit. Se la temperatura ritorna
all’interno dell’intervallo [Tmin-Tmax], la CPU invia sulla periferica
il valore 0.
I sensori ritornano la temperatura misurata come un numero intero ad
8 bit, usando i decimi di gradi Celsius come unita’ di misura.
Scrivere il codice assembly per il controllo dei sensori di temperatura
e della periferica di allarme… utilizzando il meccanismo delle
interruzioni vettorizzate (piuttosto che il polling + busy wait).
Il codice (1)
org 400h
;INIZIO PROGRAMMA
sensore1 equ 0h
; indirizzo sensore1
sensore2 equ 1h
; indirizzo sensore2
sensore3 equ 2h
; indirizzo sensore3
sensore4 equ 3h
; indirizzo sensore4
alarm equ 4h
; indiririzzo periferica allarme
lowbound equ 200 ; T-min espresso in decimi di gradi Celsius
upbound equ 300 ; T-min espresso in decimi di gradi Celsius
media dl 0
; valore medio della temperatura rilevato
baseadd equ 2000h; buffer contenente la temperatura misurata
device dl 0
; indirizzo ultimo sensore che ha acquisito
switch db 0
; valore da spedire sulla periferica d’allarme
state
db 0
; stato allarme (0=off, 1=on)
code
;inizio istruzioni
main:
;...
jsr init
;...
loop:
jmp loop ;trucco per simulare il codice sul PD32, la periferica è libera per eventuali
elaborazioni
Il codice (2)
; subroutine di inizializzazione delle periferiche e avvio acquisizione
init:
push r0
push r1
; calcola il centro dell'intervallo [Tmin-Tmax] ...
movl #lowbound, R0
;
addl #upbound, R0
;
asrl #1, R0
; e lo memorizza in R0
movl #baseadd,R1
movl R0, (R1)
; aggiorna i buffer dei 4
movl R0, 4(R1)
; sensori con il valor medio
movl R0, 8(R1)
; dell’intervallo
movl R0, 12(R1) ;
movl R0, media
; inizializza la media
movb #0,state
; state memorizza lo stato (IN=0, OUT=1)
SETIM sensore1 ;
SETIM sensore2
SETIM sensore3
SETIM sensore4 ; abilita i sensori a inviare interruzioni
CLRIM alarm
; blocca la periferica d’allarme che al momento non serve
SETI
; abilita il processore a ricevere interruzioni
Il codice (3)
START sensore1;
START sensore2;
START sensore3;
START sensore4; avvia l’acquisizione dei dati dai sensori di temp.
pop r1
pop r0
ret
; fine subroutine init
; DRIVERS
driver 0, 1600h ; periferica con IVN 0 ha driver allocato a partire dall’ind 1600h
movl #sensore1, device
jsr GET
rti
driver 1, 1650h
movl #sensore2, device
jsr GET
rti
driver 2, 1700h …; … e 3
Il codice (4)
driver 4, 1800h
OUTB SWITCH, alarm
;invia il valore di switch sul buffer di alarm
start alarm
;avvia il consumo del dato
clrim alarm
;disabilita ulteriori interrupts della periferica
rti
; SUBROUTINE GET: ACQUISIZIONE DATI DALLA PERIFERICA IL CUI IND. E’
; E' SPECIFICATO NELLA VARIAB. DEVICE
GET:
PUSH r0
push r4
push r5
movl #baseadd, R0
movl device,r5
asll #2,r5 ; r5=device*4
ADDL r5, R0 ; r0=baseadd+device*4
asrl #2,r5 ;ripristina R5 all’address del device
INL r5, (R0); preleva il valore e lo mette in RAM nel corrispondente buffer
START r5 ; avvia nuova acquisizione
JSR NEWMEDIA
Il codice (5)
MOVL media, R5 ; carico la media aggiornata in R5
movb state, R4
CMPL #upbound , R5
JNC OUT
; upbound <= R5
CMPL #lowbound, R5;
JC OUT ;lowbound > R5
; altrimenti siamo nell'intervallo [TMIN-TMAX]...
CMPb #0, R4
; verifico se lo stato era IN=0 o OUT=1
JNZ eraout
;
exit:
pop r5
pop r4
pop r0
RET
eraout: MOvb #0 ,switch
SETIM alarm
movb #0, state
jmp exit
OUT:
CMPb #0, R4
; verifico se lo stato era IN=0 o OUT=1
JZ erain ;
jmp exit
Il codice (6)
erain: MOVb #1 ,switch
SETIM alarm
movb #1, state
jmp exit
; aggiorna la media in base ai valori presenti nelle 4 longwords a partire da baseadd
NEWMEDIA:
PUSH R0
PUSH R1
MOVL #baseadd,R1
XORL R0,R0
ADDL (R1),R0
ADDL 4(R1), R0
ADDL 8(R1), R0
ADDL 12(r1), R0
ASRL #2, R0
MOVL R0, media
POP R1
POP R0
RET
end
Scarica

Gestione delle subroutine