visita il sito del nostro sponsor





INTERRUZIONI


La scorsa puntata abbiamo parlato delle architetture scalari e pipeline, ora proseguiremo il discorso introducendo le istruzioni multiciclo ed una architettura didattica, il DLX, proposta da Hennessi e Patterson in un loro famoso libro.


Architetture pipeline con istruzioni multiciclo

Le cose si complicano ulteriormente nel caso siano presenti istruzioni multiciclo, principalemente dedicate all'esecuzioni di operazioni aritmetiche su grandezze di tipo floating point. La complicazione deriva dal fatto che più unità funzionali multiciclo possono essere attive contemporaneamente, il loro completamento può avvenire anche in ordine diverso da quello dettato dalla schedulazione del codice macchina ed inoltre ciascuna unità funzionale multiciclo può in qualsiasi istante dar luogo ad un interrupt. Consideriamo il seguente pseudo-codice:


DIVF F0, F2, F4
ADDF F10, F10, F8
SUBF F12, F12, F14





Non essendoci nè conflitti di struttura nè conflitti sui dati le 3 istruzioni FP possono essere eseguite in parallelo (o meglio sovrapponendo parzialmente i loro tempi di esecuzione). Notoriamente una divisione richiede più tempo di una somma algebrica, quindi la DIVF verrà certamente completata dopo la ADDF, ma può accadere che anche la SUBF sia completata prima, consideriamo questo caso. Dal punto di vista della normale esecuzione del codice la terminazione fuori ordine non crea problemi, ma quando consideriamo la possibilità che la SUBF provochi l'insorgere di una interruzione artimetica le cose si complicano, infatti se tale interrupt avviene dopo il completamento della ADDF lo stato della macchina è stato modificato solo parzialmente, in quanto la DIVF non ha ancora prodotto i suoi risultati. Non possiamo attendere lo svuotamento della pipe, perchè potrebbe volerci molto tempo ed alcuni interrupt richiedono una bassa latenza, inoltre nulla vieta che la DIFV a sua volta generi una interruzione, in questo modo l'ordine con cui le interruzioni si presentano alla CPU e diverso da quello che si avrebbe su una macchina non pipe; ma non possiamo neanche accettare di salvare uno stato parziale, perchè ripartendo dalla DIVF verrebbe necessariamente rieseguita anche la ADDF, che ricalcolerebbe il contenuto di F10 producendo un risultato errato!


Sono stati individuati 4 diverse soluzioni a tale problema:

1) Trascurare il problema gestendo le interruzioni come asincrone
2) I risultati delle istruzioni sono accodati in un'area temporanea e qui vi restano fino a quando non sono terminate tutte le istruzioni precedenti, a questo punto lo stato della macchina viene modificato in un sol colpo

3) Si memorizza uno stato parziale della macchina insieme alle informazioni per completare correttamente tutte le istruzioni ancora pendenti

4) Si continua ad avviare istruzioni multiciclo solo se si è certi che queste non causeranno interruzioni.

Esistono due varianti della tecnica numero 2: il file storico ed il banco dei registri di predizione. Il banco dei registri di predizione è un banco di registri che accoglie i risultati prodotti dalle operazioni multiciclo, se insorge una interruzione il suo contenuto viene invalidato e si riparte dall'istruzione successiva a quella che in precedenza ha portato ad un consolidamento dei dati, se non insorgono interruzioni il contenuto dei registri del banco principale utilizzati dalle istruzioni appena terminate viene aggiornato con i valori precedentemente stoccati nel banco di predizione.


Interruzioni nel DLX

Una della caratteristiche del processore DLX è di non possedere un registro Stack Pointer, di solito emulato dal registro R31, ciò impedisce di salvare in automatico lo stato minimo del processore (PSW e PC) nello stack quando insorge una interruzione, compito che viene demandato al Gestore delle Interruzioni. A questo punto sorge un problema: una volta che il PC è stato sovrascritto con l'indirizzo del gestore degli interrupt, quest'ultimo come recupera l'indirizzo dal quale riprendere l'esecuzione? Ancora una volta il problema è risolvibile con della logica aggiuntiva e precisamente viene aggiunto un nuovo registro, con fuzione di backup del PC pre-interruzione, detto IAR (Interrupt Address Register), per tanto l'indirizzo di ritorno è presente nell'IAR. E' evidente che al sopraggiungere di una nuova interruzione il vecchio contenuto va perso, per tanto ci sono solo 2 possibilità:


1) consentire una sola interruzione per volta (mascheramento)

2) il gestore memorizza il contenuto dell'IAR in un proprio stack, consentendo così le interruzioni nidificate

Per il resto il DLX si comporta come qualsiasi altra architettura scalare.


Interruzioni e Sistema Operativo

La principale fonte di interruzioni in un calcolatore è la richiesta di attezione della CPU da parte di una o più periferiche connesse. Ciascuna di esse viene pilotata da uno specifico sottoprogramma detto device driver ed è invocato dal gestore degli interrupt. Come fa il gestore a sapere quale periferica ha richiesto l'interruzione ed a quale sottoprogramma cedere il controllo della CPU? Una qualsiasi periferica genera una interruzione mediante un segnale sul BUS di controllo, si può usare una pista per ciascuna periferica (complica il layout dalla mainboard al crescere del numero delle periferiche ed è necessario un encoder all'interno della CPU) oppure una sola pista comune successivamente la CPU interroga tutte le periferiche connesse per individuare quella che ha richiesto la sua attenzione. Questa tecnica è detta polling, è molto semplice da realizzare ciò nonostate è da evitare perchè genera molto traffico sul bus e richiedere molto tempo se ci sono molte periferiche. Una versione più raffinata richiede però un minimo di protocollo di comunicazione: la CPU genera un segnale di ACK, sempre inviato sul bus di controllo, al quale risponde solo la periferica che generato l'interruzione. In realtà l'ACK assomiglia al token delle reti token ring, ovvero viene catturato dalla prima periferica sul bus, se questa non ha richiesto l'attenzione lo passa alla successiva e così via, in questo modo si instaura una rudimentale forma di priorità. La risposta della periferica consite nel proprio ID, in realtà in questo caso sul bus dati viaggiano più informazioni, dette interrupt vector, per esempio le informazioni potrebbero essere il motivo della richiesta dell'interrupt o, meglio ancora, il puntatore a una tabella contenente la descrizione dell'interrupt e l'indirizzo della sua routine di gestione. Una volta identificata la periferica passiamo alla seconda parte del nostro problema. Il gestore degli interrupt noto l'ID della periferica individua facilmente, mendiante un processo di mapping, il driver associato e di quest'ultimo invoca il sottoprogramma opportuno. Tutte le informazioni utili per il processo di mapping sono contenute in una tabella costruita dall'OS all'avvio del sistema.


Francesco De Napoli




visita il sito del nostro sponsor