Sei sulla pagina 1di 12

Bisogna gestire ci che avviene, evitando gli stalli che, nella struttura pipeline a virgola fissa, non

avvenivano di default. Larchitettura prevede questa strategia: abbiamo, all'interno del processore,
inframezzando la parte di input, che si trova tra la CU e i registri, quello che chiamiamo stazioni di
prenotazione. Sostanzialmente gestiremo lesecuzione dellistruzione attraverso queste, che sono
dei buffer dove, ogni volta che un'istruzione vuole andare ad allocare una risorsa (tipo un
sommatore, moltiplicatore, ecc.) vengono impegnate da delle informazioni legate all'istruzione
stessa. Il buffer prende il nome di coda di istruzioni. Una volta che unistruzione viene caricata, la
sua esecuzione viene suddivisa in 3 macrofasi, legate alla possibilit che ci siano risultati di
istruzioni precedenti che producono, a loro volta, risultati di input liberi. Poi parte l'esecuzione e
infine si ha l'aggiornamento del risultato finale. Avremo un incodamento delle istruzioni in questo
buffer; da questo buffer, queste istruzioni, si verranno a prenotare a una stazione, a seconda di
quello che devono fare, e, una volta prodotto il risultato, oltre a fare il WB nel registro fp, questa
retroazione del risultato viene, cortocircuitata per andare eventualmente a impegnare (e
aggiornare) il valore di uno dei campi delle stazioni di prenotazione. Dentro le caselle di
quest'ultime, ci sono delle informazioni che sono il tipo di operazione. Nella casella, la pi stretta, il
campo viene aggiornato da uninformazione che proviene dalla coda delle istruzioni. Poi abbiamo i
2 operandi che normalmente vengono scritti dai registri, alle volte possono essere prelevati dal
bus: il common data bus. I dati prodotti dalle unit possono essere messe in comune sia con i
campi dei registri fp, sia con la stazione di prenotazione.
Possiamo avere la circostanza di una particolare istruzione che fa uso di alcuni dati, non ancora
pronta perch un dato non stato ancora prodotto, e unaltra istruzione che occupa un altro posto
della stazione di prenotazione ed gi pronta Pu essere gi inserita nellunit. E quello che
abbiamo chiamato, nella lezione precedente, gestione fuori ordine delle istruzioni.
Vediamo le 3 macrofasi che identificano l'esecuzione dell'istruzione:
1) Emissione: in questa macrofase un'istruzione, che la 1 che si trova nella coda delle
istruzioni, ( gestite con FIFO In ordine almeno in fase di emissione) viene estratta da quella
coda e, a seconda che gli operandi siano disponibili o meno, (pi che a un conflitto di dati si
pensa a conflitto strutturale) se c' un posto libero nella stazione di prenotazione nell'unit
funzionale di quell'istruzione, l istruzione viene emessa e inserita nella coda di prenotazione

