l’architettura mips pipelined - di.unito.itgunetti/didattica/architettureii/02-pipeline-3.pdf ·...

of 22 /22
1 1 Concetti di base del PIPELINING L’architettura MIPS pipelined I problemi del pipelining Alcune soluzioni di base ai problemi del pipelining Versioni più sofisticate di pipeline Osservazioni conclusive. 2 L’architettura MIPS pipelined Come abbiamo visto, la semplice architettura della macchina MIPS potrebbe essere implementata in modo tale che ogni istruzione possa essere eseguita in un unico ciclo di clock lungo approssimativamente come l’insieme dei 5 cicli necessari a completare le 5 fasi. Una ragione per cui usare una macchina monociclo sia poco conveniente la conosciamo già: il ciclo lungo sarebbe uno spreco per tutte quelle istruzioni che richiedono meno tempo (cioé meno lavoro) per essere eseguite. 3 L’architettura MIPS pipelined Ma c’è un’altra ragione importante: Suddividendo l’esecuzione di ciascuna istruzione in più fasi (ossia cicli di clock), possiamo sovrapporre (almeno parzialmente) l’esecuzione di istruzioni diverse. Ad ogni ciclo di clock, mentre una porzione del datapath è impegnata nell’esecuzione di una istruzione, un’altra porzione del datapath può essere usata per eseguire un’altra istruzione.

Upload: phamminh

Post on 12-Nov-2018

225 views

Category:

Documents


0 download

TRANSCRIPT

1

1

Concetti di base del PIPELINING

•  L’architettura MIPS pipelined

•  I problemi del pipelining

•  Alcune soluzioni di base ai problemi del pipelining

•  Versioni più sofisticate di pipeline

•  Osservazioni conclusive.

2

L’architettura MIPS pipelined •  Come abbiamo visto, la semplice architettura della macchina MIPS

potrebbe essere implementata in modo tale che ogni istruzione possa essere eseguita in un unico ciclo di clock lungo approssimativamente come l’insieme dei 5 cicli necessari a completare le 5 fasi.

•  Una ragione per cui usare una macchina monociclo sia poco conveniente la conosciamo già: il ciclo lungo sarebbe uno spreco per tutte quelle istruzioni che richiedono meno tempo (cioé meno lavoro) per essere eseguite.

3

L’architettura MIPS pipelined •  Ma c’è un’altra ragione importante:

•  Suddividendo l’esecuzione di ciascuna istruzione in più fasi (ossia cicli di clock), possiamo sovrapporre (almeno parzialmente) l’esecuzione di istruzioni diverse.

•  Ad ogni ciclo di clock, mentre una porzione del datapath è impegnata nell’esecuzione di una istruzione, un’altra porzione del datapath può essere usata per eseguire un’altra istruzione.

2

4

L’architettura MIPS pipelined •  Se possiamo far partire una nuova istruzione ad ogni ciclo di clock,

ognuna delle 5 fasi della macchina MIPS multiciclo diviene uno stage di una pipeline, e lo schema di esecuzione di una sequenza di istruzioni diviene il seguente (H-P5, Fig. C.1):

istr. number

1 2 3 4 5 6 7 8 9

istr. i IF ID EX MEM WB

istr. i+1 IF ID EX MEM WB

istr. i+2 IF ID EX MEM WB

istr. i+3 IF ID EX MEM WB

istr. i+4 IF ID EX MEM WB

5

L’architettura MIPS pipelined •  Perché il pipelining funzioni, occorre però evitare di compiere

contemporaneamente due operazioni differenti che usano le stesse risorse del data path:

–  per esempio, se nel data path è presente una sola ALU, questa non può contemporaneamente calcolare l’indirizzo effettivo di una load e eseguire una sottrazione fra i due operandi di un’altra istruzione

•  L’uso di istruzioni semplici (RISC, appunto) rende di solito abbastanza facile stabilire in ogni istante quali risorse del data path sono in uso e quali libere.

•  Questo è fondamentale per sfruttare al massimo le risorse della CPU, (a maggior ragione nel multiple issue: l’avvio e l’esecuzione in parallelo di più istruzioni)

6

L’architettura MIPS pipelined •  Però, notate, nella figura precedente sono state evidenziate le fasi WB

e ID del quinto ciclo di clock. Cos’hanno di particolare?

