ARCHITETTURA DEI CALCOLATORI MIPS E ASSEMBLER Gli ISA L’insieme di istruzioni che l’architettura hardware di un processore è in grado di interpretare viene detta ISA (Instruction Set Architecture) Linguaggio assembler e linguaggio macchina Il linguaggio assembler è un linguaggio simbolico che consente di programmare utilizzando le istruzioni del linguaggio macchina. Non a tutte le istruzioni in linguaggio assembler corrisponde un’unica istruzione in linguaggio macchina, esistono infatti pseudo-istruzioni (create per facilitare la programmazione) che vengono tradotte in una sequenza di operazioni macchina. L’operazione di traduzione è compiuta dall’assemblatore. Se nel codice sono presenti riferimenti simbolici in moduli (file) esterni o che dipendono dalla riallocazione del modulo nella memoria del programma è necessario anche il linker. Le istruzioni in linguaggio macchina sono composte da: codice operativo: Identifica l’istruzione e conseguentemente stabilisce come interpretare gli operandi riferimenti agli operandi: può essere un valore numerico, una locazione di memoria, un registro o può essere implicito nel codice operativo. Il MIPS MIPS appartiene alla famiglia di architetture RISC (Reduced Instruction Set Computer), che puntano a migliorare le prestazioni scomponendo operazioni complesse in operazioni semplici e di dimensione fissa. Ciò permette di poter progettare CPU più semplici. L’architettura RISC permette di usare direttamente solo i dati nei registri, sono quindi necessarie operazioni di load/store. Parole e indirizzamento Le parole MIPS occupano 32 bit (4 byte), quindi gli indirizzi (anch’essi di 32 bit) di due parole addicenti differiranno di 4 byte. Parole di 32 bit permettono uno spazio di indirizzamento per 232 bit=4GB di dati, ma 4GB sono 1Gparola=230 parole, quindi solo 30 bit bastano a indirizzare le parole, i 2 bit restanti dell’indirizzo identificano il byte all’interno della parola. Esistono due modalità di enumerazione dei byte nelle parole: Big-endian: l’indirizzo del byte più significativo specifica l’indirizzo di parola, quindi il byte meno significativo si trova all’indirizzo più alto Little-endian: l’indirizzo del byte meno significativo specifica l’indirizzo di parola, quindi il byte meno significativo si trova all’indirizzo più basso I registri MIPS usa un’architettura a 32(+3) registri numerati da 32 bit ciascuno, referenziabili col simbolo $ e organizzati in un Register File. Per indirizzare i 32 registri sono necessari 5 bit
Formato delle istruzioni e modalità di indirizzamento Tutte le istruzioni MIPS sono lunghe 32 bit, di cui i primi 6 rappresentano il codice operativo (OPCODE).
Tipo R (register): Riferimento agli operandi tramite registri (istruzioni aritmetico-logiche). È formato da 7 campi organizzati in: o op (opcode): identifica il tipo di istruzione [6 bit], nelle R è sempre settato a 0 o rs: registro contenente il primo operando sorgente [5 bit] o rt: registro contenente il secondo operando sorgente [5 bit] o rd: registro destinazione contenente il risultato [5 bit] o shamt (shift amount): scorrimento [5 bit] o funct: indica la variante dell’operazione [6 bit]
Tipo I (immediate): Il riferimento ad uno degli operandi si determina tramite un valore numerico presente nell’istruzione (istruzioni di accesso alla memoria o che usano costanti). I campi sono: o op (opcode): identifica il tipo di istruzione o rs: indica il registro sorgente o rt: indica il registro destinazione o indirizzo: contiene il valore dell’operando immediato (costanti), lo spiazzamento in byte (lw/sw), lo spiazzamento di una parola (branch) Per le istruzioni di salto condizionato, la modalità di indirizzamento è relativa al PC e l’offset è dato dalla distanza tra l’istruzione successiva (PC+4) e l’indirizzo dell’istruzione da eseguire dopo il salto, tranne che nelle lw/sw in cui l’offset è indicato in byte rispetto a PC+4 (se non è indicato un registro rispetto a cui calcolare l’offset, il MIPS lo calcola a partire dal global pointer). Il valore dell’ ultimo campo è esteso con segno
25 parole=100 byte (4*25) Partendo da PC+4
Tipo J (jump): dopo l’OPCODE, tutti i 26 bit identificano l’indirizzo di parola della destinazione (istruzioni di salto incondizionato). Visto che l’inizio di ogni parola è allineata e il primo byte di ogni parola è identificato dalla coppa di bit 00, questi possono essere omessi. I 4 bit mancanti vengono invece presi dai 4 bit più significativi dal PC nel momento di esecuzione dell’istruzione (se questi bit devono essere modificati se ne occupa il linker). La modalità di indirizzamento delle istruzioni J è quella pseudo-diretta
Le modalità di indirizzamento sono i modi consentiti dall’ISA per recuperare gli operandi, il MIPS supporta 5 modalità. Le diverse modalità di indirizzamento sono realizzate usando formati di istruzioni diverse
Istruzioni MIPS Lavorando l’ALU su 32 bit, nelle istruzioni I il valore numerico deve essere esteso da 16 a 32 bit, per istruzioni aritmetiche replico per i 16 bit restanti il bit di segno, per le operazioni logiche il numero viene esteso mettendo 16 bit a 0. Le operazioni svolte dall’ALU sono in complemento a 2, specificare una u nel comando indica operazioni unsigned, non riportano segnalazione di overflow e se c’è viene ignorata, queste operazioni sono usate per lavorare su indirizzi di memoria in quanto interi positivi. Le operazioni di shift spostano verso dx o sx i bit del registro, sposare a sinistra di n bit equivale a moltiplicare il valore iniziale per 2n Per caricare nei registri delle costanti o indirizzi a 32 bit (istruzioni in formato I consentono un massimo di 16 bit) si usano pseudo-istruzioni. Il numero viene spezzato in due blocchi da 16 bit, si usa l’istruzione lui (load upper immediate) che carica 16 bit nella parte più significativa del registro $x e imposta i rimanenti bit posti a 0, si usa poi l’istruzione ori (or immediate) per aggiungere gli ultimi 16 bit svolgendo appunto un or. La pseudo-istruzione è chiamata li (load immediate), mentre nel caso degli indirizzi è detta la (load address)
LA STRUTTURA DEI PROGRAMMI Memoria e processore sono basati su un modello di architettura Run-Time, che permette interoperabilità del codice definendo la collocazione e l’ingombro delle diverse classi di variabili, così come la destinazione di uso dei registri. Tutti i programmi in esecuzione sono divisi in tre parti: Codice (dichiarato nel programma): main e funzioni utente, il main termina sempre con un’istruzione di ritorno al sistema operativo Dati (dichiarato nel programma): variabili globali e dinamiche Stack (creato al lancio): aree di attivazione con indirizzi, parametri, registri salvati e variabili locali Le direttive all’assemblatore sono inserite nel file sorgente, sono: .data: direttiva che indica lo spazio di indirizzamento necessario al programma, calcolato sulla base delle variabili dichiarate in esso .text: direttiva con certo indirizzo di impianto e indica gli indirizzi dove sono allocate le istruzioni di un certo programma .globl main: contiene il main (un’etichetta che identifica in modo simbolico l’indirizzo della prima istruzione eseguita una volta lanciato il programma)
La struttura della memoria Il MIPS supporta un indirizzamento di memoria di 4GB, di cui 2GB sono riservati al sistema operativo (hanno un 1 nel bit più significativo, da 8000 0000esa in poi), il resto serve al programmatore per lo spazio utente del programma. Lo Stack cresce verso il basso (indirizzi decrescono), lo heap invece sale verso lo Stack e si occupa delle variabili dinamiche. Il Data Segment comincia 1000 0000esa di default se non è specificato un altro indirizzo, il Text Segment inizia di default a default 0040 0000esa. In assembler possono essere specificate delle etichette, queste sono identificate da un nome simbolico e rappresentano l’indirizzo di una variabile o di un’istruzione Per muoversi all’interno della memoria si fa riferimento al registro global pointer, che contiene l’indirizzo 1000 8000esa di default. Sommandogli o sottraendogli un offset (IN C2, dopo aver esteso col bit di segno il numero a 32 bit) ci si può muovere verso indirizzi più alti o più bassi. Es: un’offset di +8000esa fa spostare verso il basso di una parola in più rispetto a +8004esa perché l’1 all’inizio di entrambi i numeri deve essere moltiplicato per -1 ma il 4 del secondo offset è positivo, quindi lo spostamento verso il basso sarà minore. Con lo stesso principio funziona l’offset delle lw e sw, tuttavia se non viene indicato un registro di base, il valore verrà calcolato come global pointer+spiazzamento Variabili Le variabili globali vengono collocate ad indirizzi fissi che si trovano nella parte più bassa del data segment. Le variabili locali sono salvate nei registri o nello Stack (dipende dal loro utilizzo, se avessi l’istruzione P=&A, la variabile A non può essere messa in un registro perché i registri non hanno un indirizzo, quindi A viene messa nello Stack). Le variabili dinamiche sono salvate nello Heap Per utilizzare le variabili (a meno che non siano già nei registri) sono necessarie istruzioni di load per caricarle nei registri e di store per rimetterle in memoria una volta eseguiti i calcoli Il tipo delle variabili permette specificare quali operazioni possono essere eseguite su esse e quanto spazio bisogna riservarle in memoria Alle variabili possono essere associate delle etichette, e l’ordine con cui vengono salvate in memoria segue l’ordine con cui esse sono state dichiarate: C1000 000esa perché è la prima ad essere dichiarata (C è l’etichetta) A viene allineata a parola 1000 0004esa (i byte che finiscono 1,2,3 non vengono usati) Per allocare spazio senza inizializzare la variabile si usa la direttiva .space (n byte) I vettori si dichiarano .space (byte tipo * n elementi), sono allineati al primo byte libero
Esempi di codice
I SOTTOPROGRAMMI Gestione dello Stack MIPS Lo Stack Pointer (il cui valore è salvato nel registro $sp) punta sempre alla prima parola piena dello Stack (alla parola più in basso). Per salvare n parole nello stack, lo stack pointer deve essere decrementato di n parole in modo che esso si sposti verso il basso ingrandendo lo stack, questa operazione è fatta mediante una addiu $sp,$sp,-4*n (add unsigned, quindi con offset negativo scendo nella memoria), si possono a questo punto salvare le n parole usando le operazioni di sw. Per ridurre lo stack, lo stack pointer viene incrementato sempre con una addiu Sottoprogrammi e MIPS La chiamata ad un sottoprogramma comporta la creazione di un Record di Attivazione nello Stack, il quale viene deallocato alla fine del sottoprogramma, I record di attivazione sono impilati uno sopra l’altro (sotto in realtà, perché lo Stack cresce verso il basso), per cui il main, essendo il primo record di attivazione a essere creato, viene deallocato per ultimo. Ogni record di attivazione è associato a informazioni tra cui i parametri passati al sottoprogramma, le variabili locali, il valore restituito e l’indirizzo di ritorno alla funzione chiamante A livello ISA la chiamata a sottoprogramma di alto livello deve essere espansa in più istruzioni macchina: Il chiamante (Caller) gestisce la parte relativa al passaggio dei parametri Il chiamante attiva il sottoprogramma tramite l’istruzione di chiamata ISA
L’esecuzione dell’istruzione di chiamata ISA gestisce la parte relativa al salvataggio dell’indirizzo di ritorno (PC) e attiva il sottoprogramma Il chiamato (Callee) gestisce l’allocazione delle variabili locali e del valore restituito
Nel MIPS la chiamata ad un sottoprogramma avviene mediante l’operazione jal etichetta (Jump & Link) dove etichetta è il riferimento simbolico all’indirizzo della prima istruzione del sottoprogramma. Nel frattempo, nel registro $ra (Return Address) viene salvato l’indirizzo di ritorno, che non è altro che l’indirizzo dell’istruzione successiva alla chiamata nel programma chiamante. Il MIPS riserva i registri $a0 $a3 (Argument) per il passaggio alla funzione dei parametri, i registri $v0 e $v1 invece sono riservati ai valori di ritorno. Se i registri riservati non bastano, i parametri in più vengono passati mettendoli nello Stack. Una volta passato il controllo al sottoprogramma, questo ha il controllo dei registri. Per evitare che il sottoprogramma sovrascriva dati importanti del programma chiamante, alcuni registri del chiamante vengono salvati in memoria ogni volta che viene chiamato un sottoprogramma. Questi registri sono: $s0$s7, $fp (se utilizzato) e $ra (se ho annidamento di funzioni). L’ultima operazione del sottoprogramma riporta lo stack pointer al valore iniziale. Frame di attivazione e variabili nei sottoprogrammi Il prologo del chiamato può comportare il salvataggio di registri e l’allocazione di variabili locali, bisogna quindi calcolare la dimensione in byte dell’area richiesta: quest’area è l’area (frame) di attivazione della funzione Il Frame Pointer è un puntatore che indirizza la prima parola del sottoprogramma, è salvato nel registro $fp Per quanto riguarda le variabili locali della funzione: scalari o puntatori allora vengono messe, finché possibile, nei registri $s (nell’area di attivazione se devo referenziare (&) la variabile con un puntatore) vettori e struct sono salvati nell’area di attivazione. Gli elementi di un array sono impilati nello stack con indirizzi crescenti (V[n] sopra v[0]), in modo da aver l’indirizzo del primo elemento ad un indirizzo di memoria più basso Riassunto
Esempi di funzioni
ASSEMBLEGGIO E LINKING Per creare file eseguibili devo portare tutto il programma in un unico spazio di indirizzamento, anche se esso è diviso tra più file sorgente, questo è il compito principale del linker. La prima operazione compiuta dall’assemblatore è la creazione della Tabella dei Simboli del modulo, vengono associate: costanti definite da .eqv con il loro valore etichette del modulo (che definiscono variabili o indirizzi di salti) col proprio indirizzo. I valori degli indirizzi inseriti sono quelli del modulo rilocabili rispetto al segmento considerato (T EXT o DATA).
Inizia poi la traduzione del codice e viene creata la Tabella di Rilocazione del modulo. Un’istruzione è tradotta in modo incompleto se: il riferimento simbolico presente in essa è relativo a variabili del segmento .data o per variabili scalari la traduzione convenzionale è 0($gp) o per vettori (e altre) la traduzione è tramite la pseudoistruzione la è un’istruzione di salto di tipo J (non autorilocante): simbolo posto a 0 per convenzione il riferimento è relativo a simboli non presenti nella tabella dei simboli del modulo: simbolo posto a 0 per convenzione Se le variabili globali si spostano nel segmento dati, lo spiazzamento rispetto global pointer cambia, quindi gli indirizzi delle variabili globali devono essere rilocati dal linker. Se dei dati vengono inseriti nello stack ad un indirizzo più alto di una certa variabile, allora lo spiazzamento della variabile non deve essere ricalcolato perché lo spiazzamento rispetto allo stack pointer rimane costante. File oggetto di un modulo Intestazione: descrive le dimensioni del segmento testo e del segmento dati del modulo. Segmento testo: contiene il codice in linguaggio macchina delle procedure (o funzioni) del file sorgente. Queste procedure potrebbero essere non eseguibili a causa di riferimenti non risolti. Segmento dati statici: contiene una rappresentazione binaria dei dati definiti nel file sorgente. Anche i dati potrebbero essere incompleti a causa di riferimenti non risolti a etichette definite in altri file. Informazioni di rilocazione: identificano le istruzioni e le parole di dati che dipendono da indirizzi assoluti all’interno del file eseguibile del programma completo. La posizione di queste istruzioni dati deve essere modificata se parti del programma vengono spostate in memoria. Tabella dei simboli del modulo: associa un indirizzo alle etichette contenute nel Modulo sorgente: e contiene l’elenco dei riferimenti non risolti del modulo. Informazioni di debug
RETI COMBINATORIE Per rappresentare informazioni si usano segnali, nel mondo digitale i segnali devono essere discreti (poter assumere un numero finito di valori), nel caso informatico il segnale può assumere valori 0 e 1, per questo si parla segnali binari. È tuttavia necessario determinare un range in cui il valore misurato possa essere associato a uno 0 o ad un 1, poiché durante la trasmissione il segnale può essere modificato da rumore. Le grandezze fisiche usate da sistemi digitali per rappresentare l’informazione sono segnali elettrici, grandezze magnetiche o segnali ottici. Esistono due classi di dispositivi di elaborazione: reti combinatorie: ogni uscita all’istante t dipende esclusivamente dagli ingressi nello stesso istante reti sequenziali: l’uscita dipende sia dagli ingressi applicati in quell’istante sia dalla storia passata degli ingressi applicati alla rete I circuiti digitali sono descritti dal formalismo matematico che è l’algebra booleana, dalle espressioni logiche booleane è possibile ottenere il circuito che lo realizza tale condizione. Gli elementi dell’algebra di Boole sono: variabili di commutazione (singolo bit) operatori fondamentali (NOT (!) > AND (prodotto logico) > OR (somma logica)) proprietà degli operatori: (Prendendo un’espressione e sostituendo gli 1 con 0 e viceversa, e gli operatori tra loro, ottengo l’altra proprietà) LEGGE Identità Elemento nullo Idempotenza Inverso Commutativa Associativa Distributiva Assorbimento De Morgan
AND 1*A = A 0*A = 0 A*A = A A *!A = 0 AB=BA (A B) C = A (B C) AND rispetto a OR A*(B + C) = A*B + A*C A*(A + B) = A !(A*B) = !A + !B
OR 0+A=A 1+A=1 A+A=A A + !A = 1 A+B=B+A (A + B) + C = A + (B + C) OR rispetto a AND A + (B*C) = (A + B)*(A + C) A + A*B = A !(A + B) = !A*!B
Le ottimizzazioni che si ottengono applicando le proprietà degli operatori permettono di costruire circuiti più semplici Le tavole di verità sono tabelle che, data un’espressione logica e definito il numero n di operandi, su 2n righe forniscono tutti i possibili risultati per quell’espressione in base ad ogni possibile valore di entrata delle variabili Le porte logiche Le porte logiche sono i circuiti minimi per l’elaborazione di segnali binari e corrispondono agli operatori elementari dell’algebra di booleana. Le tre porte principali sono la porta NOT, la porta AND, la porta OR.
AND NOT
OR
NAND e NOR sono operatori funzionalmente completi, ovvero con essi si possono ricreare tutte e tre le porte principali
NOT
NAND
NOR
XOR (OR esclusivo)
X-NOR (NOR esclusivo)
Per realizzare porte a n ingressi si possono mettere porte dello stesso tipo in cascata
Il costo di realizzazione delle porte logiche (in termini di numero di transistor) e la velocità di commutazione consentono di calcolare un’indicazione del costo della rete logica che realizza un’espressione booleana e del ritardo di propagazione associato alla rete stessa Reti combinatorie A ogni funzione combinatoria, data come espressione booleana, si può sempre associare un circuito digitale formato da porte logiche, che viene chiamato rete combinatoria. La tabella delle verità di una rete combinatoria può essere ricavata per simulazione del funzionamento circuitale della rete combinatoria stessa.
F(A,B,C)=AB+!C
Una funzione combinatoria può ammettere più reti combinatorie equivalenti che la sintetizzano, che però possono avere costi diversi. La velocità di una rete combinatoria è calcolata seguendo il percorso più lento, considerando i tempi di elaborazione delle porte e di trasmissione della linea Sintesi delle reti combinatorie La sintesi delle reti combinatorie consiste nel ricavare il circuito logico a partire dalla tavola di verità dell’espressione del circuito considerato. Per ricavarle si usano le forme canoniche: 1a forma canonica (SoP): somma logica (OR) di tutti i termini prodotto (AND) delle variabili di ingresso corrispondenti agli 1 della funzione. Ogni termine prodotto (o mintermine) è costituito dal prodotto logico delle variabili di ingresso (letterale) prese in forma naturale se valgono 1, in forma complementata se valgono 0
f(a,b)
=
f1(a,b)=!a*b
+
f2(a,b)=ab
2a forma canonica (PoS): prodotto logico (AND) di tutti termini somma (OR)delle variabili di ingresso corrispondenti agli 0 della funzione. Ogni termine somma (o maxtermine) è costituito dalla somma logica delle variabili di ingresso (letterale) prese informa naturale se valgono 0, in forma complementata se valgono 1.
BLOCCHI FUNZIONALI COMBINATORI Il mutiplexer Il Multiplexer è una rete combinatoria con n ingressi, 2n ingressi dati e un’uscita e un’ingresso di selezione. Gli ingressi dati sono denominati numericamente. In base al bit di selezione, in uscita viene passato il bit del primo ingresso o del secondo ingresso. Per creare un multiplexer con ingresso a k bit si crea un parallelo di k multiplexer, e ognuno si occuperà di un bit. Il multiplexer più in basso si occupa del bit meno significativo
Il decoder Il decoder ha n ingressi e 2n uscite, entrambi numerati. In ingresso viene fornita una certa configurazione (numero dell’uscita), mentre in uscita avrò un 1 sulla linea ottenuta dal numero definito dalla configurazione. Il decoder è usato per indirizzare la memoria poiché con n bit posso indirizzare 2n parole di memoria
Il comparator Il comparator confronta gli ingressi e in base al risultato darà un 1 sull’uscita pertinente Gli adder Il full adder, a differenza dell’half adder, non è in grado di ricevere un riporto
L’ALU l’ALU è in grado di svolgere operazioni tra cui di AND, OR, somma e sottrazione. Il NOR è realizzato aggiungendo un multiplexer all’ingresso A, che permette di scegliere !A, per De Morgan il NOR viene creato usando !A nella porta AND. L’ALU esegue tutte le operazioni possibili in parallelo, ma in output si ha solo il valore desiderato grazie al multiplexer d’uscita. Per costruire un ALU a 32 bit, ne collego 32 da 1 bit in cascata, tuttavia quella che si occupa del bit più significativo è leggermente diversa, ha infatti un sistema di overflow detection (se bit di segno discorde da quello degli operandi) e in uscita porta anche il bit di segno mediante il canale SET Per realizzare il comando slt viene fatta una sottrazione tra due registri, se il risultato ha come primo bit un 1 allora $x2<$x3 e porto in uscita il valore 1 che andrà caricato nel registro $x1. L’ingresso LESS viene portato direttamente in uscita e deve essere 0 per i 31 bit più significativi di $x1 e 1 oppure 0 per il bit meno Significativo. Il bit Zero viene posto a 1 se il risultato dell’ALU vale 0, altrimenti è posto a 0 Per la sottrazione in C2 è necessario avere i segnali Binvert e Carryin a 1, mentre per le altre operazioni (eccetto il NOR) entrambi a 0. I due input sono dunque sostituiti con l’unico segnale Bnegate
Numeri relativi e reali I numeri relativi sono rappresentati in complemento a due I numeri reali sono rappresentati secondo lo standard per la rappresentazione in virgola mobile (IEEE 754)
RETI SEQUENZIALI Un circuito digitale è di tipo sequenziale se le sue uscite dipendono non solo dai valori correnti degli ingressi, ma anche da alcuni di quelli passati, quindi una stessa configurazione di ingresso applicata in due istanti di tempo successivi può produrre due valori di uscita differenti. Pertanto, un circuito digitale sequenziale (o rete sequenziale) è dotato, in ogni istante di tempo, di uno stato (memoria) che, insieme ai valori degli ingressi, ne determina il comportamento futuro. I circuiti sequenziali contengono sia elementi di memoria che circuiti combinatori I bistabili L’elemento elementare per realizzare circuiti sequenziali è il bistabile, che è in grado di memorizzare e mantenere un bit di informazione finché uno o più segnali di ingresso non ne forzano il cambiamento di stato. I bistabili sono classificati in: Asincroni: privi di un segnale di sincronizzazione, modificano lo stato rispondendo direttamente a eventi sui segnali di ingresso (più veloci ma anche più rari in quanto più complicati da progettare) Sincroni: sono sensibili ad un segnale di sincronizzazione (un clock), e la transizione da uno stato all’altro può avvenire solo in corrispondenza di eventi del segnale di controllo. Si dividono in: o bistabili sincroni controllati (gated latch) o flip flop: flip flop master slave (pulse triggered) flip flop edge-triggered (a fronte) Bistabili SR asincroni Sono dotati di due ingressi chiamati S (set) ed R (reset), e di due uscite che sono Q e !Q. A parità di ingressi R ed S, l’uscita Q ammette valori diversi a seconda del valore memorizzato (Q stesso). Come si vede dal disegno è presente una retroazione che influenza il risultato. NOR
NOR
NOR
NOR
Transizioni di stato Finché R ed S rimangono a 0, Q non varierà (rimane a 0 o 1) Se S=0 e R=1, qualunque sia il valore dello stato presente, Q diventa 0 e !Q diventa 1. Il nuovo stato è 0 (Q). Riportando R a 0 il valore di Q non cambia, lo stesso succedere se rimetto R=1 di nuovo Se S=1 e R=0, qualunque sia il valore dello stato presente, Q diventa 1 e !Q diventa 0. Il nuovo stato è 1 (Q) se S=R=1 il risultato non è deterministico in quanto dipenderà da quale ingresso sentirà prima la variazione del segnale. Lo stato R=S=1 è quindi vietato I diagrammi temporali I diagrammi temporali permettono di visualizzare il comportamento dei circuiti nel tempo, l’asse x riporta il tempo (diviso in istanti discreti) mentre l’asse y mostra i segnali logici assunti nel tempo
Il segnale di clock Il segnale di clock è un segnale binario, con andamento periodico nel tempo, deriva da una successione di impulsi in cui ogni impulso ha una larghezza costante e due impulsi consecutivi stanno a distanza costante. Il segnale di sincronizzazione permette che il bistabile possa cambiare stato solo in determinati istanti di tempo. La frequenza di clock è 1/periodo di clock. Bistabili sincroni e temporizzazione I bistabili si differenziano in base a due aspetti: La relazione ingresso-stato: definisce quando gli ingressi modificano lo stato interno del bistabile (quando gli ingressi sono efficaci), è detta anche tipo di temporizzazione: o Temporizzazione basata sul livello del segnale di sincronizzazione: Durante tutto l’intervallo di tempo in cui il segnale di controllo è attivo, qualsiasi variazione sui segnali di ingresso influenza il valore dello stato interno del bistabile (bistabili con commutazione a livello) o Temporizzazione basata sul fronte del segnale di controllo: Il valore dello stato interno del bistabile viene aggiornato solamente in corrispondenza di un fronte del segnale di controllo (bistabili con commutazione sul fronte di salita oppure di discesa).
La relazione stato-uscita: definisce quando lo stato aggiorna le uscite: o Commutazione basata sul livello del segnale di controllo: Durante tutto l’intervallo di tempo in cui il segnale di controllo è attivo un cambiamento dei segnali di ingresso modifica oltre allo stato interno anche le uscite. I bistabili con questa relazione stato-uscita sono denominati LATCH. Il segnale di controllo è solitamente chiamato enable. Le uscite cambiano quando cambiano gli ingressi o Commutazione basata sul fronte del segnale di controllo: Le uscite vengono aggiornate su un fronte del segnale di sincronismo. I bistabili con questa relazione stato-uscita sono denominati FLIP-FLOP. Le uscite cambiano in corrispondenza di un evento del clock. Inoltre:
Bistabile SR sincronizzato (SR-latch) Ha gli ingressi R, S in AND con un ingresso di sincronizzazione (di clock), ha per uscite Q (stato del bistabile) e !Q Se il clock vale 0, gli ingressi S e R non hanno alcun effetto (latch SR opaco) e il bistabile mantiene memorizzato il suo stato corrente Se il clock vale 1, gli ingressi S e R sono efficaci (latch SR trasparente) e il comportamento è quello del bistabile SR asincrono
Bistabile D sincronizzato (D-latch) Ha un ingresso D (stato che verrà memorizzato) e l’ingresso clock, ha per uscite Q (stato del bistabile) e !Q Se il clock vale 0, l’ingresso D non ha alcun effetto (latch D opaco) e il bistabile mantiene memorizzato il suo stato corrente Se il clock vale 1, l’ingresso D è efficace (latch D trasparente) e il bistabile memorizza il valore logico presente sull’ingresso D
Comandi di ripristino, ritardo di commutazione e trasparenza Tutti i tipi di bistabili dispongono di varianti dotate di un comando di ripristino CLR (Clear) che forza lo stato del bistabile a 0 re-inizializzandolo. Alcuni bistabili dispongono anche del comando di precarica PR (Preset), che forza lo stato del bistabile a 1. Di norma questi comandi sono asincroni, cioè agiscono immediatamente, senza attendere il clock Tutti i bistabili, come le porte logiche, presentano un ritardo di commutazione dell’uscita rispetto alla variazione degli ingressi o rispetto al fronte di clock che hanno indotto la transizione di stato. Il ritardo di commutazione dipende dalla tecnologia del bistabile I latch sincroni (SR o D) presentano, durante l’intervallo di tempo in cui il clock è attivo, il fenomeno di trasparenza delle uscite (indesiderato). In questo intervallo, se gli ingressi si modificano, le uscite seguono questa modifica. Per evitare il fenomeno di trasparenza si utilizzano i flip-flop (D o SR) che sono costituiti da due latch in cascata, in modo che lo stato possa modificare le uscite solo in corrispondenza di un evento (fronte) del segnale di controllo.
Flip-flop D master-slave È formato da una coppia di bistabili sincroni D in cascata con clock invertiti. Il bistabile principale campiona l’ingresso D=D1 durante l’intervallo alto del clock, lo emette sull’uscita Q1 e lo manda all’ingresso D2 del bistabile ausiliario. Il bistabile ausiliario campiona l’ingresso D2 durante l’intervallo basso del clock e lo emette sull’uscita Q2=Q. L’uscita generale Q può variare solo nell’istante del fronte di discesa del clock. Il bistabile SLAVE è in stato di trasparenza nell’intervallo basso del clock, mentre il bistabile MASTER è in stato di trasparenza nell’intervallo alto del clock. Se l’ingresso D varia durante l’intervallo alto del clock, il bistabile MASTER si comporta in modo trasparente, ma il bistabile SLAVE no, perché il suo clock si trova nell’intervallo basso
Flip-flop SR master-slave
Flip Flop edge-triggerd Limitano il problema di dover mantenere stabili gli ingressi al Flip-Flop per tutto il tempo in cui il livello del clock è alto/basso. L’evoluzione del Flip-Flop è controllata dal fronte di salita/discesa del clock (fronte attivo). Il fronte attivo agisce come un “segnale di campionamento” e in corrispondenza del fronte attivo i valori agli ingressi dell’elemento di stato vengono campionati, memorizzati e quindi presentati in uscita
BLOCCHI SEQUENZIALI Registri parallelo I registri parallelo sono vettori di flip-flop D, con n ingressi, n uscite e un ingresso di clock. Ad ogni ciclo di clock, il registro legge e memorizza nel suo stato la parola di n bit presente in ingresso, e la presenta sulle n uscite nel ciclo successivo. Non posso usare i latch D perché il fenomeno di trasparenza durante il livello alto di clock non permetterebbe al circuito di funzionare come registro
Una variante dei registri parallelo sono i registri parallelo con comando di caricamento. I segnali possono essere caricati sulle uscite soltanto se un segnale di load è a 1, nel caso load sia 0 il registro mantiene in uscita il proprio stato.
Nei registri parallelo possono essere integrati anche i comandi di CLR e PR per la re-inizializzazione, un registro parallelo che ha tutti questi ingressi è detto registro parallelo universale Registri di scorrimento Sono formati da flip-flop D collegati in cascata e hanno un ingresso seriale S. Ad ogni ciclo di clock la parola memorizzata viene spostata a destra di un bit, il bit a destra viene perso mentre il nuovo bit più a sinistra viene portato dall’ingresso S. I registri di scorrimento detti universali son dotati di un comando di scelta della direzione di scorrimento. Anche i registri di scorrimento possono disporre degli ingressi CLR e PR. I registri parallelo/scorrimento riuniscono le funzioni dei due registri visti finora
Pilotaggio delle uscite L’organizzazione della memoria in banchi comporta che più registri siano collegati alla stessa linea d’uscita, sono quindi necessari dei circuiti di pilotaggio delle uscite atti a evitare che i segnali inviati da un registro interferiscano con quelli di un altro registro. Questi circuiti sono chiamati buffer tri-state Le uscite tri-state sono gestite da un ingresso di controllo (Output Enable) che, se non attivo, forza uno stato di alta impedenza nel circuito. Lo stato di alta impedenza provoca l’isolamento elettrico dell’uscita, mentre lo stato di bassa impedenza consente di avere in uscita uno 0 o un 1
Il banco di registri (Register File) I registri vengono organizzati in una struttura a vettore, chiamata banco di registri o register file (RF). Sui registri deve essere possibile svolgere operazioni di load (presentare in uscita i bit contenuti nel registro) e di store (scrivere il nuovo valore dentro il registro). I segnali che indicano l’operazione da svolgere arrivano al registro tramite delle porte di lettura/scrittura (esistono porte con duplice funzione). Il register file del MIPS è dotato di 2 porte di lettura e 1 di scrittura indipendenti, è pertanto possibile accedere (con una temporizzazione adatta) a tre registri contemporaneamente. Porte di lettura Quando si legge da un registro, questo non viene modificato. Inoltre, il sistema procede ad una lettura per ogni ciclo di clock, eliminando la necessità di un comando di lettura esplicito. Le porte di lettura sono create mediante l’utilizzo di multiplexer, il segnale di Read Register è il segnale di controllo del multiplexer (indirizzo del registro) e permette di portare in uscita il valore contenuto nel registro specificato. Avendo il RF del MIPS due porte di lettura, avrò due segnali di Read Register che controllano due multiplexer indipendenti. Con un segnale di 5 bit si possono distinguere i 32 registri. Un’alternativa ai multiplexer è l’utilizzo dei decoder, in questo caso l’attivazione della linea selezionata dal decoder è usata come segnale di Output Enable per il buffer tri-state, e il contenuto del registro è portato in uscita
Porte di scrittura Per identificare il registro in cui scrivere il dato si usa un decoder, usando l’indirizzo a 5 bit del registro come segnale di controllo. Tuttavia, l’operazione di scrittura è un’operazione distruttiva e quindi per evitare perdite di dati, essa può avvenire solamente se in input al RF c’è un segnale di Write attivo. Mettendo in AND il segnale Write con le uscite del decoder è possibile scrivere in un determinato registro solo se l’operazione di scrittura è permessa in quel ciclo di clock Per gestire la lettura e la scrittura di un registro nello stesso ciclo di clock, la scrittura avviene sul fronte di salita mentre il dato è presentato in uscita sul fronte di discesa.
Interfaccia di memoria La memoria è un blocco sequenziale SRAM con struttura a vettore. I componenti integrati della memoria sono chiamati Chip. Per effettuare operazioni con la memoria, essa deve disporre di diversi segnali: Address: identifica l’indirizzo della parola di memoria su cui operare Chip Select (CS): se attivo il chip viene attivato, altrimenti è disattivato. Nelle memorie è possibile attivare/disattivare gruppi di chip Output Enable (OE): se attivo le uscite sono abilitate, altrimenti sono isolate Write Enable (WE): se attivo permette la scrittura, altrimenti i dati rimangono invariati Data in/out: usate per la lettura/scrittura dei dati Se sia WE che OE sono poste a 0 allora non si sta accedendo alla memoria.
Struttura della memoria (matrice di bistabili e matrice di componenti) Matrice di bistabili: Dato l’indirizzo di memoria, il decoder attiva una linea di parola (le righe rappresentano le parole) e per ogni colonna viene salvato un bit della parola. La porta AND davanti all’inizio di ogni linea di parola abilita la scrittura solo con segnale di WE attivo. Ogni bistabile ha la sua uscita tri-state in quanto la linea di uscita dei bit in una certa posizione è condivisa. Matrice di componenti: sono formate da blocchi di chip SRAM da 4K parole di 1024 bit ciascuna per ottenere una memoria da 4Mparole ognuna di 8 bit (quindi devo avere 8 uscite). Le parole sono divise tra i chip e alla stessa posizione nel chip corrispondono i bit di una stessa parola. Per riconoscere la parola serve un indirizzo da 22 bit, i primi 12 identificano la parola tra le 4K, gli altri 10 identificano il bit tra i 1024 della parola
Tipi di memorie DRAM (Dynamic RAM): sono memorie elettroniche volatili che memorizzano informazioni in un condensatore il cui accesso avviene tramite un transistor. A causa della tendenza dei condensatori a scaricarsi col tempo, è necessario un re fresh periodico. Bastando un transistor per bit, le DRAM sono molto compatte. SRAM (Static RAM): l’informazione è memorizzata da un minimo di 2 transistor, finché sono alimentate non ho bisognio di operazioni di refresh come per le DRAM. Richiedendo più transistor , pertanto sono meno compatte delle DRAM e consumano di più, tuttavia sono più veloci e quindi vengono usate per costruire le cache ROM (Read Only Memory): sono memorie non volatile realizzate da una matrice di transistor, hanno grande capacità
IL PROCESSORE Architettura base del processore Il processore MIPS separa la Memoria Istruzioni (MI, usta solo in lettura) dalla Memoria Dati (MA). In base all’istruzione da eseguire vengono indicati i registri da usare come operandi, per questo la Memoria Istruzioni è direttamente collegata al Register File. Il Register File (RF) è formato dai 32 registri definiti dal MIPS. Ha 4 ingressi (2 segnali di Register Read, 1 segnale di Register Write, 1 ingresso per i dati in scrittura) e 2 uscite (contenuto dei 2 registri letti). L’ALU si occupa di calcolare il risultato di operazioni aritmetico-logiche (R/I aritmetiche), indirizzi di memoria (load/store) e confronti (salti condizionati). Il risultato ottenuto può essere scritto in un registro del RF (R/I aritmetiche), essere usato come indirizzo di lettura/scrittura della Memoria Dati (load/store) o per calcolare l’indirizzo della prossima istruzione (salti condizionati) Fetch delle istruzioni Per la fase di fetch delle istruzioni entrano in gioco la Memoria Istruzioni, il PC (che contiene l’indirizzo dell’istruzione corrente) e un sommatore che permette di calcolare la prossima istruzione (PC+4) Esecuzione di istruzioni aritmetico logiche (tipo R) 1. Prelievo istruzione dalla memoria istruzioni e incremento del PC. 2. Lettura dei 2 registri sorgente ($y e $z) dal banco dei registri (Register File), utilizzando i bit [25-21] e [20 -16] per selezionare i registri
3. Operazione dell’ALU sui dati letti dal banco dei registri, utilizzando il campo funct per realizzare la funzione aritmetico-logica corretta (opcode R sempre 000000). 4. Scrittura del risultato dell’ALU nel banco dei registri utilizzando i bit [15-11] dell’istruzione per selezionare il registro destinazione ($x) op $x,$y,$z Per eseguire istruzioni aritmetico-logiche, all’ALU deve essere fornito in ingresso il valore di due registri operandi provenienti dal Register File, oltre che ad un segnale per specificare l’operazione in output (OP_ALU) questo segnale dipende dal codice operativo dell’istruzione). Per leggere dal RF, è necessario fornirgli i due segnali di Register Read (RegRead) formati da 5 bit, che permettono di identificare univocamente i registri. Il risultato ottenuto dall’ALU deve essere scritto nel RF, per farlo però deve venir attivato il segnale di Register Write (RegWrite)
Esecuzione di istruzioni di Load (tipo I) 1. Prelievo istruzione dalla memoria istruzioni e incremento del PC 2. Lettura del registro base ($y) dal banco dei registri, bit [25-21] 3. Operazione dell’ALU per calcolare la somma del valore letto dal registro base e dei 16 bit meno significativi dell’istruzione estesi in segno (campo offset) 4. Prelievo del dato nella memoria dati utilizzando come indirizzo di lettura il risultato dell’ALU 5. Scrittura del dato proveniente dalla memoria nel banco dei registri; il registro destinazione ($x) è indicato dai bit [20-16] dell’istruzione. lw $x,offset($y)
Esecuzione di istruzioni di Store (tipo I) 1. Prelievo istruzione dalla memoria istruzioni e incremento del PC 2. Lettura del registro base ($y), bit [25-21], e del registro sorgente ($x) dal banco dei registri; il registro sorgente è indicato dai bit [20-16] dell’istruzione 3. Operazione dell’ALU per calcolare la somma del valore letto dal registro base e dei 16 bit meno significativi dell’istruzione estesi in segno (offset) 4. Scrittura del dato proveniente dal registro sorgente ($x) nella memoria dati utilizzando come indirizzo di scrittura il risultato dell’ALU
sw $x,offset($y)
Load/store combinati
Esecuzione di istruzioni con operandi immediati (tipo I) 1. Prelievo istruzione dalla memoria istruzioni e incremento del PC 2. Lettura del registro sorgente ($y) dal banco dei registri, bit [25-21] 3. Operazione dell’ALU per calcolare la somma del valore letto dal registro sorgente e dei 16 bit meno significativi dell’istruzione estesi in segno (campo immediato) 4. Scrittura del risultato dell’ALU nel banco dei registri; il registro destinazione ($x) è indicato dai bit [2016] dell’istruzione. addi $x,$y, 22 Esecuzione di salti condizionati (tipo I) 1. Prelievo istruzione dalla memoria istruzioni e incremento del PC 2. Lettura dei 2 registri sorgente ($x e $y) dal banco dei registri RF, bit [25-21] e [20 -16] 3. Operazione dell’ALU per effettuare la sottrazione tra i valori letti dal banco dei registri. Il valore (PC+4) viene sommato ai 16 bit meno significativi dell’istruzione estesi in segno (offset); il risultato è l’indirizzo di destinazione del salto (Branch Target Address). Poiché lo spiazzamento dell’istruzione branch è in parole, prima di sommare lo spiazzamento (offset) con il contenuto di (PC+4), beq $x,$y,offset bisogna moltiplicare per 4 il valore dello spiazzamento (in byte), è quindi presente uno shifter di valore 2 dopo l’estensore di segno 4. L’uscita Zero dell’ALU viene utilizzata per decidere quale valore debba essere memorizzato nel PC: (PC+4) oppure (PC+4+offset). Se Zero=1 (se la sottrazione dà 0 quindi i registri sono uguali) salto.
Schema dei passi delle istruzioni
Processore completo In un unico ciclo di clock nessuna risorsa può essere utilizzata più di una volta per istruzione, per cui ogni risorsa di cui si abbia bisogno più di una volta deve essere duplicata. Per creare il processore completo quindi alcune unità funzionali devono essere duplicate per permettere lì esecuzione di tutte le istruzioni, altre invece possono essere condivise da differenti flussi di istruzioni (in questo caso si interpone un multilexer). Alcuni esempi sono: Il secondo ingresso dell’ALU è il contenuto di un registro (istruzione di tipo R) oppure la metà meno significativa dell’istruzione (istruzione load/store o aritmetiche immediate). Introduco un MUX A al secondo ingresso dell’ALU Il valore scritto nel registro destinazione proviene dal risultato dell’ALU (istruzione tipo R o aritmetica immediata) oppure dalla Memoria Dati (istruzione load). Introduco un MUX C all’ingresso dei Dati per Scrittura del RF Il numero del registro in cui si vuole scrivere il risultato è indicato da diversi campi (i bit [15-11] per le istruzioni di tipo R e bit [20-16] per istruzioni di load e aritmetiche immediate). Introduco un MUX D all’ingresso del Registro Scrittura del RF
I segnali di controllo Bisogna ora aggiungere al processore un’unità di controllo, che si occuperà di generare i segnali di controllo in ingresso alle unità funzionali del processore. Il valore assunto dai segnali è legato ad ogni ciclo al codice operativo dell’istruzione in esecuzione. Il segnale X significa che quel componente non è rilevante per l’istruzione, quindi non succederà niente a prescindere dal segnale di controllo scelto (nota: Src=Source)
Implementazione della bne L’istruzione beq porta al salto nel caso in cui i due registri confrontati siano uguali, ovvero se il bit di Zero ottenuto dall’ALU è 1. Per implementarlo bisogna modificare la logica che genera PCsrc, sapendo che l’opcode di beq è 000100 mentre quello di bne è 000101. Si ottiene: PCsrc = (notOp_code [26] and Zero and Branch) or (Op_code [26] and notZero and Branch) Clock del processore Il clock del processore deve essere implementato in modo che per ogni ciclo venga possa essere portata a termine una (e una sola) istruzione. Istruzioni diverse richiedono tempi di esecuzione diversi, quindi il clock deve essere stabilito relativamente all’istruzione più lunga
PROCESSORE PIPELINE La tecnica di pipelining consiste nel migliorare le prestazioni di un processore sovrapponendo istruzioni appartenenti ad un flusso di esecuzione sequenziale. Le istruzioni vengono eseguite dal processore con uno sfasamento pari ad uno stadio dell’esecuzione dell’istruzione, che idealmente coincide con un ciclo di clock. Perché la pipeline funzioni, tutti gli stadi devono essere di pari lunghezza (ciclo di pipeline), questo significa che i passi che richiedono meno tempo per essere eseguiti (o che non ci sono) rimarranno in attesa fino alla fine del ciclo di clock. La pipeline peggiora la latenza (tempo di esecuzione) di una individuale istruzione, tuttavia incrementa di molto il troughput (numero di operazioni per unità di tempo) Nel MIPS l’istruzione più lunga è la Load, che richiede 5 passi, il cui passo più lungo richiede 200ps, quindi la pipeline MIPS dovrà essere formata da 5 stadi tutti lunghi 200ps, a prescindere dall’istruzione in esecuzione. Se tutti gli stadi di esecuzione fossero perfettamente bilanciati questa pipeline dovrebbe permettere un incremento prestazionale del 500%, tuttavia il fatto che l’intervallo di tempo fra il completamento di 2 istruzioni sia superiore al valore minimo possibile ne va ad intaccare il guadagno in termini di prestazioni
Esempi di guadagno prestazionale 3 istruzioni di load senza pipeline: 3 x800 ps = 2400 ps 3 istruzioni di load con pipeline: 2 x200 ps + 1000 ps = 1400 ps Fattore di miglioramento = 2400 / 1400 = 1,71 (valore basso dovuto al mancato riempimento della pipeline ed al doverla svuotare) 1 000 000 istruzioni di load senza pipeline: 1 000 000 x 0,8 ns = 800 000 ns 1 000 000 istruzioni di load con pipeline: 1 000 000 x 0,2 ns + 0,8 ns = 200 000,8 ns miglioramento 800 000 ns/200 000,8 ns = 3,999984 (con 1000 istruzioni, guadagno di 3,984 volte) Passi dell’esecuzione pipeline MIPS e registri pipeline
La pipeline MIPS è formata da 5 stadi e tra ognuno degli stadi è interposto un registro che prende il nome dai stadi tra cui si trova. I dati elaborati da uno stadio vengono scritti nel registro interstadio sul fronte di salita che termina il ciclo di clock, e dopo un periodo di stabilizzazione possono essere usati (registri di tipo edge-triggered su rising edge)
Tuttavia, essendo sui registri salvati informazioni appartenenti a istruzioni diverse, bisogna risolvere il problema della scrittura nel RF del risultato (che si trova in MEM/WB), in quanto il valore presente nel registro IF/ID non appartiene ad una successiva, ed usare quell’informazione per identificare il registro di scrittura risulterebbe in un errore. Per questo motivo l’indirizzo di scrittura delle istruzioni viene fatto passare insieme ai dati attraverso gli stadi della pipeline, memorizzandolo registro dopo registro. Per permettere ad un dato di essere letto da un registro nello stesso ciclo di clock in cui esso viene scritto, la scrittura nel RF avviene sul fronte di discesa del clock, per cui la prima metà del ciclo di clock salva il dato e t_propMEM/WB + t_set upRF <= 100 ps (scrittura RF) durante la seconda è possibile accedervi • a 100 ps fronte di discesa e scrittura in RF • t_propRF + t_set upID/EX<= 100 ps (lettura RF)
Segnali di controllo della pipeline I segnali di controllo della CPU pipeline sono gli stessi di quella monociclo, tuttavia bisogna fare in modo che ogni stadio della pipeline abbia a disposizione i segnali di controllo adeguati all’operazione che si sta svolgendo in quel passo. I valori dei segnali vengono tutti generati a partire dal contenuto del registro IF/ID che, dopo ogni fetch, contiene l’istruzione da eseguire e il valore del PC incrementato. Ai primi due stadi IF e ID non sono associati segnali di controllo espliciti in quanto l’unico considerato è il clock e il suo fronte attivo, i valori dei segnali per gli stadi EX, MEM e WB sono passati attraverso la pipeline salvandoli nei registri intrestadio, e man mano che vengono utilizzati non vengono più propagati
B
seq
Per rappresentare i valori si usino queste convenzioni: segnali a singolo bit: 1 o 0, oppure X se il bit può essere 1 o 0 indifferentemente valori a più bit: codifica esadecimale del valore, oppure “n.d.” se valore non determinabile per il caso richiesto
2
1
main
branch 1 2
A
D
C
Legenda dei registri inter‐stadio
(32) ecc.= n° di bit del campo considerato
(Rs) o (Rt) = contenuto del registro Rs o Rt
Rd, Rt, R= numero di registro, dove R può essere Rd o Rt
I campi dei registri interstadio sono indicati come: Nome_Registro_Inters tadio.Campo_x
PIPELINE E HAZARD Tipi di conflitti conflitti strutturali: tentativo di usare la stessa risorsa da parte di diverse istruzioni nello stesso intervallo di tempo (non presente nel MIPS perché la Memoria Dati e la Memoria Istruzioni sono separate, inoltre il RF è gestito in lettura/scrittura con una temporizzazione che le permetta entrambe nello stesso ciclo di clock) conflitti sui dati: tentativo di utilizzare un risultato prima che sia pronto conflitti di controllo: tentativo di prendere una decisione sulla prossima istruzione da eseguire prima che la condizione sia stata valutata Conflitto dati R/R (migliore ottimizzazione) Si verifica quando un’istruzione R necessita del valore di un registro prima che questo sia stato aggiornato da un’istruzione R precedente. Questo conflitto si risolve con un circuito di Propagazione/Bypassing EX/EX: visto che il valore aggiornato è già calcolato dopo lo stadio EXE della prima istruzione, mediante l’aggiunta di un collegamento hardware è possibile fornire il valore appena calcolato come ingresso allo stadio EX della seconda istruzione
Conflitti load/R (migliore ottimizzazione) Si verifica quando un’istruzione R ha bisogna di un usare registro prima che il nuovo valore sia stato caricato in quel registro dall’istruzione load. Per risolvere il conflitto si usa un circuito di propagazione MEM/EX: la load dispone del risultato alla fine del suo stadio di MEM, aggiungendo uno stallo/NOP (No Operation) e aggiungendo un circuito che collega lo stadio MEM allo stadio EX posso portare dare il valore alla seconda istruzione
Conflitto di controllo (beq, migliore ottimizzazione): Si verifica quando un’istruzione necessita di conoscere il valore di una condizione prima che questa sia stata calcolata. Utilizzando una Pipeline Ottimizzata la condizione può essere disponibile alla fine del passo ID, quindi: branch untaken: l’istruzione che richiede la condizione non è immediatamente dopo l’istruzione che la calcola. In questo caso con la pipeline ottimizzata funziona tutto branch taken: l’istruzione che richiede la condizione è immediatamente dopo l’istruzione che la calcola, in questo caso anche con pipeline ottimizzata bisogna inserire uno stallo/NOP
Conflitto di dati Le dipendenze di dato diventano conflitti di dato solamente se la richiesta va indietro nel tempo, una richiesta nello stesso ciclo di clock non diventa un conflitto. Le tecniche di risoluzione dei conflitti di dato sono software (prime 2) e harware (seconde 2): NOP (no operation): inserimento nel codice di una NOP, è la risoluzione più semplice ma allunga il tempo di esecuzione del programma. Tutti i segnali di controllo di una NOP sono posti a 0
Scheduling/riordino: il compilatore individua in una serie di istruzioni quelle che sono indipendenti dalle altre e le interpone tra due istruzioni in conflitto, in questo modo si risolve il conflitto senza allungare il tempo d’esecuzione del programma (nel caso non ci siano istruzioni indipendenti viene inserita una NOP). Lo scheduling richiede l’utilizzo di compilatori potenti
Stalli: il flusso di istruzioni in ingresso alla pipeline viene bloccato a livello hardware finché il conflitto non è risolto, le istruzioni che sono state bloccate dopo essere entrate nella pipeline rimangono in sospeso nello stadio in cui erano. Poiché ci si accorge nello stadio di ID del conflitto, l’esecuzione viene bloccata in questo stadio e il registro IF/ID deve essere preservato, questo porta la nuova istruzione entrante nella pipeline a rimanere bloccata nel suo stadio IF. In ciascun ciclo di stallo, lo stadio ID scriverà nella parte “segnali di controllo” del registro ID/EX solo valori a 0
propagazione/forwarding/bypassing: si inseriscono circuiti che permettono di trasportare il risultato di un’operazione da uno stadio della pipeline ad un altro non appena esso è stato calcolato, senza aspettare che venga salvato nei registri.
Propagazione di dato Se un’istruzione è nel suo stadio EX e ha bisogno di un dato non ancora scritto dalla fase WB bisogna portare il dato in ingresso all’ALU, c’è conflitto se: 1a. EX/MEM.RegistroR = ID/EX.RegistroRs 1b. EX/MEM.RegistroR = ID/EX.RegistroRt
Hazard in EX
2a. MEM/WB.RegistroR = ID/EX.RegistroRs 2b. MEM/WB.RegistroR = ID/EX.RegistroRt
Hazard in MEM
Aggiungendo dei multiplexer agli ingressi dell’ALU posso prelevarne gli operandi da qualsiasi registro di pipeline e non solo dal registro ID/EX. Le condizioni logiche che rilevano il conflitto sono (considerando anche di voler usare sempre il dato più recente nel caso lo avessi in propagazione sia da EX che da MEM):
Le condizioni riguardanti il registro Rs operano sul MUX PA, quelle riguardanti Rt operano su MUX PB. I segnali di controllo del multiplexer di propagazione risultano essere:
ROSSO: propagazione EX/EX BLU: propagazione MEM/EX
Propagazione per conflitto load/store Si verifica quando load scrive in un registro che store vuole salvare in memoria. Load ha il risultato pronto alla fine del suo stadio MEM, e il dato serve a store all’inizio della sua fase MEM. Per risolvere il problema vien introdotto un forwarding MEM/MEM. Bisogna aggiungere un multiplexer per selezionare il corretto dato da scrivere Propagazione per conflitti load/use (R) Il problema si pone quando la load deve scrivere in un registro un nuovo valore (di cui dispone alla fine di MEM), ma il registro è richiesto come operando dalla fase EX dell’istruzione di tipo R appena successiva. In questo caso un forwarding MEM/EX non è sufficiente e bisogna quindi introdurre uno stallo. In aggiunta all’unità di propagazione è necessaria una unità di rilevamento dei conflitti che durante lo stadio di ID possa inserire uno stallo tra la lettura del dato e il suo utilizzo. Il conflitto viene rilevato utilizzando ID/EX di load e IF/ID di use: If (ID/EX.MemRead and ((ID/EX.RegistroRt =IF/ID.RegistroRs) or (ID/EX.RegistroRt =IF/ID.RegistroRt))) Allora metti in stallo per un ciclo di clock. Al ciclo successivo posso usare una propagazione MEM/EX
Conflitti di controllo i conflitti di controllo si verificano in presenza di istruzioni di salto condizionato, visto che la condizione di salto viene determinata nello stadio MEM. Per risolvere il problema si possono adottare tre strategie: senza predizione: vengono inserite dopo le branch 3 NOP oppure tre cicli di stallo predizione: si predice che il salto non venga eseguito (branch untaken, risultato più probabile) e quindi si dovranno scartare dalla pipeline 3 istruzioni solo nel caso in cui il salto debba essere fatto pipeline ottimizzata: il calcolo dell’indirizzo di salto e la valutazione della condizione sono spostati hardware in stadi precedenti della pipeline, questo permette di dover scartare una sola istruzione dalla pipeline invece che tre pipeline ottimizzata + predizione: si parte dal presupposto che la branch non verrà eseguita, nel caso la condizione sia verificata si introduce uno stallo Struttura della pipeline ottimizzata: Calcolo della destinazione: I valori di PC e dell’immediato sono disponibili nel registro IF/ID, quindi il sommatore che calcola l’indirizzo di salto può essere spostato dallo stadio EX a ID Valutazione della condizione: i due registri letti nello stadio di ID vengono confrontati da un confrontatore formato da una batteria di XNOR e un AND finale per generare 1 se la condizione è verificata Per eliminare l’istruzione in eccesso nel caso di salto vine aggiunto un segnale IF.Scarta che azzera la parte del registro IF/ID contenete l’istruzione, rendendola una NOP. In caso di salto PCsrc=Zero AND Branch è posto a 1
LA GERARCHIA DELLE MEMORIE La gerarchia delle memorie ha come scopo quello di permettere di accedere velocemente a programmi grandi. Per rendere possibile questo si fanno lavorare insieme memorie di grandi dimensioni e lente (memoria B) in grado di salvare il programma, con memorie più piccole e veloci (memoria A) su cui vengono trasferiti solo i blocchi di istruzioni necessari nel breve termine. Il processore fa sempre riferimento agli indirizzi di memoria B, ma ottiene i dati dalla memoria A, bisogna quindi associare gli indirizzi della memoria B quelli della memoria A. Comportamento di accesso alla memoria L’accesso alla memoria da parte dei programmi non è omogeneo, bensì presenta caratteristica di località (che rende efficace la struttura della gerarchia di memoria): località spaziale: un programma tende ad accedere agli stessi indirizzi di memoria cui ha già acceduto di recente località temporale: un programma accede con maggior probabilità agli indirizzi vicini a quelli cui ha già acceduto in passato Una volta che il processore richiede una parola relativa ad un certo indirizzo e avviene l’accesso alla memoria A, si parla di HIT (successo) se la parola era presente nella memoria A, in caso contrario si parla di MISS e la parola cercata dovrà essere caricata dalla memoria B in memoria A (il tempo impiegato per il trasferimento è chiamato Miss Penalty). 𝑛° 𝑎𝑐𝑐𝑒𝑠𝑠𝑖 = 𝑛° 𝑀𝑖𝑠𝑠 + 𝑛° 𝐻𝑖𝑡 𝑛° 𝑀𝑖𝑠𝑠 𝑛° 𝑎𝑐𝑐𝑒𝑠𝑠𝑖 𝑛° 𝐻𝑖𝑡 𝐻𝑖𝑡 𝑅𝑎𝑡𝑒 = 𝑛° 𝑎𝑐𝑐𝑒𝑠𝑠𝑖 𝑀𝑖𝑠𝑠 𝑅𝑎𝑡𝑒 =
La memoria A è formata da più blocchi, questo per permettere di allocarvi parole relativi a parti non contigue del programma in esecuzione. In seguito ad una MISS, prima di poter caricare un nuovo blocco, uno vecchio deve essere scaricato. Questa viene detta politica di sostituzione e può essere: casuale: il blocco scaricato è scelto a caso FIFO: viene sostituisce il blocco caricato meno di recente, indipendentemente dall’ultimo utilizzo del blocco Least Recently Used (LRU): viene sostituito il blocco utilizzato meno di recente (meno probabile che sarà richiesto in futuro per definizione di località temporale). È il metodo migliore Gerarchie reali I programmi di oggi sono troppo grandi e i processori troppo rapidi per poter avere una gerarchia a soli due livelli. Sono quindi gerarchizzate più memorie create con tecnologie diverse
Traduzione degli indirizzi La CPU quando deve accedere alla memoria richiede la parola presente ad un indirizzo virtuale, ma gli indirizzi della memoria centrale sono invece fisici, è quindi presente un meccanismo di traduzione degli indirizzi da virtuali a fisici, che viene operato dalla MMU (Memory Management Unit). Inoltre, a causa della gerarchia, servirà una traduzione tra indirizzi fisici e indirizzi di cache
LE MEMORIE CACHE La memoria centrale e la cache sono organizzate in blocchi delle medesime dimensioni, e la cache conserva copie dei blocchi della memoria centrale. Avendo i blocchi le stesse dimensioni, lo spiazzamento di una parola in un blocco di indirizzi della memoria centrale piuttosto che in quello della cache non cambia. Ad ogni blocco della cache è associato un bit di Valid che indica se il blocco è una copia valida o è libero. Il sistema di gestione della cache si occupa di caricare e scaricare dalla cache i blocchi di memoria centrale. Cache istruzioni e cache dati (MIPS) Istruzioni: se il processore deve eseguire un’istruzione e la trova in cache, allora la legge e la esegue. Se l’istruzione non è in cache allora la pipeline viene messa in stallo in modo che il blocco contennete l’istruzione venga caricato dalla memoria centrale in un blocco libero della cache, a spostamento avvenuto lo stallo della pipeline viene rimosso e l’istruzione eseguita Dati: se il dato che il processore deve leggere si trova in cache, allora esso viene letto ed utilizzato. Se non si trova in cache, il dato deve venire scritto nella cache (stallo pipeline), viene poi letto e il dato memorizzato in cache (e se serve in memoria) Scrittura dei blocchi Write through: L’informazione viene scritta sia nel blocco della cache che nel blocco della memoria centrale (per evitare uno stallo dovuto alla scrittura sul livello inferiore viene utilizzato un buffer di scrittura, e la scrittura avviene senza bloccare il processore) Write back: L’informazione viene scritta nella cache, mentre il livello inferiore viene aggiornato solo quando è necessaria la sostituzione del blocco di cache (per ogni blocco di cache viene mantenuta l’informazione sulla modifica mediante un bit Modifica) Cache a indirizzamento diretto Ogni blocco della memoria centrale può essere caricato in un unico blocco di cache (no duplicati), calcolato:
blocco di indice (indirizzo) j della memoria centrale è caricabile solo nel blocco di cache di indice (indirizzo): [resto div intera di j / n° blocchi della cache] Questo tipo di indirizzato richiede che il numero di blocchi della memoria centrale e della memoria cache sia una potenza di 2. Dati: memoria centrale di 2N parole/byte (N bit di indirizzo) blocchi di 2K parole/byte (K bit di indirizzo per identificare una parola nel blocco) memoria centrale di 2(N - K) blocchi (2N/2K) memoria cache di 2M blocchi (M bit di indirizzo per identificare un blocco nella cache) allora 2L=N - M - K blocchi di memoria centrale si mappano in un identico blocco di cache. Si usano i bit corrispondenti dell’indirizzo per identificare il blocco effettivamente caricato in cache (etichetta)
23 blocchi cache: 3 bit indirizzo (indice) del blocco 25 blocchi memoria centrale: 5 bit indirizzo (indice) del blocco 22 blocchi di memoria centrale si mappano in un identico blocco di cache (= 25 /23) Ogni blocco della cache include: valid bit: indica se questa posizione contiene o meno dati validi (all’accesso tutto a 0) campo etichetta: contiene il valore che identifica univocamente l’indirizzo del blocco di memoria corrispondente ai dati memorizzati Campo dati: contiene la copia dei dati Dato un indirizzo di memoria centrale, l’accesso a cache avviene nel modo seguente: la parte di indirizzo che contiene l’indice del blocco in cache (M) viene usata per selezionare il blocco Se il blocco è valido, la parte di indirizzo che contiene l’etichetta (L), viene confrontata con l’etichetta del blocco selezionato se il confronto è positivo il dato è in cache e la parte di indirizzo che specifica il byte (o la parola) nel blocco viene utilizzata per accedere al byte (o parola) corretta In generale un indirizzo di memoria di N bit è diviso in 4 campi: B bit: singolo byte nella parola (Se non è indirizzabile per byte B= 0) K bit: parola all’interno del blocco di cache M bit per individuare la posizione del blocco in cache N-M-K-B bit di etichetta per verificare che il blocco di cache contenga l’indirizzo cercato Esempio: – Memoria centrale 4Gigabyte (32 bit indirizzo) – Blocchi da 4 parole (16 byte): B=2, K=2 bit – Memoria cache da 16k parole: 12 bit per indirizzare un blocco (n° blocchi = 214/22) – Etichetta da 16 bit
Le cache a indirizzamento diretto hanno una struttura identica a quella di una normale memoria, in cui un blocco indirizzato è attivato mediante un decoder che riceve in ingresso l’indice del blocco in cache. La struttura della cache è semplice, l’accesso veloce e il trasferimento di dati avviene parola per parola
Cache completamente associative Un blocco di memoria centrale può essere memorizzato in un qualunque blocco della cache. Non esistendo relazione tra gli indirizzi delle due memorie non si pone il problema del mapping. Dato un indirizzo di memoria di N bit, con blocchi di cache di 2M byte, gli M byte meno significativi dell’indirizzano individuano il byte nel blocco di cache, mentre gli N-M bit più significativi rappresentano un’etichetta lunga. Per trovare una parola nella cache è necessario un confronto di tutte le etichette presenti nella cache con l’indirizzo di memoria richiesto, questa ricerca avviene in parallelo tramite una memoria associativa Cache set-associative a n vie Questa cache è indirizzata per gruppi, dove un gruppo è composto da almeno n blocchi di cache. Ogni blocco della memoria centrale può essere caricato in un solo gruppo prefissato (mapping), ma in uno qualsiasi degli n blocchi in esso contenuti (indirizzamento diretto per i gruppi, associatività per i blocchi contenuti). Oltre 8 vie non si hanno più benefici tali per cui valga la pena di complicare il circuito Un indirizzo di memoria di N bit è suddiviso in 4 campi: B bit meno significativi per individuare il byte all’interno della parola K bit per individuare la parola all’interno del blocco M bit per individuare il gruppo, indice del gruppo (indirizzamento diretto per il gruppo) N-(M+K+B) come etichetta, quale blocco nel gruppo (completamente associativa nel gruppo)
nelle cache a 2 vie ogni gruppo è costituito da 2 blocchi, in pratica è come avere due cache a indirizzamento diretto affiancate, che vengono usate insieme, accedendo ai due blocchi corrispondenti nelle due cache e scegliendo quello più conveniente dei due
Nelle cache a A 4 vie ogni blocco di memoria centrale può essere caricato in 4 blocchi di cache (ogni gruppo ha dimensione di 4 blocchi) -Memoria centrale 4Gbyte: 32 bit -Memoria cache 1K parole (4K byte), con blocchi da 1 parola Organizzazione dell’indirizzo: – Bit 0 e 1: indirizzano i byte – Bit 2-10: indice del gruppo nella cache – Bit 31-11: etichetta estesa – Numero blocchi nella cache = dimensioni della cache/dimensione del blocco=210/1=210 – Numero di gruppi nella cache= numero di blocchi cache/ dimensione del gruppo = 210/22 =28= 256 gruppi
INPUT/OUTPUT A LIVELLO HARDWARE Le periferiche interagiscono in modo asincrono con il processore e la memoria di un calcolatore attraverso interfacce di ingresso/uscita (I/O), il cui numero può variare ma che devono essere almeno tre. Il collegamento tra l’interfaccia e il calcolatore avviene attraverso un BUS di interfacciamento. Le interfacce contengono dei registri leggibili/scrivibili sia dal processore che dalla periferica stessa, sono: Registro dati: contiene i dati che la periferica deve leggere (uscita) o ha scritto (ingresso) Registro di controllo: contiene indicazioni sulle operazioni che la periferica deve compiere e sul suo modo di funzionamento Registro di stato: contiene informazioni sullo stato di funzionamento della periferica oltre al bit di Ready (se attivo significa che il processore può svolgere una lettura/scrittura di un dato)
Indirizzamento dei registri delle periferiche Esistono due modi in cui il processore può indirizzare i registri delle periferiche (MIPS è MM): Memory Mapped I/O: i registri delle periferiche sono associati ad indirizzi omogenei con quelli della memoria centrale, per cui le istruzioni di accesso rimangono invariate. I registri delle periferiche devo essere mappati in modo tale che la memoria non risponda a tali indirizzi con i propri dati Port Mapped I/O: sono previste istruzioni macchina specifiche per l’accesso ai registri della periferica e gli indirizzi sono separati da quelli della memoria (chiamati Port). Ad istruzioni diverse sono assegnati segnali di controllo diversi, quindi la memoria non si cura di quegli indirizzi Gestione dell’I/O Le tecniche di gestione dell’I/O devono consentire le interazioni tra periferica e calcolatore in termini di Sincronizzazione e Trasferimento dati. Le tecniche di gestione sono tre Gestione a controllo di programma Sia la sincronizzazione che il trasferimento dei dati sono gestiti a livello software (da piccoli programmi). Il programma controlla di continuo il bit Ready fino ad un cambio di stato che indica la presenza di un dato su cui operare. Questa tecnica di gestione è molto efficiente, ma solo quando il processore ha solo quello da fare (sistemi embedded che controllano sensori), un calcolatore classico sprecherebbe solo cicli di clock aspettando un dato che potrebbe non arrivare.
Gestione con meccanismo di Interrupt La sincronizzazione avviene a livello hardware, un segnale di Interrupt che si alza/abbassa in base al bit Ready indica al calcolatore la disponibilità di un dato nei registri della periferica. La trasmissione dei dati è gestita ancora a livello software. A differenza della gestione a controllo di programma, la gestione con Interrupt permette alla CPU di lavorare su altre istruzioni finché la variazione del segnale di Interrupt non viene avvertita (test prima della fase di Fetch), in quel momento la CPU interrompe il programma in esecuzione e passa a svolgere una routine di Interrupt di risposta (dipende dalla periferica e dal servizio di I/O richiesto), per poi riprendere l’esecuzione del programma. La routine di risposta non deve assolutamente modificare registri del programma in esecuzione. Directed Memory Access (DMA) Sia la sincronizzazione che il trasferimento dei dati sono gestiti gestiti a livello hardware. La periferica è in grado di prendere il controllo del BUS e generare segnali di accesso alla memoria, per trasmettere autonomamente dei dati dalla/in memoria centrale. In DMA il master del BUS non è più la CPU, bensì il controllore del DMA (la periferica). La tecnica DMA prevede le seguenti fasi: 1. Predisposizione: una procedura dell’OS scrive nei registri dell’interfaccia: a. l’indirizzo di memoria (buffer/cache) dal quale iniziare il trasferimento b. l’indirizzo sulla periferica (traccia+settore) dal quale iniziare il trasferimento (è possibile scegliere un ordine ottimale di lettura) c. il numero di dati (parole di memoria) da trasferire d. la direzione del trasferimento (lettura da periferica o scrittura su periferica) 2. La procedura del Sistema Operativo scrive nel registro di controllo dell’interfaccia il comando di avviamento (“start”) dell’operazione e quindi il processore passa ad eseguire altri programmi. La periferica può a questo punto procedere in modo autonomo nel trasferimento 3. Trasferimento di un blocco di dati: a. Nel caso di lettura da periferica, ogni volta che dalla periferica arriva un dato all’interfaccia, l’interfaccia scrive il dato in memoria, incrementa l’indirizzo in memoria, decrementa il numero di dati ancora attesi e, se non sono arrivati tutti, aspetta il prossimo dato. b. Nel caso di scrittura su periferica, ogni volta che la periferica disponibile ad accettare nuovi dati, l’interfaccia preleva il dato da memoria, incrementa l’indirizzo in memoria, decrementa il numero dei dati ancora da trasferire e, se non sono trasferiti tutti, aspetta che la periferica sia disponibile per il prossimo dato 4. Fine (tipicamente a interruzione): Se l’ultimo dato è stato trasferito, l’interfaccia segnala al processore che l’operazione in DMA si è conclusa I BUS I BUS sono degli insiemi di fili, raccolti per utilizzo, che hanno lo scopo di collegamento tra i componenti del calcolatore. Possono essere: Interni: collegano i blocchi funzionali interni ad un’unità funzionale (usano segnali proprietari) Esterni: collegano le unità funzionali tra loro (usano segnali standard). I BUS esterni sono di due tipi e si occupano rispettivamente della gestione delle periferiche e della gestione della memoria
Transazioni di BUS Una transazione di BUS (ciclo di BUS) è un insieme di operazioni sul BUS: transazione di trasferimento: trasferisce una certa quantità di informazione tra due unità funzionali. transazione di interrupt: protocollo di segnalazione di un interrupt alla CPU e relativa accettazione (con predisposizione dell’attivazione della routine di risposta all’interrupt) Transazione di Interrupt Le linee di Interupt sono collegate in modo diverso a seconda che il segnale sia la richiesta della periferica o la ripsosta della CPU: INT_REQ (interrupt request): collegamento in wired-or. La periferica (anche più d’una) attiva il segnale di interrupt request sulla linea quando il suo bit Ready cambia stato INT_ACK (interrupt acknoledgment): collegamento in daisy chain. Il processore rileva il segnale di interrupt request e accetta l’interruzione attivando il segnale di interrupt acknowledge. Il segnale INT_ACK viene propagato dalle periferiche fino alla (prima) periferica interrompente che disattiva il suo interrupt request e non propaga il segnale (ordine gerarchico delle periferiche). In corrispondenza della generazione del segnale di INT_ACK può partire un ciclo di trasferimento (lettura) in cui il processore acquisisce dalla periferica interessata il vettore di interrupt
Transazione di trasferimento Fase di arbitraggio: serve a selezionare un’unità, detta MASTER, che controlla il BUS durante l’operazione. Un’unità di arbitraggio (di solito CPU) gestisce le richieste di diventare MASTER del BUS da parte di altre unità funzionali. Le richieste raggiungono l’arbitro mediante tre linee di BUS: o BUS Request (richiesta di cessione del controllo): collegati in wired-or. La linea è asserita da tutte le unità ed è letta dall’arbitro. Il segnale è attivo basso o BUS Grant (conferma di cessione del controllo): collegamento in daisy chain. Asserita dall’arbitro e letta dalle unità. Come per le periferiche con meccanismo di Interrupt, un’unità funzionale trasferisce il segnale finché non è stata lei a fare una richiesta (vale l’ordine gerarchico) o BUS Busy (indicazione che esiste un Master corrente che sta eseguendo un trasferimento): collegamento in wired-or. Asserita da tutte le unità e letta da tutte le unità Quando l’arbitraggio è terminato definendo il prossimo Master, questo deve attendere la fine del trasferimento corrente prima di iniziare la propria fase di trasferimento
Fase di trasferimento: il MASTER seleziona mediante le linee di indirizzo del BUS un’unità SLAVE su cui lavorare, indicando la direzione di lettura (SM) e di scrittura (MS). Per il trasferimento vengono usate le linee dati del BUS
Temporizzazione del BUS I BUS possono essere: Sincroni: il funzionamento è governato da un clock del BUS, il cui segnale è trasferito a tutti i BUS sincroni e alle unità funzionali a cui essi sono collegati.
Asincroni: funzionamento governato dall’interazione Master-Slave, le unità funzionali osservano il BUS di controllo e quando avviene una transizione di segnale significa che si verifica un avanzamento dell’operazione (il BUS usa segnali di controllo che realizzano un protocollo di handshake). I segnali di controllo per l’handshake sono: o MSYN (Master Synchronisation): Il MASTER segnala di avere impostato indirizzo e RW o SSYN (Slave Synchronisation): Lo SLAVE segnala di avere completato l’operazione di trasferimento
Lettura su BUS asincrono Questa procedura prende il nome di Full-Handshake, è indipendente dal clock ed è insensibile alla presenza di SLAVE lenti. Inoltre, è Fully Interlocked poiché ogniqualvolta uno dei due segnali di sincronismo varia, anche l’altro varia in risposta: 1. MSYN viene attivato 2. SSYN viene attivato in risposta a MSYN 3. MSYN viene disattivato in risposta a SSYN 4. SSYN viene disattivato in risposta a MSYN
Scrittura su BUS asincrono