dell'unit funzionale dell'istruzione. Per capirlo meglio, abbiamo la 1 istruzione in coda della
coda delle istruzioni, supponiamo che una MULT. Il moltiplicatore, tra le sue stazioni di
prenotazione, (possono essere 2-3-4 a seconda della capienza del buffer stazione di
prenotazione), ha un posto libero dove mettere questa istruzione? Si? Allora viene tolta dalla
coda delle istruzioni e impegna un posto nella coda di prenotazione dellunit funzionale che lei
deve usare. La 1 istruzione in coda , per esempio una somma, se c una stazione libera
viene inserita dentro E emessa, esce dalla coda e prenota la sua unit funzionale.
L'istruzione per essere attiva, ed entrare in esecuzione, deve avere la disponibilit
dell'hardware , ma anche la disponibilit degli operandi sorgente. Se alcuni di questi non
sono disponibili, l'istruzione che sta in quella coda di prenotazione, si mette a osservare, un po
con un meccanismo di snoopy, il common data BUS. Questo un bus, scritto dalle unit
funzionali, che poi va o nel banco dei registri o nelle stazioni di prenotazioni( solo quando
serve). Supponiamo di avere unistruzione che vuole usare un registro come input, che non
pronto. Supponiamo che listruzione voglia usare F8; ci serve sapere se il registro F8 pronto,
ovvero se il valore di F8 nel banco dei registri effettivamente quello, oppure se F8 il
risultato di unistruzione che deve essere ancora completata Serve una struttura per capire
ci. Supponiamo che da questa struttura, nella coda di prenotazione, sia evidente che
listruzione che vuole usare F8, voglia usare un registro non ancora pronto. Nel momento in cui
unistruzione, in coda di prenotazione, si accorge di questo, sa che non pu iniziare fin quando
non ha loperando sorgente disponibile. Per, pi che aspettare che loperando sorgente
disponibile venga scritto nel banco dei registri e poi da li venga a lei, si mette a osservare il
common data bus. Nel momento in cui lunit funzionale, che deve produrre quel dato, lo ha
prodotto, lui se ne va in F8 ma, mentre se ne va, lo prelevo e aggiorno il contenuto del
particolare campo della stazione di prenotazione che vuole usare F8. Se latro input era F6,
che era gi disponibile, posso iniziare il lavoro. L'esecuzione parte quando tutti i risultati dinput
sono disponibili e, ovviamente, ho a disposizione l'unit funzionale.
Si noti che pi istruzioni possono diventare eseguibili per una stessa unit funzionale nel
medesimo ciclo di clock. Supponiamo 2 istruzioni nella stessa stazione di prenotazione che
vogliono entrambe usare il moltiplicatore. Una aspetta F6 e laltra F8. F8 prodotto dal
moltiplicatore e F6 dal sommatore, che aveva iniziato il suo lavoro un po pi tardi. A questo
punto lesecuzione pu essere eseguita in maniera casuale Nel momento in cui listruzione
stata messa nella stazione di prenotazione ha pari priorit con le altre istruzioni. Non
importante chi inizier prima. Se entrambe hanno i risultati pronti, potrebbero iniziare entrambe
prima dell'altra, senza alcun problema. Nel momento in cui viene eseguita listruzione, questa
viene a completarsi quando l'istruzione viene scritta nell'apposito registro e passa nel common
data bus e, se viene intercettato perch ha un dato input di unaltra istruzione, il dato usato
per aggiornare sia l'operando input di una certa istruzione, che per essere scritto nel registro
sorgente.
Quali sono i campi della stazione di prenotazione?
I campi in figura sono 3 ma nella realt sono 7:
Op: Viene aggiornato dalla coda delle istruzioni e viene segnata listruzione che l'unita
funzionale deve fare. Supponiamo che siamo nella situazione della memoria e
dobbiamo fare una somma o differenza, lo devo specificare e via dicendo.
Qj & Qk: Sono 2 campi che fanno riferimento alle eventuali unit funzionali che stanno
producendo i 2 input, J 1 input, K 2 input. Nellipotesi in cui questa particolare
istruzione deve usare come input un registro che non pronto, in Qj o Qk, a seconda