•  Poniamo che l’istruzione i sia una load, e la i+3 sia di tipo-R: nel ciclo di clock 5 si sta contemporaneamente scrivendo nel register file il risultato dell’istruzione i e si stanno leggendo dal register file gli operandi dell’istruzione i+3.

•  Insomma, sembra proprio che stiamo cercando di usare la stessa risorsa funzionale nello stesso ciclo di clock per due istruzioni diverse…

3

7

L’architettura MIPS pipelined •  In realtà questo si può fare perché alcune unità funzionali possono

essere usate due volte in parti diverse dello stesso ciclo di clock. QUI FIGURA

•  In questo schema di esecuzione di una load, ogni fase è associata all’unità funzionale usata in quella fase: la parte tratteggiata indica che l’unità non è usata in quella porzione del ciclo di clock. (adattata da Patterson-Henessy 3rd ed., fig. 6.4):

•  Così, nella fase WB il register file viene scritto nella prima parte del ciclo di clock, mentre nella fase ID, il register file viene letto nella seconda parte del ciclo di clock.

IM IF

Reg ID

ALU EX

DM MEM

Reg WB

CC1 CC4 CC3 CC2 CC5

8

L’architettura MIPS pipelined Ed ecco allora che la pipeline MIPS può essere vista come una serie di datapath traslati nel tempo, uno per ciascuna istruzione in esecuzione. Notate ancora come è indicato l’accesso al register file, attraverso le linee tratteggiate (H-P5, Fig. C.2):

9

L’architettura MIPS pipelined

•  Sulla schematizzazione del pipelining del lucido precedente si possono fare due osservazioni:

1.  Dobbiamo necessariamente ipotizzare l’esistenza di memorie (cache) diverse per dati (DM) e istruzioni (IM), in modo da evitare conflitti tra le fasi IF e MEM. Entrambe le fasi accedono alla memoria, che ora viene interrogata 5 volte più di frequente del caso senza pipelining. La memoria deve essere in grado di sopportare questo carico di richieste.

2.  La figura non mostra la gestione del PC, che deve essere incrementato ad ogni ciclo di clock, nella fase IF (a meno che non sia l’istruzione stessa – un branch o un jump – a modificare il PC)

4

10

Registri del pipelining

•  In una implementazione reale, ogni stage della pipeline è separato e collegato allo stage successivo da opportuni registri della pipeline (ovviamente invisibili all’utilizzatore della CPU, ossia il programma in esecuzione)

•  Alla fine di un ciclo di clock il risultato, ossia l’output delle operazioni di ogni stage viene memorizzato in un registro della pipeline in modo da poter essere usato come input dello stage successivo al successivo ciclo di clock.

•  Questi registri servono anche a trasportare risultati intermedi calcolati nella pipeline tra due stage non adiacenti della pipeline (capiremo più avanti con un esempio)

11

Registri del pipelining •  Questi registri svolgono lo stesso ruolo dei (e di fatto includono i)

registri interni che avevamo introdotto per passare dalla versione monociclo a quella multiciclo della MIPS: i registri interni IR, A, B ALUoutput, ed MDR.

•  Servono cioè a rendere disponibili i valori prodotti in output da una fase della pipeline alla successiva.

•  Possiamo fare un’analogia con una catena di montaggio: quando l’operatore di una fase ha completato il suo lavoro sul pezzo, lo deposita in un contenitore, in modo da renderlo disponibile all’operatore della fase successiva.

12

Architettura MIPS con Pipeline

•  Conveniamo di chiamare l’insieme dei registri di pipeline che permettono di accoppiare due stadi adiacenti della pipeline con il nome dei due stadi. Avremo così i registri IF/ID, ID/EX, EX/MEM e MEM/WB.

•  Naturalmente questi registri devono avere una dimensione sufficiente a contenere tutti i dati che devono fluire da una fase alla successiva (P-H5,fig. 4.35, lucido successivo)

5

13

Architettura MIPS con Pipeline

14

Architettura MIPS con Pipeline •  Notate che non vi sono registri di pipeline dopo la fase WB, ossia

nello stadio di scrittura del risultato.

•  Infatti, alla fine di questo stadio tutte le istruzioni devono alterare qualche elemento di stato del processore visibile al livello ISA: il register file, la memoria dati o il PC.

