Calcolatori elettronici/La gestione dei dispositivi input/output
Il processore non comunica direttamente (tramite il bus) con i periferici, ma ci sono dei moduli di interfaccia detti porte. Ogni porta contiene dei registri per lo scambio di dati e per le informazioni di stato, che hanno degli indirizzi specifici: siccome il processore conosce solo quegli indirizzi, è compito della porta far comunicare il processore e il periferico.
Alcuni circuiti di controllo gestiscono il funzionamento del registro. Un segnale di read/write e il decodificatore di indirizzi specificano rispettivamente il tipo di operazione e su quale registro vuole operare il processore.
Modalità di indirizzamento
[modifica | modifica sorgente]Modalità Memory-Mapped-IO
[modifica | modifica sorgente]In modalità Memory-Mapped-IO, le periferiche e la memoria sono mappate in un unico spazio di indirizzamento: ogni porta di periferica ha un indirizzo, e il processore comunica con le porte di periferica in modo analogo a come comunica con le celle di memoria; la logica di decodifica si occupa di accedere o alla memoria o alla periferica basandosi solamente sull'indirizzo. Sebbene sia supportata dall'8086, la scelta di questa modalità esclude la possibilità di utilizzare alcuni indirizzi di memoria, perché una cella di memoria e una porta di periferica non possono avere lo stesso indirizzo.
Modalità Isolated-IO
[modifica | modifica sorgente]La modalità Isolated-IO offre due spazi di indirizzamento distinti per la memoria e le periferiche. Il segnale IO/M specifica se l'indirizzo fornito dal processore è destinato alle periferiche o alla memoria, ma è un segnale aggiuntivo che deve essere decodificato.
Sincronizzazione
[modifica | modifica sorgente]La comunicazione tra la periferica e il processore deve avvenire alla velocità massima, e nessuno dei due deve penalizzare le prestazioni della comunicazione. Solitamente il processore è molto più veloce delle periferiche → serve un meccanismo di sincronizzazione.
I/O programmato
[modifica | modifica sorgente]L'I/O programmato è un meccanismo completamente software che si basa su un driver per la gestione completa della periferica. Il processore campiona (= polling) il segnale di ready della periferica finché non è pronta, in modo che il trasferimento di dati tramite i registri avvenga in modo sincronizzato.
Svantaggio: il codice che effettua il polling è un semplice ciclo da cui il processore non esce finché la periferica non è pronta → fino al termine del ciclo il processore è impegnato unicamente ad effettuare il polling in attesa che la periferica sia pronta.
Interrupt
[modifica | modifica sorgente]La richiesta di interruzione (o interrupt) è una situazione di "emergenza" in cui le periferiche chiedono al processore di interrompere l'esecuzione di una serie di istruzioni.
Quando la periferica è pronta, può richiamare l'attenzione del processore con una richiesta di interruzione: il segnale di INT viene campionato dal processore al termine dell'esecuzione di ogni istruzione. In questo modo, finché non arriva la richiesta di interruzione il processore può effettuare altre operazioni anziché passare tutto il tempo a testare il segnale di ready. Quando il processore rileva una richiesta di interruzione, passa alla procedura di servizio ISR, che è una serie di istruzioni in memoria che gestiscono la richiesta.
Il processore salva via hardware i contenuti correnti del PC e della parola di stato prima di richiamare la ISR. La ISR deve all'inizio salvare via software nello stack eventuali registri e parole di memoria utilizzati.
Si dice che l'interrupt è vettorizzato perché esiste una Interrupt Vector Table che associa ogni codice di interrupt all'indirizzo della corrispondente ISR.
L'Interrupt Controller gestisce il flusso di richieste di interruzione provenienti da più periferiche. L'Interrupt Acknowledge (INTA) è un segnale fornito dal processore all'Interrupt Controller per informarlo che è pronto a servire una periferica e che ha bisogno dell'indirizzo della periferica che ha fatto la richiesta → l'Interrupt Controller glielo invia tramite il bus dati.
Il bit I nei registri di stato STI e CLI può disattivare temporaneamente l'ascolto delle richieste di interruzione da parte del processore. L'Interrupt Controller può essere programmato in modo da disabilitare selettivamente le periferiche, oppure associando delle priorità alle periferiche in modo da servire prima le periferiche con maggiore priorità in caso di richieste simultanee. Inoltre, grazie alle priorità si può implementare una soluzione più complicata: la procedura di servizio di una periferica con una certa priorità può venire interrotta da un'altra periferica a priorità maggiore, mentre vengono escluse le periferiche a priorità minore.
La latenza di interrupt è il ritardo massimo di reazione alle richieste di interruzione, cioè il tempo massimo tra l'attivazione del segnale di INT e l'avvio della ISR. Il processore 8086 ha un'elevata latenza di interrupt (l'istruzione DIV
per esempio richiede più di 100 colpi di clock) → l'8086 non è adatto per le applicazioni real-time.
Altre cause di richiesta di interruzione
[modifica | modifica sorgente]Segnali di errore
[modifica | modifica sorgente]Le richieste di procedure di servizio possono essere scatenate da:
- un'eccezione incontrata da un'operazione svolta dal processore (ad es. divisione per zero);
- un'eccezione di illegal instruction, cioè il codice operativo letto dalla memoria non corrisponde ad alcuna istruzione esistente (ad es. il codice 00...0 spesso non corrisponde a un'istruzione esistente ma è riservato alla terminazione del programma);
- un errore di parità durante la lettura dalla memoria.
Segnali per il debug
[modifica | modifica sorgente]Il processore può essere impostato in modalità debug tramite il flag di interrupt:
- modalità trace: al termine di ogni istruzione (modalità single step), il processore richiama la procedura di servizio che gestisce l'operazione di debug;
- il programmatore può impostare un breakpoint su un'istruzione, che corrisponde a una istruzioni di salto alla procedura del programma di debug → il processore, dopo aver eseguito l'ultima istruzione, si ferma e salta alla procedura del programma di debug, dopodiché se necessario ritorna a eseguire il codice;
- alcune particolari strutture dati possono essere usate dal debugger per accedere a variabili e registri.
Eccezioni di privilegio
[modifica | modifica sorgente]Molti processori hanno due modalità di funzionamento:
- modalità supervisore: è prevista per il sistema operativo;
- modalità utente: è più limitata, ed esclude delle istruzioni critiche che se il programma in esecuzione tenta di eseguire scatenano le eccezioni di privilegio (ad es. l'istruzione
ALT
che blocca il processore deve essere richiamata solo dal sistema operativo).
Soluzione ibrida
[modifica | modifica sorgente]Una soluzione semplice ed economica prevede l'uso di una porta logica OR come Interrupt Controller semplificato. Per capire da quale periferica arriva la richiesta, il processore deve eseguire un'unica procedura di servizio che legga tutti i segnali di ready delle periferiche (polling).
DMA
[modifica | modifica sorgente]Il DMA Controller è un dispositivo, separato dal processore, in grado di gestire il trasferimento di grosse moli di dati tra una periferica e la memoria, ed evita che ogni singolo byte debba passare attraverso un registro del processore appesantendo quest'ultimo.
Devono esistere dei segnali di coordinamento tra il DMA Controller e:
- il processore: il DMA Controller è a sua volta una periferica in grado di gestire cicli di bus, cioè in grado di diventare il bus master → deve esistere un meccanismo di arbitraggio del bus (segnali DMA Request e DMA Acknowledge) in modo che il processore e il DMA Controller non facciano accesso al bus contemporaneamente;
- la periferica: il DMA Controller e la periferica sono collegati, oltre che attraverso il bus, anche in maniera diretta da un segnale bidirezionale di sincronizzazione, in modo che la periferica possa informare il DMA Controller quando è pronta (e viceversa).
Fasi di trasferimento
[modifica | modifica sorgente]- programmazione del trasferimento: il processore ordina al DMA Controller che è necessario effettuare un certo trasferimento specificando l'indirizzo di partenza del blocco da trasferire (tramite la porta IOAR), la dimensione del blocco da trasferire (porta DC), e la direzione del trasferimento (registro di controllo);
- il DMA Controller aspetta che la periferica sia pronta;
- la periferica comunica al DMA Controller che è pronta;
- segnale DMA Request: il DMA Controller fa sapere al processore che intende prendere il controllo del bus;
- segnale DMA Acknowledge: il processore informa il DMA Controller che si è sganciato dal bus;
- il DMA Controller diventa il bus master[1] e inizia il trasferimento;
- alla fine del trasferimento, il DMA Controller rilascia il bus e informa il processore che è pronto per un altro trasferimento.
Modi di funzionamento
[modifica | modifica sorgente]- burst transfer: il trasferimento avviene a blocchi, e la CPU non può accedere al bus fino a quando non è stato trasferito l'intero blocco → le prestazioni del sistema dipendono dall'efficienza delle cache del processore;
- cycle stealing: ogni tanto il DMA Controller cede temporaneamente il controller del bus al processore → il trasferimento è più lento, ma il processore non è bloccato per periodi troppo lunghi;
- transparent DMA: il DMA Controller è in grado di capire (tramite dei segnali di stato del bus) quando il processore sta usando il bus, e può sfruttare i momenti in cui il bus è libero per continuare il trasferimento → il processore è rallentato il meno possibile perché non c'è la negoziazione del bus.
Note
[modifica | modifica sorgente]- ↑ La memoria e la periferica non si accorgono che il bus master non è più il processore ma il DMA Controller.