delloperando, scriveranno un codice che identifica quali sono le unit funzionali dalle
quali uscir il valore di Vj e Vk. Se questultimi sono pronti, Qj e Qk valgono 0. Se i dati
non sono pronti, Qj e Qk indicano un codice che specifica da dove verranno prodotti
quei dati. Quindi star attento a intercettare quei dati, prodotti da quelleventuale
modulo, sul common data bus.
Vj & Vk: Sono 2 campi che hanno senso solo se Qj e Qk valgono 0 perch in Vj e in Vk
stanno scritti gli operandi. Quando unistruzione entra in una stazione di prenotazione,
che vuole usare F6 e F8, se F6 disponibile allora in Vj, dal banco dei registri viene
prelevato F6 e si va a scrivere in quel campo. ( copiato in Vj e in Qj viene messo 0). Se
non disponibile in Qj viene inserito 3, per esempio, e il valore di Vj ha un qualcosa che
non ha valore. Lo stesso dicasi per k.
A: Viene usato nel momento in cui parliamo di stazione di prenotazione, dove un
hardware dedicato ha calcolato lindirizzo di memoria stesso e, nellipotesi di una LOAD
o STORE, quel campo stato inizializzato dallindirizzo che viene calcolato da una unit
funzionale specificatamente preposta a questo. Nello schema, lunit di indirizzamento,
calcola lindirizzo. Come? Preleva listruzione; questa conterr limmediato, al suo
interno viene estesa in segno, avr una porta di ingresso al banco dei registri interi, far
la somma e calcoler lindirizzo inserendolo nel buffer di LOAD o STORE. Quello di
STORE contiene, oltre lindirizzo, anche il dato fp che deve essere inserito in memoria.
La stazione di prenotazione della memoria funziona con un campo che
semplicemente lindirizzo per le istruzioni di LOAD, mentre per le STORE c anche un
altro campo prelevato o dal common bus o dal campo dei registri.
Busy: Indica se la stazione di prenotazione occupata oppure no; nel senso che, nel
momento in cui devo emettere un'istruzione, devo controllare se una casella della
stazione di prenotazione disponibile. Questo si fa vedendo un bit associato a
ciascuna riga/casella di quella stazione di prenotazione. Una volta impegnata una delle
righe, prendo una riga in cui il bit 0, scrivo le informazioni imponendo quel busy bit
uguale a 1 e, quando completo l'istruzione legata a quella casella, ritorner a mettere 0
al bit busy.
Qi: Legato a ciascuno dei registri. Rappresenta il meccanismo per far capire se un
registro pronto oppure no. Abbiamo una tabella che ha tante caselle quanti sono i
registri fp, se un'istruzione, che entrata in una stazione di prenotazione, deve
calcolare F6 (per esempio), essendo stata inserita nella stazione di prenotazione di
ununit funzionale unistruzione che deve calcolare F6, il suo contenuto non ha alcun
valore ( nel campo dei registri). In questa tabella, alla casella associata a F6 vado a
scrivere qual l'unit funzionale che deve produrre F6. In fase transitoria, in cui nulla
deve essere prodotto, le Qi sono tutte uguali a 0 ad indicare che nessuna unit
funzionale sta producendo il particolare valore di quel registro.
2) Scrittura
3) Esecuzione
4) Conferma o consolidamento: Quando un dato arrivato nel buffer di riordino e quel dato
proviene da unistruzione che stata confermata, allora viene consolidato e se ne va in
memoria se serviva per fare una STORE o nel banco dei registri se era un WB.

Vediamo meglio lultimo registro.


Qi=0 significa che quel registro disponibile; Qi uguale a un certo numero significa che il registro
associato a Qi, per esempio Q19, nel senso che F19. Se vale 5, significa che lunit funzionale 5
sta producendo questo F19. Se Q19 vale 0, F19 significativo. Ritornando al discorso della
stazione di prenotazione che viene impegnata da unistruzione: nel momento in cui listruzione
viene emessa e vuole fare uso dellinput F5 e F6, si va a vedere Q5 e Q6. Se valgono 0, dal banco
dei registri fp vengono presi F5 e F6 e vengono inseriti nel campo Vj e Vk. Se Q5 vale 0 e Q6 vale
1, allora F5 disponibile ed preso dal banco dei registri e messo in V5; in V6 non scrivo niente
perch non ha alcun significato, ma in Qk scrivo lo stesso numero che trovo scritto nella tabella del
banco dei registri.

Abbiamo la coda della stazione di prenotazione di una particolare unit funzionale, che deve fare
loperazione di cui questistruzione si occupa: MULT. Vado nella coda della stazione di
prenotazione del moltiplicatore. Lei vuole fare F6*F8 = F10. Per ciascuno dei registri abbiamo il
campo Qi. Nel momento in cui listruzione arriva, listruzione fa si che si scriva che F10 prodotta
da questa unit funzionale e, se qualcuno lo chiede, non va dato (F10). Il moltiplicatore associato
al numero 1, per dire che F10 non ha valore, anche se non ho ancora iniziato. Questa cosa
avvenuta nella seguente maniera: se poco fa qualche istruzione richiedeva F10, essendo stata
emessa dalla coda di istruzioni, listruzione prima di lei stata emessa, ha trovato 0 e listruzione
ha preso dal banco dei registri F10. Se viene messa dopo di questa unaltra istruzione che vuole
usare F10, non la andr a prendere dal banco dei registri, ma osserver il common data bus in
attesa che qualcuno produca F10. Cosa succede su F6 e F8? Voglio usarli come input, trovo 0 a
F6 E disponibile. Qj viene messo a 0 perch ho disponibile il dato ( copiato rispetto la tabella a
destra); in Vj, dal banco dei registri, copio F6. Poi vedo F8: vado nella tabella e ha come campo Q
il valore 2. Quindi in Qk copio 2 e non prendo F8 perch non ha alcun valore. Questistruzione
attender che, dal common data bus, venga prodotto, dallunit funzionale 2, il risultato, in maniera
tale che, una volta prodotto, andr nel banco dei registri e durante il viaggio lo catturer, lo
metter dentro e porr a 0 il campo. Solo dopo aver avuto i 2 operandi potr continuare il mio
lavoro ( nel moltiplicatore) e produrre F10. Dal common data bus andr nel banco dei registri,
scriver 0, e chi voleva F10 lo intercetter.