•  Ad esempio, una istruzione di tipo-R modifica un registro, e il valore con cui deve essere aggiornato il registro di output può essere messo direttamente nel registro specificato nell’istruzione, dove sarà disponibile per l’istruzione successiva (ma più avanti dovremo modificare questo modo ingenuo di vedere la cosa…)

15

Registri del pipelining

IF/ID ID/EX EX/MEM MEM/WB

Il datapath di esecuzione delle istruzioni nella pipeline con i registri di pipeline tra gli stadi in evidenza (H-P5, fig. C.3):

Program execution order of the (instructions)

6

16

Esecuzione di una istruzione nella MIPS pipelined

•  Illustriamo il funzionamento della pipeline usando l’esempio di esecuzione di una load.

•  Nelle figure che seguono è evidenziata in blu la parte destra della memoria e dei registri (register file e registri di pipeline) quando questi vengono letti, ed è evidenziata in blu la parte sinistra quando questi vengono scritti.

•  Sono anche evidenziate in blu le altre unità funzionali attive in ciascuna fase.

17

Esecuzione di una istruzione nella MIPS pipelined

•  Instruction Fetch: l’istruzione viene letta dalla Instruction Memory indirizzata dal PC, e viene posta nel registro IF/ID. (Patterson-Hennessy, fig. 4.36a)

18

Esecuzione di una istruzione nella MIPS pipelined

•  Instruction Fetch: Il PC viene incrementato e riscritto in PC, ma anche salvato in IF/ID, perché potrebbe servire in una fase successiva (infatti in questo momento non si sa ancora che istruzione si sta eseguendo…).

7

19

Esecuzione di una istruzione nella MIPS pipelined

•  Instruction Decode: il registro IF/ID viene letto per indirizzare il register file. Vengono letti i due registri, anche se se ne userà uno solo. I 16 bit del valore immediato vengono convertiti in un valore a 32 bit, e i 3 valori vengono scritti in ID/EX insieme al valore incrementato del PC (Patterson- Hennessy, fig. 4.36b)

20

Esecuzione di una istruzione nella MIPS pipelined

•  EXecution: la load legge da ID/EX il contenuto del registro 1 e il valore immediato, li somma attraverso la ALU e scrive il risultato in EX/MEM. (Patterson-Hennessy, fig. 4.37).

21

Esecuzione di una istruzione nella MIPS pipelined

•  EXecution: notate come, se l’istruzione in esecuzione fosse un salto, l’ADDER userebbe il valore del PC (contenuto in ID/EX) per calcolare il valore del PC in caso di salto eseguito.

8

22

Esecuzione di una istruzione nella MIPS pipelined

•  MEMory: avviene l’accesso alla memoria dati, indirizzata dal valore letto nel registro EX/MEM. Il dato letto viene scritto in MEM/WB. (Patterson-Hennessy, fig. 4.38a).

23

Esecuzione di una istruzione nella MIPS pipelined

•  Write Back: Viene scritto il registro di destinazione della load col valore prelevato dalla memoria dati (Patterson-Hennessy, fig. 4.38b).

•  Domanda: dov’è scritto il numero del registro da modificare (ossia il registro di destinazione della load)?

24

Esecuzione di una istruzione nella MIPS pipelined

•  L’esecuzione pipelined non è semplice come sembra: nel datapath usato, durante la fase WB di una istruzione, il registro IF/ID contiene già il numero del registro di destinazione di una istruzione successiva!

•  Per evitare di caricare il dato dalla memoria nel registro sbagliato, il registro di destinazione della load non deve limitarsi a memorizzare il suo numero nel registro IF/ID, altrimenti verrebbe sovrascritto al ciclo di clock successivo, quando un’altra istruzione entra nella fase IF.

•  Durante le varie fasi di esecuzione della load, il numero del registro di destinazione va trasmesso da IF/ID attraverso ID/EX e EX/MEM fino a MEM/WB, in modo da usarlo nella fase WB per scrivere il registro giusto.

9

25

Esecuzione di una istruzione nella MIPS pipelined

•  Ecco una versione corretta del datapath pipelined per gestire la load: il numero del registro di destinazione passa attraverso tutti i registri di pipeline per essere disponibile nella fase WB della load. Ovviamente, la dimensione dei registri di pipeline deve essere estesa (di quanti bit?) per contenere anche questo valore (Patterson-Hennessy, fig. 4.41)

