Al termine della nostra spiegazione sul funzionamento delle interruzioni nello Z80, consideriamo qui un esempio di gestione di una periferica di input. Per semplicità consideriamo solo il caso di interrupt mascherabile in modo 1:
Supponiamo che all’inizio il flip flop sia inizialmente azzerato: la linea Busy sarà bassa (segnalando in tale modo la disponibilità del sistema a ricevere dati). Quando la periferica avrà pronto un carattere da inviare, poiché il segnale Busy lo consente, predisporrà il dato sulla linea del dato e invierà un impulso (di breve durata) sulla linea Strobe.
Come si può dedurre dall’analisi dello schema in figura, l'impulso Strobe ottiene due effetti: carica il dato nel Registro di latch e porta a “1” il FF, tramite l’ingresso di Preset. La linea di Busy viene così portata alta automaticamente, indicando alla periferica che non possiamo ricevere altri dati, per il momento (infatti il dato ricevuto è attualmente nel registro dei latch, ma non e` stato ancora acquisito dal processore).
Il segnale EN, generato dalla decodifica dell’indirizzo del buffer 3-state, è collegato anche al clock del FF: la lettura del dato da parte del processore causerà, "via-hardware", l'azzeramento delle linee di Busy e di Ready, permettendo ora alla periferica di inviare un ulteriore dato e cancellando la segnalazione di dato pronto rivolta al processore stesso.
La linea Busy attraverso la porta NOT produce invece una richiesta di interrupt allo Z80, il quale potrà così intervenire a leggere il dato solo quando necessario, senza essere impegnato periodicamente ad interrogare la periferica in polling. Questo rappresenta un grosso vantaggio: il processore potrà tranquillamente continuare a lavorare su altri compiti senza doversi preoccupare di controllare periodicamente i dispositivi presenti, gestendo le richieste di questi soltanto all'atto del loro effettivo bisogno.
Qui sotto è mostrato il codice relativo al programma principale e alla routine di interrupt:
ORG 000h | ||
JP 0100h | ; salta al programma (il RESET fa iniziare il programma da 0000h) | |
; ******************* Interrupt Routine ******************* | ||
ORG 0038h | ; indirizzo a cui dev'essere caricata la routine | |
PUSH AF | ; salva sullo stack il contenuto di tutti i registri interni | |
PUSH BC | ||
PUSH DE | ||
PUSH HL | ||
PUSH IX | ||
PUSH IY | ||
IN A,(040h) | ; legge in A un dato dalla periferica | |
LD HL,0200h | ; legge l'indirizzo a cui salvare il dato | |
LD (HL), A | ; scrive il dato in memoria | |
INC HL | ; incrementa HL due volte | |
INC HL | ||
LD 0200h, HL | ; scrive in memoria l'indirizzo di salvataggio successivo | |
POP IY | ; ripristina il contenuto dei registri interni | |
POP IX | ; in ordine contrario rispetto al salvataggio | |
POP HL | ||
POP DE | ||
POP BC | ||
POP AF | ||
EI | ; abilita gli interrupt | |
RETI | ; termina la routine di gestione dell'interrupt | |
; ******************* Programma principale ******************* | ||
ORG 0100h | ||
LD HL,0200h | ; carica in 0200h l'indirizzo iniziale a cui bisogna salvare i dati (0202h) | |
LD (HL),0202h | ||
IM1 | ; setta l'interrupt di modo 1 | |
EI | ; abilita gli interrupt mascherabili | |
inizio: | ||
... | ; qui ci sono le istruzioni del programma principale | |
... | ||
JP inizio | ; il programma viene eseguito ciclicamente |
Sito realizzato in base al
template offerto da
http://www.graphixmania.it