La tabella a destra mi dice lunit funzionale che sta usando quel dato ( direttamente associato a
un particolare registro), le caselle non sono legate al registri ma al 1 e 2 operando.
Abbiamo un codice in cui c una moltiplicazione che fa un calcolo e unaltra che ne fa unaltra.
Entrambe sono arrivate nella stazione di prenotazione e entrambe hanno il diritto di essere
eseguite. Posso procedere eseguendo quella che entrata prima, ma potrebbe capitare che il
risultato di questa, usata dopo, usata in unaltra istruzione e quindi se eseguivo laltra potevo far
partire quella di dopo. Non ho nessun elemento per sapere se meglio eseguire una o laltra
perch limportante che, una volta arrivate, vengano eseguite. In coda non detto che vengano

eseguite nellordine in cui arrivano. In pi non c alcun controllo Altrimenti non sarebbero
arrivate.

Vediamo un esempio in cui abbiamo il seguente programma:


1. L.D F6, 32(R2)
2. L.D. F2, 44(R3)
3. MUL.D F0, F2, F4
4. SUB.D F8, F2, F6
5. DIV.D F10, F0, F6
6. ADD.D F6, F8, F2
Nel momento in cui abbiamo una LOAD, il campo dellistruzione prevede, come nella LOAD intera,
un immediato, un codice che identifica un registro e un codice che identifica un destinazione.
Attenzione che rispetto alla LOAD intera, il campo degli operandi identico. Se avessimo una
LOAD intera con 6 2 32 stiamo facendo la load di 32+ R2 in R6, per il codice operativo di quella
LOAD diverso da quello della L.D. Il codice operativo della L.D specifica che quel 6 non R6 ma
F6 mentre 2 sempre R2 perch lindirizzo calcolato da un immediato e da un registro intero.
Cosa vuole fare questo codice?
Vuole caricare F6 e F2, eventualmente F4 era gi disponibile per quello che vuole fare la
moltiplicazione prendere F2 e moltiplicarlo per F4. Il risultato della moltiplicazione sar F0.
Sempre F2 usato come input nella SUB che vuole usare come input F6 a produrre F8. Poi una
DIV che vuole usare F6 output della prima LOAD e F0 che loutput della moltiplicazione. Ci sono
una serie di dipendenze. Viene prodotto F10 e infine, F2, con F8, risultato della SUB, dovr essere
usato dalla ADD per produrre F6 che sovrascriver lF6 precedentemente trovato.

Queste istruzioni sono state tutte emesse, ma in un particolare istante sono entrate in esecuzione
solo le 2 LOAD. Perch non le altre? Perch stata completata solo la 1 LOAD come si vede in
tabella. La 2 LOAD stata messa in esecuzione, per nel momento in cui la 1 stata completata
e la 2 sta per essere completata, gioco forza nessuna di queste pu entrare in esecuzione. Nella
MULT F4 pronto, per non vuole usare F6 che gi disponibile, ma vuole usare F2 che non
stato ancora scritto e quindi non entra in esecuzione ( si trova nella stazione di prenotazione e sta
ascoltando il common data bus in attesa che esca F2). La SUB sta anche lei aspettando che esca
F2. La DIV ha disponibile F6, ma F0 non pu prenderlo dal banco dei registri perch la Qi di F0
dice che quellF0 deve essere prodotto dalla MULT che deve ancora iniziare Non disponibile.
Non avendo pronti nessuno degli oggetti la DIV e la ADD finale devono aspettare. Le immagini
che seguono mostrano ci che accade nelle stazioni di prenotazione e nello stato del registro.