26

Prestazioni •  La presenza della pipeline (e quindi di hardware più sofisticato) rende

evidentemente l’esecuzione di una singola istruzione più lenta di una istruzione identica senza pipeline

•  Ma il throughput della CPU aumenta, ossia i programmi girano più velocemente. ma quanto più velocemente?

•  Supponiamo una CPU senza pipeline con i seguenti dati:

–  Operazioni con la ALU e branch richiedono 4 cicli di clock. –  Operazioni di accesso alla memoria richiedono 5 cicli di clock. –  op. ALU = 40%; branch = 20%; accessi alla memoria = 40%. –  clock = 1 ns.

27

Prestazioni •  Qual è il tempo medio di esecuzione di una istruzione?

Avg. exec time = (0,4 + 0,2) x 4ns + 0,4 x 5 ns = 4,4 ns.

•  Supponiamo ora che la CPU sia dotata di pipeline, e ipotiziamo che l’overhead introdotto ad ogni ciclo dall’hardware necessario ad implementare la pipeline sia di 0,2 ns (è un valore ragionevole). Abbiamo:

speedup = avg. exec time senza pipeline / avg. exec time con pipeline = 4,4 ns / 1,2 ns = 3,7.

•  Ossia un incremento (teorico) delle prestazioni di 3,7 volte

10

28

Problemi del pipelining •  Purtroppo, le cose non funzionano in modo così semplice. Ci sono

tre classi di problemi che possono limitare la produttività della pipeline:

1.  Problemi strutturali: quando alcune particolari combinazioni di istruzioni non possono essere eseguite simultaneamente nella pipeline a causa del numero limitato di unità funzionali disponibili (se ad esempio c’è una sola ALU non può essere usata nello stesso ciclo di clock da due diverse istruzioni )

2.  Problemi sui dati: quando una istruzione ha bisogno del risultato di una precedente ma quel dato non è ancora stato prodotto

3.  Problemi di controllo: quando vengono eseguiti branch, che possono cambiare il valore del PC: fino a che non si conosce l’esito della valutazione della condizione del branch non si sa dove prosegue l’esecuzione del programma.

29

Problemi del pipelining •  Quando si verifica uno di questi problemi è necessario fermare (to

stall) la pipeline. In particolare, quando una istruzione I genera un problema nella pipeline:

–  le istruzioni avviate prima di I (che quindi si trovano in una fase più avanzata della pipeline) possono proseguire fino ad essere completate.

–  le istruzioni avviate dopo I (che quindi che si trovano in fasi precedenti della pipeline) devono essere fermate, fino a che non viene risolto il problema dell’istruzione I.

•  Nel seguito vediamo alcune soluzioni di base ai tre tipi di problemi del pipelining, che erano già implementate nell’architettura MIPS.

•  Nel prossimo capitolo vedremo le tecniche più sofisticate che permettono ad alcune delle istruzioni avviate dopo I di proseguire la loro esecuzione indipendentemente da I.

30

Problemi Strutturali •  In generale, i problemi strutturali si verificano perché (per ragioni

di complessità o di costi di produzione) alcune risorse hardware all’interno del datapath non sono duplicate, e ovviamente non possono essere contemporaneamente usate da due istruzioni nella pipeline

•  Ad esempio, la presenza di una cache L1 unica per dati e istruzioni genererebbe frequentissimi problemi strutturali, ed è per questo che sono solitamente disponibili due cache di primo livello separate.

•  Ad esempio due istruzioni nella pipeline non possono usare la stessa ALU nello stesso ciclo di clock.

11

31

Problemi Strutturali •  Per questa ragione nelle moderne CPU (ma anche in quelle vecchie,

per la verità), molte unità funzionali, in particolare quelle combinatorie, come le ALU, sono duplicate più volte (ne vedremo più avanti vari esempi).

•  Ma ovviamente questo richiede circuiti più complessi, che consumano di più e costano di più.

•  E il progettista deve quindi trovare un compromesso tra la complessità del progetto, delle prestazioni, dei consumi e dei costi di produzione.

32

Problemi sui Dati •  I problemi sui dati si verificano perché, ovviamente, le istruzioni di