LOAD 1 non Busy perch stata completata, la LOAD 2 e tutte le altre sono busy. La ADD3 non
busy perch ha una coda di prenotazione con 3 stazioni per il sommatore. In realt ne abbiamo
occupate solo 2, una per la SUB e una per la ADD, la 3 stazione disponibile. Poi abbiamo le 2
stazioni del moltiplicatore e divisore ( hanno parte dellhardware in comune Unico blocco che
riesce a fare ambo le cose). Fintanto che dalla coda delle istruzioni non viene pronta unistruzione
che vuole fare una LOAD o ADD, restano bloccate nella coda di istruzioni. Nel campo Op abbiamo
lindicazione delloperazione che dobbiamo fare. Vj, in questo caso, contiene qualcosa che non ha
significato, perch? Per quanto riguarda queste operazioni di calcolo Qj diverso da 0 e mi indica
da dove prendere loperando. Lo stesso vale per Qk. Gli unici campi pieni sono quelli che indicano
che Vk preso dal banco dei registri o dalla memoria con loperazione della 1 LOAD. Il campo A
mi dice qual lindirizzo dove andare a pescare la LOAD In quel particolare momento questa
la stazione di prenotazione.
Vediamo i registri Qi. Hanno una serie di 0, ma anche una serie di codici diversi da 0 che mi dicono
che F0 non posso prenderlo perch sar prodotto da MULT1, F2 non lo posso prendere perch
sar prodotto da LOAD 2, ecc. Situazione in un particolare momento.
Passaggio Importante: Se una istruzione ha gli operandi liberi nella coda di istruzioni, la posso
avviare? Il codice che abbiamo visto inizialmente mi d un ordine di esecuzione delle istruzioni
( LOAD, LOAD, MULT, SUB, DIV, ADD) In realt, questo fatto di eseguire queste cose nel seguente
ordine garantito dal fatto che queste istruzioni sono entrare nella coda delle istruzioni Unica
struttura di tipo FIFO. Poi le stazioni di prenotazione non sono di tipo FIFO, appena una ha i 2
operandi sorgente vado in esecuzione. Non faccio casini perch nel momento in cui emessa
unistruzione( supponiamo la 1 LOAD), questa va subito a marcare F6, il Q di F6 viene marcato.
Se eseguo unaltra istruzione che vuole usare F6 e magari trova tutto libero, quellistruzione non
partir perch F6 non disponibile. E il modo in cui queste istruzioni che sono state emesse e
hanno marcato il territorio sullo stato dei registri che impedir che la ADD venga eseguita prima
della DIV. Ci non succeder mai, o se verr eseguita e scrive F6, la DIV F6 non lo andr a
leggere da F6 ma lo andr a leggere dal common data BUS. Nel momento in cui viene emessa
unistruzione, nellordine logico con cui le istruzioni devono essere eseguite, queste vanno a
marcare cosa stanno producendo e anche il Qj e Qk da dove arriva il dato. Quindi vediamo cosa
succede attraverso la seguente immagine:

Mander in esecuzione la ADD prima della DIV. Non ho un problema, perch? LADD, quando
stata mandata in esecuzione, aveva disponibili F8 (prelevato dal common data BUS prodotto dalla
SUB) e F2 ( preso dal common data BUS della LOAD), la DIV sta aspettando F0 dalla MULT. In un
particolare momento abbiamo: completato la LOAD, scritto F2 quindi la MULT, che voleva F4 e F2,
stata avviata. Non ancora completata perch richiede qualche colpo di clock. La SUB che
voleva F2 e F6 stata avviata contemporaneamente. F6 serve alla SUB e DIV ed disponibile
perch completata dalla 1 LOAD. La MULT F4 lo ha gi preso dal banco dei registri, la SUB ha
preso F6 sul common data BUS. Subito dopo la 1 LOAD viene completata anche la 2 LOAD, F2
arriva sul common data BUS e viene prelevato dalla MULT, SUB e ADD. Contemporaneamente,
nello stesso istante, sia la MULT che la SUB hanno entrambi i 2 operandi. Perch entrambi
contemporaneamente? Entrambi avevano gi F4 e F6 e quando arriva F2 sul common data BUS
diventano operativi, per la SUB pi corta come latenza ed gi terminata. La MULT non
ancora terminata. Nel frattempo termina la SUB e produce F8. La ADD, che aveva preso F2 dal
common data BUS, prende anche F8 dal common data BUS, viene eseguita e completata. Chi
rimasta? La DIV che sta aspettando F0, non neanche in esecuzione, la MULT che in
esecuzione non ancora terminata. Quando terminer metter F0 sul common data BUS e cosi
finalmente la DIV, che aveva gi prelevato F6, ricever F0 e tra un tot di colpi di clock terminer. E
bene notare che il programma stato eseguito in maniera disordinata, ma senza la presenza di
conflitti di dati, proprio perch se ci fossero stati, unistruzione avrebbe trovato nel suo campo Qj o
Qk: Il risultato lo devi aspettare da quellunit funzionale Non sarebbe partita.

( Al di fuori della tabella sopra) Supponiamo unistruzione generica che vuole produrre F8, unaltra
che vuole usare F8 e poi c unistruzione generica che produce F8. Queste sono emesse in
questordine: quando la 1 viene emessa, in Q8 viene scritto A; viene emessa quella che vuole
usare F8, vado a leggere e trovo A e scrivo nella mia Q, A. Poi viene messa quella che produce F8
e allora scrivo C. Se arriva unaltra istruzione che vuole usare F8 trova scritto C. La chiave nel
fatto che lemissione avviene FIFO e quando una emessa vedo quello che sar, come se tutto
quello che stato prima di me stato completato. Se stato completato trover 0 e lo andr a
prendere, se non stato completato trovo scritto chi mi deve produrre quel dato e lo aspetto.

Qui non abbiamo una serie di busy, tutte le unit che hanno completato il loro lavoro, marcando
busy = no, indicano il fatto che se vuole arrivare una LOAD dalla coda delle istruzioni c una
casella ( in questo caso 2) liberi nella stazione di prenotazione della memoria. Se voglio usare
operazioni di somma e sottrazione ho 3 caselle libere. Ho problemi, ovviamente, nella coda di
prenotazione della MULT per moltiplicazioni e divisioni ma tra un attimo la moltiplicazione finir e si
liberer quel busy. E infatti nella tabella sotto, sugli stati, F0 e F10 sono quelli che mancano diversi
da 0. Se ora viene emessa unistruzione che vuole usare F10, lei nel suo Qk copier questo
valore. Se unistruzione vuole usare F6, copier 0 in Qk e prelever dal banco dei registri F6.

Vediamo adesso il caso di un loop:


L.D F0, 0(R1)
MUL.D F4, F0 F2
S.D F4, 0(R1)
DADDIU R1, R1, -8
BNE R1 R2 Loop; salta se R1 diverso da R2
Essendo un ciclo abbiamo una serie di istruzioni che usano gli stessi registri.
Prima per, vediamo una tabella che riassume un po quello che ci siamo detti sino ad ora:

La tabella divisa a seconda delloperazione che dobbiamo fare.


Voglio emettere unistruzione fin quando non trovo vuota una stazione di riservazione. Non
potendola emettere, metto in stallo la coda delle istruzioni. Quando una stazione di prenotazione si
libera, la emetto e faccio ci che si vede in alto a destra della tabella.
Abbiamo per quellistruzione un rs e un rt. Si va nello stato dei registri, si vede se lo stato dei
registri del particolare registro rs, vuole usare F8 e vedo se Qi di questo F8 diverso da 0. Se
diverso da 0, qualcuno sta producendo quellinput, vado nella RS, vado al campo Qj e scrivo ci
che trovo scritto. Quel Qi diverso da 0, vale 5? Scrivo 5 a significare che Qj vale 5 Formalismo
per descrivere ci che abbiamo detto. Altrimenti se Qi 0, loperando disponibile. Vado in Vj e
prendo il contenuto del banco dei registri, stiamo parlando di F8? Vado al banco dei registri F8 e lo
metto in Vj ma metto 0 nel mio Qj. Stesso procedimento per il 2 registro sorgente rt, questa volta
con Qk e Vk. Ho impegnato la stazione di riservazione? In busy devo mettere busy yes e devo
anche fare unaltra cosa fondamentale: venire nel registro stato a marcare il mio registro
destinazione. Questo ci che faccio nel momento in cui ho emesso unistruzione fp.
Cosa succede se devo fare una LOAD o STORE? Devo avere il buffer vuoto. Voglio fare, per
esempio, la LOAD di F8; devo verificare se F8 diverso 0, o meglio se F8 libero. Se F8 libero,
Qi diverso da 0, prender dal banco dei registri F8 e lo metter in Vj. Se devo fare una STORE
devo verificare che il mio sorgente, che devo scrivere in memoria, sia disponibile. Se lo significa
che Qi uguale a 0 e quindi else prendo rt e lo metto in Vk. Altrimenti se diverso da 0, devo
mettere in Vk chi mi sta producendo il dato. Se devo fare una LOAD, loperazione pi semplice