un programma non sono scorrelate da loro, e alcune istruzioni devono usare valori calcolati da istruzioni precedenti.

•  Consideriamo la seguente sequenza di istruzioni macchina:

DADD R1, R2, R3 // R1 = R2 + R3

DSUB R4, R1, R5

AND R6, R1, R7

OR R8, R1, R9

XOR R10, R1, R11

•  R1 è scritto dalla DADD nello stage WB, ma la DSUB dovrebbe usare tale valore nello stage ID, prima che sia stato calcolato!

33

Problemi sui Dati IF/ID ID/EX EX/MEM MEM/WB L’uso del

risultato della DADD nelle istruzioni successive crea un problema, perché il registro R1 viene scritto dopo che le istruzioni tentano di leggerlo (H-P5, Fig. C.6)

12

34

Problemi sui Dati

•  Notate anche la AND: la scrittura di R1 è completata alla fine del ciclo di clock n. 5, ma letta dalla AND al ciclo 4.

•  Invece, la OR opera senza problemi, perché legge R1 nella seconda parte del ciclo di clock n. 5, mentre la scrittura del registro è avvenuta nella prima parte del ciclo stesso.

•  Chiaramente anche la XOR funziona correttamente.

35

Problemi sui Dati: il forwarding

•  Una “semplice” tecnica usata per risolvere questo tipo di problemi è detta forwarding (ma anche bypassing, o short-circuiting)

•  L’idea è di rendere il risultato dell’esecuzione di una istruzione (nel nostro esempio, il risultato della DADD) disponibile per le istruzioni successive il prima possibile (prima ancora della fase WB della stessa DADD)

•  Questo può essere fatto usando i registri della pipeline che memorizzano i risultati intermedi delle varie fasi della pipeline

36

Problemi sui Dati: il forwarding

•  Si può infatti notare che il risultato dell’operazione della ALU, contenuto nei registri EX/MEM e MEM/WB, può essere riutilizzato come input della ALU stessa nei successivi cicli di clock.

•  Se la Control Unit si accorge che una precedente operazione della ALU sta scrivendo un registro che deve immediatamente essere riusato come input per la ALU stessa, preleva il valore da un opportuno registro della pipeline anziché aspettare che sia presente nel registro di destinazione.

13

37

Problemi sui Dati: il forwarding IF/ID ID/EX EX/MEM MEM/WB l’uso del

forwarding permette di evitare alcuni stall sui dati (H-P5, Fig. C.7)

38

Problemi sui Dati: un caso di stall

•  La tecnica del forwarding non può però risolvere tutte le situazioni di stalling della pipeline dovute ai dati. Considerate questa sequenza di istruzioni macchina:

LD R1, 0(R2) // indirizzo = contenuto di R2 + 0

DSUB R4, R1, R5

AND R6, R1, R7

OR R8, R1, R9

39

Problemi sui Dati: un caso di stall •  Il dato indirizzato dalla LD sarà presente nel registro MEM/WB

solo alla fine del ciclo di clock 4, mentre la DSUB ne ha bisogno all’inizio di quel ciclo.

•  In altre parole quando è coinvolta una load, fino a che il dato proveniente dalla cache (o peggio, dalla RAM) non è effettivamente presente in CPU, non può essere usato da alcuna istruzione successiva, e si verifica uno stalling della pipeline.

•  L’hardware della pipeline si accorge della situazione e ferma le istruzioni successive (per uno o più cicli di clock) fino a che non è disponibile il dato di cui hanno bisogno.

14

40

Problemi sui Dati: un caso di stall IF/ID ID/EX EX/MEM MEM/WB La LD può

passare il risultato alle AND e OR, ma non alla DSUB (H-P5, Fig. C.9)

41

Problemi di Controllo

•  I problemi di controllo si presentano quando viene eseguita un’istruzione di branch, che può cambiare il valore del PC.

•  Anche assumendo una implementazione aggressiva che esegue un branch in due cicli di clock, se il salto viene eseguito il PC non viene aggiornato fino alla fine del secondo ciclo di clock, nello stage ID, dopo che è stato calcolato l’indirizzo da inserire nel PC.

•  Quindi l’istruzione “fisicamente” successiva al branch (ossia quella all’indirizzo PC+4) ha già terminato la fase IF. Ma se il salto va effettuato non è quella la prossima istruzione da eseguire.

42

Problemi di Controllo •  Considerate questo semplice esempio:

LD R1, 0 (R4)

BNE R0, R1, else

DADD R1, R1, R2

JMP next

else: DSUB R1, R1, R3

next: OR R4, R5, R6

•  Quando sappiamo se il branch verrà eseguito, la DADD ha già completato la fase IF

15

43

Problemi di Controllo •  Un modo semplice di gestire la situazione è di eseguire comunque la

fase di fetch dell’istruzione fisicamente successiva al branch (ossia la DADD).

•  Alla fine della fase ID del branch, si sa se il salto verrà eseguito o no. Se non viene eseguito, tutto bene, la DADD prosegue con la fase ID

•  Se il salto va eseguito, si deve eseguire la DSUB, che riparte ovviamente dalla fase IF, e si è quindi sprecato un ciclo di clock: la fase IF della ADD. Ossia:

branch instr. IF ID EX MEM WB

branch succ. IFDADD IFDSUB ID EX ...

branch succ.+1 IFOR ID EX

44

Problemi di Controllo •  Ovviamente, si sprecano dei cicli di clock, il cui numero dipende dalla

frequenza dei branch in un programma, e dal fatto che in ogni specifico branch il test abbia successo o no.

•  Notate che nell’esempio visto lo spreco relativo ad un branch è al più di un ciclo di clock, perché assumiamo un datapath in grado di completare un branch in due cicli di clock

•  Istruzioni di branch che usano gli operandi in modo più complesso, possono richiedere più cicli di clock per la valutazione della condizione di salto, e l’eventuale spreco può essere molto maggiore.

45

Problemi di Controllo •  Un’altra soluzione consiste nel fare delle assunzioni a priori sulle

istruzioni di salto. Si parla allora di predizione statica dei branch. Ad esempio, l’hardware della pipeline potrebbe assumere che:

1.  Tutti i branch all’indietro sono sempre eseguiti

2.  Tutti i branch in avanti non vengono mai eseguiti

•  e continuare il fetching dell’istruzione successiva al branch in ciascuno dei due casi.

•  Se però l’assunzione è errata, l’istruzione di cui si è iniziata l’esecuzione erroneamente deve essere trasformata in una no-op, e bisogna ripartire dal fetching dell’istruzione giusta.

•  Notiamo che con una predizione statica, in caso di salto effettuato è necessario in ogni caso calcolare il valore del nuovo PC prima che sia possibile sapere qual è la prossima istruzione da eseguire.

16

46

Problemi di Controllo •  Se la maggior parte delle predizioni si rivela corretta, lo spreco di

cicli di clock risulta abbastanza limitato.

•  Ad esempio, in un loop eseguito più volte il salto all’indietro viene eseguito più volte, e quello in avanti solo quando il loop termina, e quindi una volta sola.

•  I salti in avanti possono essere usati in caso di condizioni di errore, per trasferire il controllo al codice di gestione dell’errore. Se si assume che gli errori siano rari...

•  Naturalmente, questo tipo di predizione non funziona molto bene per dei semplici if then else…

47

Problemi di Controllo •  Un ulteriore tecnica, usata già nelle prime architetture RISC, è detta

delayed branch.

•  Consiste nel piazzare dopo un branch, una istruzione che è comunque necessario eseguire, indipendentemente dall’esito del branch.

•  l’istruzione viene quindi portata a termine e solo a quel punto il salto viene (o meno) eseguito.

•  Questa tecnica richiede l’intervento del compilatore, e ovviamente non è sempre facilmente applicabile (vedremo più avanti quanto il compilatore possa essere fondamentale per migliorare le prestazioni della CPU).

48

Problemi di Controllo

il caso (a) è facile da gestire per il compilatore, ma gli altri... (H-P5, Fig. C.14).

17

49

Eccezioni •  Interrupts, trap, eccezioni di varia natura che interrompono il

normale flusso di istruzioni sono molto difficili da gestire in un sistema con pipeline, dove l’esecuzione delle istruzioni è sovrapposto.

•  In generale, quando una istruzione I genera una eccezione, la pipeline deve essere fermata, permettendo alle istruzioni dopo I di terminare, e a quelle prima di I (ma già nella pipeline) di essere fatte ripartire dall’inizio dopo che l’eccezione è stata gestita.