perch devo andare nel registro di stato e dire: Sto facendo la LOAD di F8, in F8 scriver r in
maniera tale che chi vuole usare F8, quando viene qua, legge la LOAD1 che lo vuole produrre.
Nella fase di esecuzione abbiamo da attendere che entrambi gli operandi siano disponibili.
Sostanzialmente sia Qj che Qk, in AND, devono essere uguali a 0. Quando lo sono, eseguo il
calcolo usando gli operandi Vj e Vk. Se Qj= 0 ed allinizio della coda di LOAD STORE, il registro
sorgente, con cui vado a calcolare lindirizzo, mi calcolo limmediato pi sorgente per ottenere
lindirizzo. Dopo aver calcolato lindirizzo, vado in memoria a fare la lettura e prendendo il campo A
della stazione di riservazione. Questo per quanto riguarda lesecuzione.
Se sto facendo la fase di scrittura, ho completato la mia operazione e bisogna prendere il dato che
va sul common data BUS. Nel momento in cui un dato viaggia sul common data BUS, ciascuna
istruzione, che nella stazione di riservazione X, si chiede se la stazione r, che ha completato,
coincide col proprio Qi. Se c una particolare istruzione che tiene Qi = LOAD2 e sta arrivando sul
common data BUS qualcosa prodotto da LOAD2, si prende il risultato e si mette nel banco dei
registri. Il risultato fa si che Qi venga messo = 0 e lo stesso lo faccio per Qj. Avendo completato
vado a scrivere no sul busy. Per lo STORE Vk va in memoria allindirizzo A e vado a mettere il busy
uguale a no.
Ritorniamo al loop, cosa fa?
Carica un vettore che caricato in memoria a partire da un certo numero, 0 + IMM R1. R1 stato
inizializzato a puntare allultimo elemento di questo vettore ( meccanismo visto ieri per gestire i
vettori in modo tale da avere un puntatore che quando arriva a 0 esco dal loop). Supponiamo che
R1 valga 800, carico F0. F2 un valore precaricato e faccio F0*F2 e calcolo F4. Vado nello stesso
indirizzo dove avevo caricato il dato e scrivo F4. Decremento R1, se R1 non uguale a R2 salto al
loop. Quando combaciano non salter pi. Il programma sta leggendo il vettore in memoria e lo sta
moltiplicando per lo scalare F2 per poi aggiornare il vettore. Vediamo come avviene questa
esecuzione.

Stessa tabella di prima, dove per viene aggiunta una colonna che ci chiarisce listruzione di che
iterazione . Abbiamo una situazione in cui, in un particolare momento, la LOAD stata emessa
ed eseguita. Non stata ancora completata F0 non ancora stato letto. La MULT che vuole
usare F0 non pu essere in esecuzione, stata solo emessa. La STORE che vuole usare F4
stata solo emessa. La cosa strana che nel frattempo stata avviata laltra LOAD ed avviata in
esecuzione. Succeder che, questa LOAD, produrr F0 cos come anche laltra LOAD produrr F0.
Attenzione per che lF0 della 2 LOAD non lF0 che deve essere usato dalle prime 2 istruzioni.
Infatti nella stazione di prenotazione( che possiamo vedere nellimmagine sotto), queste 2 istruzioni
hanno come Qj non F0, perch altrimenti quando viene prodotto il 1 F0 entrambe non possono
partire, ma hanno scritto qual la stazione di prenotazione che produce quel dato. Quindi la 1

MULT del primo ciclo ha scritto che Qj che produrr F0 LOAD1 e la MULT del secondo ciclo ha
scritto che il mio F0 LOAD2. Quindi, quando la LOAD1 si completer, anche se il dato andr in
F0, la MULT non se lo prender dal common data BUS perch su quel common data BUS c
scritto che quellF0 proviene da LOAD1 Solo chi lo sta aspettando da LOAD1 lo pu prendere.
Nel momento in cui ho eseguito la LOAD, Q0 dello stato dei registri, tiene LOAD2, perch? Se
viene messa una nuova istruzione che vuole F0, leggendo LOAD2 scriver nel suo Qj: Stai
aspettando qualcosa che viene da LOAD2, e la prossima istruzione che entrer dalla coda delle
istruzioni sar una LOAD. Una nuova LOAD potr essere emessa quando verr a liberarsi una
nuova stazione di LOAD.