•  Ci risparmieremo per il resto del corso di capire come il tutto viene fatto funzionare, ma sappiate che è una cosa molto complicata, che aumenta sensibilmente la complessità della CPU (numero di transistors, consumi,...)

50

Versioni più sofisticate di Pipeline •  Lo schema della pipeline diviso in 5 stage era già usato nei primi

processori RISC, ed è ancora usato nei processori di fascia bassa, in particolare per applicazioni embedded:

–  processori per alcuni semplici tipi di console per video giochi

–  processori per stampanti laser, macchine fotografiche, videocamere,…

–  routers

51

Versioni più sofisticate di Pipeline •  Se una pipeline è efficace, perché non usarne due? Fintanto che:

–  Riusciamo a prelevare dalla Instruction Memory due istruzioni contemporaneamente,

–  le due istruzioni lanciate in parallelo non generano conflitti sull’uso dei registri, e

–  non dipendono l’una dall’altra

•  si avrà un ulteriore guadagno computazionale

•  Anche in questo caso, eventuali conflitti dovranno essere minimizzati dal compilatore, o a run time (con le tecniche che vedremo più avanti).

18

52

Versioni più sofisticate di Pipeline •  Una architettura a due pipeline con cinque (circa) stage era adottata

nel primo Pentium (ossia l’80586, il successore dell’80486). La pipeline u poteva eseguire qualsiasi istruzione macchina, mentre la pipeline v era per semplici istruzioni intere (Tanenbaum, Fig. 2.5)

BTW, Cosa c’è di “strano” in questa figura, dal punto di vista di una architettura RISC?

53

Versioni più sofisticate di Pipeline •  Le istruzioni venivano eseguite “in-order”, ossia nell’ordine in cui

comparivano nel programma (vedremo più avanti che si può anche fare diversamente) e alcune regole fisse stabilivano se due istruzioni erano compatibili, in modo da poterle eseguire in parallelo.

•  Altrimenti, veniva eseguita solo la prima, e si tentava l’accoppiamento della seconda con la terza, e così via...

•  Compilatori specifici per il Pentium erano in grado di generare codice con un alto numero di istruzioni adiacenti compatibili.

•  Un Pentium con compilatore ottimizzato faceva girare codice due volte più velocemente di un 486 con lo stesso clock

54

Versioni più sofisticate di Pipeline •  Naturalmente si potrebbe pensare di avere ancora più pipeline in

parallelo, ma le architetture moderne sono andate in una direzione leggermente diversa, introducendo più unità funzionali per l’esecuzione della fase EX (H-P5, Fig. C.33)

19

55

Versioni più sofisticate di Pipeline •  Infatti, in una CPU reale, che esegue un insieme completo di

istruzioni macchina, alcune istruzioni richiedono una fase EX molto più lunga delle altre fasi:

–  Somma/sottrazione di numeri floating point

–  moltiplicazione e divisione tra numeri interi

–  Moltiplicazione e divisione tra numeri floating point

•  eseguire queste operazioni in un unico ciclo di clock molto lungo sarebbe possibile, ma questo penalizzerebbe inutilmente le altre fasi, alle quali basta un ciclo di clock molto più breve.

56

Versioni più sofisticate di Pipeline •  Del resto, la fase EX ha bisogno di un clock breve anche quando

viene eseguita una operazione di somma o sottrazione tra interi, o una operazione logica (AND, OR) o un confronto tra i valori di due registri.

•  La soluzione ottimale è allora di:

1.  usare un ciclo di clock breve, adeguato alle fasi IF, ID, MEM, WB, e alla fase EX quando viene eseguita una operazione semplice

2.  e usare, per le operazioni più complesse, che richiedono più tempo, delle unità funzionali a loro volta suddivise in più fasi e (di solito) a loro volta pipelined.

57

Versioni più sofisticate di Pipeline •  Struttura della pipeline con unità funzionali multiple

dell’architettura MIPS (H-P5, Fig. C.35):

20

58

Versioni più sofisticate di Pipeline •  L’architettura schematizzata nel lucido precedente rappresenta bene

ad alto livello il funzionamento delle architetture moderne. Da questo schema deduciamo alcune proprietà comuni a tutte le CPU moderne:

1.  la lunghezza della pipeline dipende dal tipo di istruzione in esecuzione, e istruzioni più complesse richiedono più cicli di clock per essere eseguite.

2.  Ci possono essere più istruzioni contemporaneamente in esecuzione nella fase EX. Nel nostro esempio, potremmo avere fino a 4 operazioni di somma F.P., e 7 operazioni intere o F.P. di moltiplicazione, contemporaneamente attive.

•  (Nota tecnica: in molti casi reali l’unità di divisione è suddivisa in più fasi, ma non è pipelined)

59

Versioni più sofisticate di Pipeline •  E’ quasi inutile osservare che i problemi strutturali, sui dati e sul

controllo diventano ancora più critici da gestire e complicati da risolvere. Pensate: già il CDC 6600, a metà degli anni 60, aveva le seguenti unità funzionali:

–  4 unità floating point

–  5 unità per gli accessi in memoria

–  7 unità per le operazioni intere

60

Scheduling statico della Pipeline •  Lo schema di pipelining visto fin’ora assume che le istruzioni

vengano eseguite in ordine (in-order), ossia secondo l’ordine in cui sono incontrate dal PC. Se si verifica un problema strutturale o sui dati che non può essere risolto col forwarding, la pipeline viene temporaneamente fermata. Questo tipo di pipeline è detto Pipeline schedulata staticamente

•  Come vedremo più avanti però, le CPU moderne implementano spesso una qualche forma di scheduling dinamico della Pipeline, modificando l’ordine di esecuzione delle istruzioni per cercare di limitare l’effetto degli stall della pipeline.

21

61

Architetture superscalari •  Le architetture che sfruttano più unità funzionali nella fase EX,

vengono comunemente definite superscalari.

•  In realtà, formalmente, una architettura è superscalare se è in grado di mandare in esecuzione più istruzioni per ciclo di clock. Evidentemente, ciò è utile solo se l’architettura possiede più unità funzionali che possono operare in parallelo nella fase EX (ci torneremo ampiamente quando parleremo dell’Instruction Level Parallelism)

•  Una architettura superscalare richiede quindi un datapath più ampio, in grado di trasportare da una fase all’altra della pipeline più istruzioni in fase di esecuzione.

62

Osservazioni conclusive •  Riassumendo, le architetture RISC sono particolarmente adeguate

per il pipelining per tre motivi fondamentali:

1.  Le istruzioni hanno tutte la stessa lunghezza: ciò ne semplifica il prelievo dalla Instruction Memory nella fase IF e la loro decodifica nella fase ID.

•  Nel set di istruzioni dell’architettura 80x86 le istruzioni hanno lunghezza variabile da 1 a 17 byte, e dunque prelievo e decodifica sono più laboriosi.

•  Nei processori Intel più recenti, le istruzioni macchina vengono tradotte in microistruzioni di tipo RISC prima di procedere alla fase EX. AMD fa qualcosa di simile, e addirittura chiama queste microistruzioni “rop” da “RISC operation” (ci torneremo più avanti).

63

Osservazioni conclusive 2.  Il livello ISA di una qualsiasi architettura RISC ha un numero

ridotto di formati di istruzioni, e in tutti i formati i registri sorgente stanno sempre nella stessa posizione. (ovviamente per quanto permesso dalla semantica dell’istruzione)

•  Tale regolarità permette allo stadio ID di iniziare a leggere il register file in parallelo alla decodifica dell’istruzione da parte delle Control Unit.

•  Se ciò non fosse possibile, occorrerebbe spezzare la fase ID in due fasi separate di Instruction Decode e Operand Fetch, allungando così la pipeline (ritornate alla figura 2.5 del Tanenbaum)

22

64

Osservazioni conclusive 3.  Nelle architetture RISC gli operandi in memoria dati compaiono

solo nelle load e nelle store: questo vincolo permette di usare lo stadio EX per calcolare l’indirizzo di memoria e lo stadio successivo (MEM) per accedere alla memoria.

•  Al contrario, se si potessero specificare operazioni direttamente sugli operandi in memoria (come nelle architetture CISC) avremmo bisogno di 3 stadi: per calcolare l’indirizzo, per accedere alla memoria, per eseguire l’operazione.

•  Senza contare il fatto che la memoria costituisce un collo di bottiglia per l’esecuzione delle istruzioni.