Per ora le 2 stazioni di LOAD sono impegnate, infatti nella stazione vediamo busy yes a entrambe;
fra un po, che si completer LOAD1, busy sar no e la prossima LOAD, del terzo ciclo, potr
essere emessa e ,mettendo la 3 LOAD, verr scritto in F0 dello stato dei registri LOAD3. Tutte le
istruzioni che verranno emesse dopo, se richiedono F0, dovranno prendere questo F0.

Accenniamo quello che avviene nel momento in cui abbiamo la gestione col buffer di riordino,
situazione in cui i risultati vengono gestiti in maniera speculativa.
(Strategia per gestire la coda di istruzioni in maniera non FIFO: cerca)
Eseguo delle istruzioni che sono eseguite anche in maniera speculativa. Ovvero? Per esempio, se
sto facendo un salto, non ho verificato una condizione di salto perch basata su un registro float
che devo ancora calcolare. Allora posso ipotizzare che il salto si verifichi (o no) e eseguo le
istruzioni . Le istruzioni eseguite, producono dei risultati, che non vanno nel banco dei registri
Non c' neanche un buffer di STORE dove, dal banco dei registri, i dati vengono presi per essere
scritti in memoria, ma i risultati delle operazioni vengono sistemati nel buffer di riordino e, questo
buffer, attende fintanto che non avviene la validazione dell'istruzione. Solo quando listruzione
effettivamente confermata, perch valuto la condizione, allora vado sia nel banco dei registri, sia
nella memoria. Solo se un dato deve andarsi a scrivere effettivamente, perch la mia

speculazione stata confermata, posso andarlo a mettere in memoria. Il buffer funge, in un certo
senso, da anticamera sia per la scrittura dei registri che per la scrittura in memoria.

Vediamo delle architetture di rango superiore. L'obiettivo aumentare le prestazioni e questa


cosa parte dall'idea che fino ad ora siamo stati limitati da 1 condizione: il fatto che in ogni colpo di
clock, venisse prelevata dalla memoria una sola istruzione. Tutto quello che abbiamo visto, ha
previsto che in un colpo di clock prelevo unistruzione, faccio il fetch, poi il decode e via dicendo.
Poi eravamo stati bravi da gestire il fatto che, se anche listruzione non era completata, posso
avviare unaltra istruzione se quelle precedenti non sono completate. Ci siamo messi in una
condizione in cui, nella migliore delle ipotesi, siamo eseguendo un'istruzione per colpo di clock.
Abbiamo un CPI ideale di 1 ( Clock Per Istruzione) Il programma non potr essere completato in
meno di un colpo di clock per istruzione e raggiunger il CPI=1 solo se non ho beccato alcuno
stallo. Il prossimo step: come posso fare a diminuire quel CPI? Voglio impiegare meno di un
colpo di clock per istruzione. Ho una serie di possibilit; il bottle neck che se voglio eseguire pi
di un'istruzione nel colpo di clock, devo avere l'hardware per fare questo ma anche necessito di
prelevare l'istruzione e quindi praticamente, per migliorare la prestazione, devo prelevare pi
istruzioni per colpo di clock. Se riesco a fare ci, devo pensare a come gestire queste istruzioni e
posso iniziare a pensare se , effettivamente, possibile diminuire questo CPI. Laltra opzione ,
cambiare mentalit, e pensare a unistruzione che continua a prelevarne una per colpo di clock ma
al suo interno codifichi il lavoro che in una programmazione standard era richiesto in una sola
istruzione. Se quando vado in memoria a prelevare unistruzione e trovo una MULT, la eseguo e poi
prelever unaltra istruzione e via dicendo, c un modo per prelevare unistruzione sola dalla
memoria per colpo di clock ma accelerare le cose? Si, se listruzione che prelevo mi spiega un
compito che sino a oggi vedevo spiegato in una serie di istruzioni. Questo lapproccio dei
processori vettoriali: con un'istruzione codifico un task che, altrimenti, veniva codificato con tante
istruzioni, pur continuando a prelevare un istruzione per colpo di clock, miglioro le prestazioni.
L'altro approccio : miglioriamo le prestazioni prelevando pi istruzioni per colpo di clock.