Post on 30-Jul-2015
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 2
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
AAPPPPUUNNTTII DDII CCAALLCCOOLLAATTOORRII EELLEETTTTRROONNIICCII
Appunti e dispense con esercizi redatti da Nicola Pietroleonardo e Fabio Stroppa in base alle lezioni del
corso di “Calcolatori Elettronici” del Prof. Ing. Francescomaria Marino al Politecnico di Bari dell’anno
accademico 2009/2010.
Parte teorica a cura di Nicola Pietroleonardo.
Esercizi ed approfondimenti a cura di Fabio Stroppa.
Copyright (c) 2009-2010-2011 Nicola Pietroleonardo e Fabio Stroppa. nicola.pietroleonardo@gmail.com
fa88y@msn.com
Questo testo è pubblicato sotto licenza: Creative Commons Attribuzione - Non commerciale – Condividi allo stesso modo 2.5 Italia
http://creativecommons.org/licenses/by-nc-sa/2.5/it/
Il testo della licenza è disponibile qui: http://creativecommons.org/licenses/by-nc-sa/2.5/it/legalcode Tutte le versioni di questo testo sono disponibili nell'area download di Desfa.org. Gli autori non forniscono nessuna garanzia sulle nozioni esposte, nonché sulla precisione delle stesse; fermo restando il forte impegno degli autori nel rendere questo documento il più preciso possibile. Questo testo è da intendersi pertanto a puro scopo informativo.
EEDDIITTOORR:: NNiiccoollaa PPiieettrroolleeoonnaarrddoo
PPRROODDUUZZIIOONNEE:: NNiiccoollaa PPiieettrroolleeoonnaarrddoo,, FFaabbiioo SSttrrooppppaa
GGRRAAFFIICCAA DDII CCOOPPEERRTTIINNAA:: FFaabbrriizziioo PP.. BBaallddiinnii -- hhttttpp::////wwwwww..bbaalldduuss..aalltteerrvviissttaa..oorrgg//
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 3
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
IINNDDIICCEE GGEENNEERRAALLEE
PARTE PRIMA .................................................................................................................................. 7
SET DI ISTRUZIONI .................................................................................................................................... 8
ISTRUZIONI DI TRASFERIMENTO DEI DATI ........................................................................................................... 8
ISTRUZIONI DI TIPO M (MOV) ........................................................................................................................ 10
ISTRUZIONI DI CALCOLO ................................................................................................................................ 11
ISTRUZIONI DI CONTROLLO ............................................................................................................................ 12
TABELLA SOTTOINSIEME ISTRUZIONI DI MIPS64®. ............................................................................................. 13
ESECUZIONE DELLE ISTRUZIONI ALL’INTERNO DEL PROCESSORE – STRUTTURA DEL PROCESSORE ............................... 14
FORMATO DELLE ISTRUZIONI ....................................................................................................................... 14
CODIFICA DELL’ISTRUZIONE PER UN PROCESSORE NO-PIPELINE ........................................................................... 15
STRUTTURA DEL PROCESSORE NO-PIPELINE ..................................................................................................... 16
DESCRIZIONE DETTAGLIATA DI OGNI PASSAGGIO ............................................................................................... 17
1^ FASE IF – INSTRUCTION FETCH ............................................................................................... 17
2^ FASE ID – INSTRUCTION DECODE ........................................................................................... 17
3^ FASE EX – EXECUTION ......................................................................................................... 18
4^ FASE MEM – MEMORY ACCESS ............................................................................................. 19
5^ FASE WB – WRITE BACK ...................................................................................................... 20
RIEPILOGO .............................................................................................................................................. 21
TECNICA PIPELINE – TEMPO DI ESECUZIONE DI UN PROGRAMA .......................................................................... 23
STRUTTURA DEL PROCESSORE PIPELINE ........................................................................................................... 26
EVENTI DI CIASCUNO STADIO DELLA PIPELINE DI MIPS. ...................................................................................... 27
BREVE CENNO SULLE MEMORIE DEL PROCESSORE (CACHE DI 1°LIVELLO) – ACCESSO ALLA MEMORIA ....................... 29
ALEE STRUTTURALI – ALEE DI DATO ........................................................................................................ 31
ALEE STRUTTURALE. ..................................................................................................................................... 31
ALEE DI DATO ............................................................................................................................................. 31
1. ISTRUZIONI ALU ............................................................................................................................... 32
2. ISTRUZIONI LOAD ............................................................................................................................. 35
3. ISTRUZIONE BRANCH ......................................................................................................................... 36
MIPS PIPELINE OTTIMIZZATO ......................................................................................................................... 37
DELAY SLOT – TECNICA STATICA ..................................................................................................................... 38
TECNICA SPECULATIVA – TECNICA DINAMICA .................................................................................................... 39
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 4
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
SROTOLAMENTO DEL LOOP ....................................................................................................................... 41
PIPELINE DA PROGRAMMA ....................................................................................................................... 43
ESERCIZI DI RIEPILOGO ..................................................................................................................................... 45
ESERCIZIO 1 ................................................................................................................................................ 45
ESERCIZIO 2 ................................................................................................................................................ 48
ESERCIZIO 3 ................................................................................................................................................ 51
ESERCIZIO 4 ................................................................................................................................................ 53
ESERCIZIO 5 ................................................................................................................................................ 55
PARTE SECONDA .......................................................................................................................... 62
GERARCHIA DI MEMORIA ....................................................................................................................... 63
MECCANISMO A FINESTRA DEI REGISTRI .......................................................................................................... 63
PRINCIPI FONDAMENTALI DELLA GERARCHIA DI MEMORIA ................................................................................. 63
TRASPERENZA DEI LIVELLI .................................................................................................................. 63
PRINCIPI DI LOCALITA’ ...................................................................................................................... 64
- LOCALITA’ SPAZIALE ...................................................................................................................... 64
- LOCALITA’ TEMPORALE.................................................................................................................. 64
QUATTRO DOMANDE PER LA CLASSIFICAZIONE DELLE GERARCHIE DI MEMORIE ..................................................... 64
MEMORIE CACHE ...................................................................................................................................... 65
UN PO’ DI STORIA E CURIOSITÀ .............................................................................................................. 65
STRATEGIE DI ALLOCAZIONE DEI BLOCCHI ................................................................................................ 65
CACHE COMPLETAMENTE ASSOCIATIVA ....................................................................................................... 66
CACHE AD INDIRIZZAMENTO DIRETTO ......................................................................................................... 66
CACHE SET ASSOCIATIVA ........................................................................................................................... 66
STRATEGIE DI RICERCA E IDENTIFICAZIONE ............................................................................................... 67
STRATEGIE DI SOSTITUZIONE (FALLIMENTI DI ACCESSO) ............................................................................. 68
1. METODO RANDOM .......................................................................................................................... 68
2. METODO LRU (LAST RECENTLY USED) ................................................................................................. 68
3. METODO FIFO (FIRST IN FIRST OUT) ................................................................................................... 69
FALLIMENTI DI ACCESSO ALLA CACHE – LEGGE DELLE TRE C ........................................................................... 69
STRATEGIE DI SCRITTURA NELLA CACHE ................................................................................................... 70
1. WRITE THROUGH. ............................................................................................................................ 70
2. WRITE BACK.................................................................................................................................... 70
ELETTRONICA DELLE MEMORIE ................................................................................................................. 71
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 5
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
SRAM. ............................................................................................................................................ 71
DRAM. ........................................................................................................................................... 71
VALUTAZIONE DELLE PRESTAZIONI DELLA MEMORIA CACHE ......................................................................... 72
FUNZIONAMENTO LOGICO DI UNA MEMORIA CACHE .................................................................................. 75
CACHE POWERPC ............................................................................................................................. 75
CACHE MOTOROLA 68000 ................................................................................................................ 77
INTERAZIONE DELLE MEMORIE CACHE IN UN SISTEMA COMPLESSO ............................................................... 78
PROBLEMATICHE RELATIVE ALL’I/O..................................................................................................... 78
PROBLEMATICHE RELATIVE AI SISTEMI MULTICORE ............................................................................... 78
MIGLIORAMENTO DELLE PRESTAZIONI DELLA BANDA PASSANTE DI UNA MEMORIA ......................................... 79
BANCHI MULTIPLI DI MEMORIA PARALLELI .................................................................................................. 79
BANCHI MULTIPLI DI MEMORIA INTERLACCIATI ............................................................................................. 79
ORGANIZZAZIONE DELLE MEMORIE A SEMICONDUTTORE ............................................................................. 81
ESERCIZI DI RIEPILOGO ................................................................................................................................ 82
ESERCIZIO 1 ............................................................................................................................................ 82
ESERCIZIO 2 ............................................................................................................................................ 82
PARTE TERZA ................................................................................................................................ 84
PROCESSORE FLOATING POINT ................................................................................................................ 85
SCHEDULING DELLE ISTRUZIONI FLOATING POINT .............................................................................................. 88
ALGORITMO DI TOMASULO ....................................................................................................................... 89
APPLICAZIONE ALGORITMO DI TOMASULO - ESEMPIO ................................................................................ 91
VANTAGGI .............................................................................................................................................. 98
PARTE QUARTA ............................................................................................................................ 99
PROCESSORI VLIW ................................................................................................................................ 100
PROCESSORI SUPERSCALARI .................................................................................................................. 103
PROCESSORI VETTORIALI ....................................................................................................................... 104
TABELLA SET ISTRUZIONI VETTORIALI. ............................................................................................................ 105
OPERAZIONI DI LOAD E STORE ..................................................................................................................... 105
L’ISTRUZIONE LVWS .................................................................................................................................... 106
I REGISTRI VLR E MVLR ............................................................................................................................... 106
PRESTAZIONI ............................................................................................................................................. 107
ANALISI REALE DELL’ARCHITETTURA DI UNA CPU VETTORIALE – CRAY-1 (1976) .................................................. 108
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 6
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
SCHEMA LOGICO .................................................................................................................................... 108
IDEE ALLA BASE DELLA ORGANIZZAZIONE VETTORIALE ................................................................................. 109
CODICE VETTORIALE ............................................................................................................................... 109
ESECUZIONE ARITMETICA DELLE ISTRUZIONI ............................................................................................... 110
SISTEMA DI MEMORIZZAZIONE DI DATI VETTORIALI NEI REGISTRI VETTORIALI ................................................. 110
ESECUZIONE ISTRUZIONI VETTORIALI ......................................................................................................... 110
STRUTTURA DELLE UNITA’ VETTORIALI ...................................................................................................... 111
DIFFERENZA FRA ARCHITETTURA MEMORIA-MEMORIA E ARCHITETTURA A REGISTRI VETTORIALI ....................... 111
VETTORIZZAZIONE AUTOMATICA DEL CODICE ............................................................................................. 112
GESTIONE DI VETTORI CON DIMENSIONE SUPERIORE A MVLR – VECTOR STRIPMINING ..................................... 112
PARALLELISMO DELLE ISTRUZIONI VETTORIALI ............................................................................................. 114
PENALITA’ DI AVVIO DELLE CPU VETTORIALI ............................................................................................... 115
GESTIONE DELLE CONDIZIONI – USO DEL REGISTRO V.MASK – ISTRUZIONI MASCHERATE ................................. 115
RIDUZIONE A OPERAZIONI SCALARI ........................................................................................................... 117
ESERCIZIO ............................................................................................................................................. 118
ARCHITETTURA MULTICORE .................................................................................................................... 123
PARALLELISMO A LIVELLO DI THREAD, MULTI-THREAD .................................................................................... 124
1. SIMULTANEOUS MULTI-THREADING .................................................................................................. 124
2. FINE-GRAINED MULTI-THREADING. .................................................................................................. 124
3. COARSE-GRAINED MULTI-THREAD. ................................................................................................... 124
MEMORIA CONDIVISA E MEMORIA DISTRIBUITA IN SISTEMI MULTICORE ............................................................ 125
INDICE ANALITICO ................................................................................ 126
BIBLIOGRAFIA ...................................................................................... 127
ESERCIZI SVOLTI ................................................................................... 128
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 7
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
PARTE PRIMA
PARTE PRIMA
PROCESSORE SCALARE
ARCHITETTURA INTERA
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 8
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
SET DI ISTRUZIONI (processore di riferimento: MIPS64®) Con una pluralità di dati che si possono trattare, si va a definire un SET DI ISTRUZIONI per un processore che
usa questi dati.
TIPI DI DATI:
Floating point: sia in SINGLE PRECISION che DOUBLE PRECISION, trattandosi di dati a 32 bit e a 64
bit;
Interi: in profondità di 8, 16, 32, 64, bit e per questi numeri varrà la possibilità di averli o senza
segno (UNSIGNED) oppure con segno (SIGNED);
Quindi definiti i tipi di dati con cui il processore deve lavorare, vediamo quali sono le istruzioni che su questi
dati userà il processore. Si è deciso che il processore deve lavorare su questi dati perché, dopo aver fatto un
po’ di conti dei transistor a disposizione in un chip, è possibile integrare un certo numero di unità di calcolo
floating point a 32 o 64 bit e un ALU a che lavora con dati a 64 bit (essendo l’ALU capace di lavorare con
dati a 64 bit può anche lavorare con dati a profondità più bassa, opportunamente riempiendo i bit
mancanti).
Il processore di riferimento di questo corso è il MIPS64®.
Tutte le istruzioni che esegue il MIPS64® appartengono ad uno di questi gruppi:
Istruzioni di calcolo;
Istruzioni di accesso alla memoria;
Istruzioni di controllo;
Le istruzioni di calcolo si separano in due famiglie se il calcolo è intero (userò l’ALU) oppure se il calcolo è
floating point (userò le unità di calcolo floating point).
ISTRUZIONI DI TRASFERIMENTO DEI DATI
1ª LETTERA: indica il tipo di operazione
L indica un’operazione di tipo load, MEMORIA PROCESSORE;
S indica un’operazione di tipo store, PROCESSORE MEMORIA.
2 ª LETTERA: indica il dato che viene trattato dall’istruzione, quanti bit verranno trattati
B indica byte, quindi una parola di 8 bit;
H indica half (mezzo), quindi mezza parola ossia 16 bit (una parola è di 32 bit);
W indica word, quindi una parola intera ossia 32 bit;
D indica double, quindi una doppia parola ossia 64 bit.
3 ª LETTERA: indica se l’operazione riguarda un dato UNSIGNED (NON È SEMPRE PRESENTE)
U indica unsigned, quindi un’operazione che riguarda un dato senza segno.
Si osservi che nell’operazione di STORE non è presente, per nessun dato da trattare, la lettera U, questo
perché effettivamente l’operazione è identica per entrambi i tipi di dati. Invece è necessaria specificarla
nell’operazione di LOAD (ma non in tutte). La necessità di specificare la terza lettera risale al momento della
carica del dato; se questo è un dato binario o un dato con segno la carica deve essere fatta in maniera
diversa.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 9
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Esempio - LOAD DI UN BYTE
Questo processore ha i registri interi di 64 bit, quindi quando viene effettuata la LOAD di un byte
dalla memoria sarà letta una parola di 8 bit che verrà scritta in un registro (che come detto è di 64
bit); quegli 8 bit verranno messi nella parte meno significativa del registro.
00000101
I restanti 56 bit dovranno essere riempiti opportunamente; si è portati a pensare che questi 56 bit
potranno essere riempiti con una sequenza di 0, però questo non è sempre vero. Si suppone che il
numero letto è il numero -5; i numeri negativi vengono scritti utilizzando il complemento a 2,
quindi:
00000101
Complemento a 1 11111010 +
1
11111011
Il numero ottenuto è -5 in binario (complemento a 2).
Se invece 11111011 fosse un numero assoluto, ossia senza segno, sarebbe 255 – 4 = 251. Quindi gli
stessi bit possono significare cose diverse a seconda che si consideri un numero binario con o senza
segno.
Non a caso se sommo 251 a 5 ottengo 256, cioè se lo leggo come numero intero o lo leggo in
complemento a 2 quando poi vado a fare la somma del numero intero letto più il valore assoluto
del numero in complemento a 2 ottengo sempre 256.
Quindi nel momento della load bisogna sapere se il byte che si sta leggendo è con o senza segno,
perché se è senza segno allora riempio i 56 bit con degli 0, altrimenti se è un numero che è scritto in
complemento a 2 bisognerà riempirli non sempre con degli 0 ma con quello che è il bit di segno del
numero stesso, quindi se è un numero con segno gli 8 bit saranno riempiti con il numero binario in
complemento a 2 mentre i restanti 56 bit con la replica del bit di segno, quindi 1 nel caso esso sia
negativo.
11111111111111…………………1 11111011
Questa differenza fa si che le istruzioni per caricare un byte in un registro siano diverse. Identico
discorso vale nel momento in cui vengono effettuate load di HALF WORD (16 bit) o di un WORD (32
bit).
Nel caso della load di una DOUBLE WORD non vi è nessun problema poiché essa è già di 64 bit.
56bit + 8bit = 64 bit
56bit + 8bit = 64 bit
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 10
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Esempio - STORE DI UN BYTE
Quello che sta scritto negli altri 56 bit del registro non viene preso in considerazione; quindi
vengono presi gli 8 bit meno significativi e vengono scritti in memoria. Per questo non è presenta la
lettera U nell’istruzioni di store.
Identico discorso vale per le store di HALF WORD o di WORD.
ALTRE ISTRUZIONI DI TRASFERIMENTO DEI DATI
L.S indica un’operazione di tipo load FLOATING POINT a SINGLE PRECISION (32 bit)
L.D indica un’operazione di tipo load FLOATING POINT a DOUBLE PRECISION (64 bit)
La differenza è che una volta letti questi bit devono copiarsi non nei registri GPR (General Purpose) ma nei
registri floating point, che sono simili elettronicamente ai GPR ma non sono collegati (in hardware) all’ALU,
che fa i calcoli in aritmetica intera, bensì alle unità di calcolo floating point.
I vecchi processori a 32 bit utilizzavano registri GPR e flaoting point a 32 bit trattando questi ultimi nel
seguente modo: essendo a 32 bit non creano nessun problema nelle istruzioni L.S, però quando si trovano
ad operare con dati floating point double devono lavorare in coppia, cioè una parte del dato andrà in un
registro e l’altra in un altro, i quali devono essere adiacenti considerando come primo registro uno che
abbia un numero pari; quindi un esempio di adiacenza è F0 – F1 oppure F2 – F3. Questo perché il dato
floating point double sarà trattato in maniera tale che il primo registro associato terrà i bit che riguardano
l’esponente e una parte della mantissa, mentre l’altro conterrà i restanti bit della mantissa; in particolare,
nell’istruzione, sarà necessario solamente indicare il registro pari in cui salvare il dato floating point double,
poiché è sottointeso che verrà utilizzato anche il registro successivo.
In questo corso considereremo però il MIPS64® che ha registri e bus a 64 bit.
ISTRUZIONI DI TIPO M (MOV) Sono istruzioni che lavorano su dati che sono già all’interno del processore.
MFC0 indica un’operazione di tipo copia dati dal registro GPR a un registro speciale;
MTC0 indica un’operazione di tipo copia dati da un registro speciale ad uno GPR;
MOV.S indica un’operazione di tipo copia dati da un registro in virgola mobile a singola
precisione in un altro dello stesso tipo;
MOV.D indica un’operazione di tipo copia dati da un registro in virgola mobile a doppia
precisione in un altro dello stesso tipo;
ALU
UNITA’ DI CALCOLO FLOATING POINT
REGISTRI FLOATING POINT
REGISTRI GPR
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 11
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
MFC1 indica un’operazione di tipo copia dati da un registro GPR a un registro FLOATING
POINT;
MTC1 indica un’operazione di tipo copia dati da un registro FLOATING POINT a un registro
GPR.
L’utilità di queste ultime due istruzioni sta nel fatto che se durante l’esecuzione i dati hanno riempito tutti i
registri GPR e serve un registro per caricare un altro dato sarà possibile prendere un dato da un registro
GPR e copiarlo in un registro floating point, in modo tale da far posto al nuovo dato.
Attenzione il dato che andrà nel registro floating point non sarà assolutamente elaborato dall’unità di
elaborazione floating point, perché sarà un dato che non avrà nessun significato.
ISTRUZIONI DI CALCOLO Queste istruzioni iniziano tutte con la lettera D a significare il trattamento di dati DOUBLE. Questo perché
l’ALU è progettata a 64 bit. Le altre tre lettere indicano il tipo di operazioni che si vuole fare; la lettera U
indica che l’operazione deve essere svolta su dati UNSIGNED, operazione che risulta diversa nei dati senza
segno, ad esempio si considerino i casi di overflow, i quali sono segnalati da una parte del processore
chiamata PSW (Process Status Word) che ha un bit che segnala l’overflow.
La lettera I indica che uno degli operandi è un IMMEDIATO, ossia un dato già noto nel momento in cui il
compilatore scrive il programma eseguibile; si deduce che non è necessario salvare questo operando in un
registro, ad esempio si considerino le istruzioni per implementare un ciclo for le quali hanno la variabile
indice salvata in un registro a cui verrà sommato ogni volta un altro valore che però non è necessario
salvare in un registro (il compilatore sa già che quel valore è 1). L’immediato occupa 16 bit nell’istruzione. Si
noti che è assente la sottrazione con un immediato, questo è ovvio perché è possibile fare la somma con un
immediato con segno meno.
Vediamo un’istruzione particolare:
MADD indica un’operazione di moltiplicazione – somma, cioè è possibile in un'unica
istruzione effettuare una moltiplicazione e una somma (ad esempio: 𝑥 ∙ 𝑦 + 𝑧).
Chiaramente questa istruzione deve avere un’unità dell’ALU che operi direttamente su questa istruzione e
che quindi cominci a fare la somma appena i bit del prodotto cominciano ad essere calcolati. Quindi l’unità
di calcolo che fa la MADD non esegue prima la moltiplicazione e poi la somma, perché altrimenti si avrebbe
un’ALU lenta quanto il tempo per fare una moltiplicazione e poi una somma.
Poi ci sono le istruzioni per effettuare le operazioni logiche; in particolare istruzioni di AND si usano quando
si vogliono fare operazioni di mascheramento, cioè quando si vogliono vedere solo alcuni bit di una parola;
l’operazione di mascheramento si ottiene creando una maschera da mettere in AND con la parola da
mascherare, questa maschera permetterà di vedere solo alcuni bit del numero.
Osserviamo ora la seguente istruzione:
LUI indica un’operazione che permette di caricare nella parte alta di un registro il valore
di un immediato.
La lettera U questa volta non indica unsigned ma sta per UPPER (superiore).
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 12
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Infine analizziamo le istruzioni di scorrimento (shift) e le istruzioni d’impostazione (set).
ISTRUZIONI SHIFT
Composte dalle lettere DS e poi da altre due lettere; lo shift può essere fatto a sinistra o a destra,
troviamo per questo una L (left) o una R (right). Inoltre lo shift si caratterizza dal fatto che può
essere sia di tipo logico sia di tipo aritmetico, indicando rispettivamente con le lettere L e A.
Lo shift logico fa scorrere i bit in un verso e fa entrare degli zeri;
lo shift aritmetico viene usato per fare calcoli aritmetici.
In particolare per lo shift a destra è bene notare che esiste sia quello di tipo logico che quello di tipo
aritmetico: lo shift logico sposta i bit della parola e fa entrare degli zeri, mentre lo shift aritmetico
sposta la parola ed estende il bit di segno; per lo shift a sinistra, invece, si considera solo lo shift
logico in quanto non essendoci estensione di segno entrano solo degli zeri.
Infine può essere presente la lettera V la quale indica che lo shift avviene di un numero di posizioni
variabile.
ISTRUZIONI SET
Sono istruzioni che vanno ad impostare un registro ad un valore minore di un certo altro valore; la
prima lettera S sta per set, la seconda lettera L sta per less, la terza lettera T sta per than, infine
potrebbero essere presenti altre lettere tra cui la I (immediate) e la U (unsigned).
ISTRUZIONI DI CONTROLLO Sono istruzioni che consentono al programma di eseguire un flusso d’istruzioni diverso da quello
sequenziale, questo perché si potrebbe aver bisogno di dover saltare ad un’altra istruzione. Si distinguono
così due tipi di salti d’istruzione:
SALTO CONDIZIONATO: è un tipo di salto che viene effettuato nell’esecuzione di un programma se
la condizione da verificare è vera, altrimenti si prosegue con il normale
svolgimento sequenziale del programma. Questo tipo di salto viene
chiamato Branch, da qui l’utilizzo della lettera B come prima lettera
dell’istruzione.
SALTO INCONDIZIONATO: è un tipo di salto che viene effettuato nell’esecuzione di un programma il
quale deve andare ad eseguire un’altra istruzione, la quale non è quella
successiva, a prescindere da tutto. Questo tipo di salto viene chiamato
Jump, da qui l’utilizzo della lettera J come prima lettera dell’istruzione.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 13
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Di seguito è riportata la tabella con un riepilogo di alcune le istruzioni qui sopra presentate più altre che costituiscono il sottoinsieme di istruzioni di MIPS64®.
Tipo di istruzione/codice
operativo Significato dell’istruzione
Trasferimento di dati:
trasferisce dati tra i
registri e la memoria,
oppure tra registri (di tipo
intero, virgola mobile o
speciale); l’unica modalità
di indirizzamento della
memoria è quella con
scostamento a 16 bit, cui
sommare il contenuto di
un GPR
LB, LBU, SB Carica un byte, carica un byte senza segno, memorizza un byte (da/in
registri per interi)
LH, LHU, SH Carica mezza parola, carica mezza parola senza segno, memorizza
mezza parola (da/in registri per interi)
LW, LWU, SW Carica una parola, carica una parola senza segno, memorizza una parola
(da/in registri per interi)
LD, SD Carica una doppia parola, memorizza una doppia parola (da/in registri
per interi)
L.S, L.D, S.S, S.D Carica un SP, carica un DP, memorizza un SP, memorizza un DP
MFC0, MTC0 Copia da/a un GPR a/da un registro speciale
MOV.S, MOV.D Copia da un registro in virgola mobile a singola o doppia precisione a un
altro registro dello stesso tipo
MFC1, MTC1 Copia da 32 bit in/da registri in virgola mobile da/in registri interi
Logico/aritmetiche:
operazioni su numeri interi
o su dati di tipo logico
contenuti in un GPR; gli
overflow di operazioni
aritmetiche su numeri con
segno vengono segnalati
DADD, DADDI, DADDU,
DADDIU
Addiziona, addiziona un valore immediato (tutti i valori immediati sono
a 16 bit); con segno e senza segno
DSUB, DSUBU Sottrai; con segno e senza segno
DMUL, DMULU, DDIV,
DDIVU, MADD
Moltiplica e dividi; con segno e senza segno; moltiplica-e-addiziona;
tutte le operazioni richiedono e producono valori a 64 bit
AND, ANDI Esegui AND, esegui AND con un dato immediato
OR, ORI, XOR, XORI Esegui OR, esegui OR con un dato immediato; esegui OR esclusivo,
esegui or esclusivo con un dato immediato
LUI Carica nella parte alta un valore immediato, cioè scrivi un valore
immediato nei bit da 32 a 47 di un registro, poi estendi il segno
DSSL, DSRL, DSRA, DSLLV,
DSRLV, DSRAV
Scorri; sia in modo immediato (DS__) sia in forma variabile (DS__V); gli
scorrimenti sono logico verso sinistra, logico verso destra, aritmetico
verso destra
SLT, SLTI, SLTU, SLTIU Imposta un valore inferiore a, omposta un valore inferiore ad un valore
immediato; con segno e senza segno
Controllo:
Salti condizionati e non
condizionati; relativi al PC
o usando un registro
BEQZ, BNEZ Salta se un GPR è/non-è uguale a zero; scostamento di 16 bit da PC+4
BEQ,BNE Salta se i GPR sono/non-sono uguali; scostamento di 16 bit da PC+4
BGTZ, BLTZ Salta se un GPR è maggiore/minore a zero; scostamento di 16 bit da
PC+4
BGEZ, BLEZ Salta se un GPR è maggiore/minore o uguale a zero; scostamento di 16
bit da PC+4
BC1T,BC1F Verifica il bit di confronto nel registro di stato per le operazioni in
virgola mobile e salta; scostamento di 16 bit da PC+4
MOVN, MOVZ Copia un GPR in un altro GPR se il terzo GPR è negativo, se è zero
J, JR Salta incondizionatamente; scostamento di 26 bit da PC+4 (J) oppure
destinazione in un registro (JR)
TRAP Trasferisce il controllo al sistema operativo a un indirizzo vettorizzato
ERET Torna al codice utente da un gestore di eccezione; ripristina la modalità
utente
Il SET-ISTRUZIONI completo del MIPS64® è disponibile al seguente link:
http://www.mips.com/products/architectures/mips64/
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 14
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESECUZIONE DELLE ISTRUZIONI ALL’INTERNO DEL PROCESSORE – STRUTTURA DEL
PROCESSORE
FORMATO DELLE ISTRUZIONI Come già detto c’è la possibilità di avere un formato di istruzioni a lunghezza variabile e un formato a
lunghezza costante. Il caso che interessa è quello a formato di istruzioni a lunghezza costante e quelle che
operano in virgola fissa; le istruzioni di
questo tipo sono tutte quelle mancanti
del punto e sono tutte codificate in un
formato a 32 bit.
6 bit dedicati al codice operativo;
un numero preciso di bit che riguardano l’istruzione e quindi dipendono dal suo tipo:
o Istruzione di tipo R, cioè quell’istruzione che richiede operandi che sono dei registri e quindi
sono istruzioni che codificano operazioni ALU in cui sia il primo sorgente che il secondo
sorgente ed il destinazione sono un registro; in questo caso dovendo specificare tre registri,
ciascuno di questi richiede un numero di bit pari a 𝑙𝑜𝑔2𝑛 dove n è il numero dei registri
che il processore possiede (in questo caso sono 32 e quindi ogni registro richiede 5 bit);
segue che dopo i 6 bit del c.o. ci sono tre campi ciascuno da 5 bit; ci sono dei campi
aggiuntivi che vengono usati per estensioni del tipo di operazione da fare.
o Istruzione di tipo I, cioè quell’istruzione che richiede un immediato e quindi non è
necessario l’utilizzo di un registro per la memorizzazione del valore dell’immediato (è noto
dentro l’istruzione); sia avrà: un registro sorgente, un registro destinazione e un immediato
di 16 bit; quando poi verrà effettuato il calcolo fra il registro sorgente e l’immediato,
quest’ultimo verrà esteso a 32 bit (i 16 bit verranno copiati dall’istruzione e verranno messi
in ingresso all’ALU solo dopo averlo espanso a 32 bit, aggiungendo per 16 volte il bit di
segno). Questo tipo di istruzione viene utilizzata anche per quelle di tipo BRANCH, la quale
richiede un immediato per effettuare un salto condizionato, il quale si verifica indicando
l’indirizzo dove saltare. Sappiamo però che l’indirizzo è di 32 bit e quindi non posso avere
un indirizzo nell’istruzione, per cui si avrà un salto che sarà sempre relativo al program
counter (PC) e quindi si avrà un registro che indicherà la condizione e il valore, che una
volta esteso a 32 bit dovrà sommarsi al PC.
o Istruzione di tipo Jump, cioè quell’istruzione che richiede un immediato per effettuare un
salto incondizionato, ma non richiede di specificare la condizione; in questo caso
l’istruzione, non dovendo specificare nessun operando, ha a disposizione tutti i restanti 26
bit per indicare dove saltare, questi bit sempre relativi al PC.
Quando il processore carica un’istruzione non sa che tipo di istruzione è e quindi cosa contiene, per cui
vedremo che una volta caricata l’istruzione, andando a leggere i 6 bit del codice operativo, la control unit
saprà come interpretare i restanti 26 bit.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 15
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CODIFICA DELL’ISTRUZIONE PER UN PROCESSORE NO-PIPELINE Qualsiasi istruzione inizia la sua esecuzione nello stesso modo, perché è chiaro che il processore
nell’eseguire un’istruzione non conoscendone ancora il tipo deve comportarsi con tutte allo stesso modo.
Quindi le prime operazioni non dipenderanno dal tipo dell’istruzione; successivamente una volta che il
processore avrà compreso quella che è la particolarità dell’istruzione che sta processando, eseguirà delle
operazioni a seconda che l’istruzione è di tipo ALU, LOAD/STORE oppure di DIRAMAZIONE.
Il processore ogni volta che esegue un’istruzione lo fa eseguendo un programma, definito come
microprogramma; questo microprogramma è costituito da una serie di microistruzioni. Il microprogramma
è scritto in una micro memoria; in questa micro memoria sono quindi scritte tutti i passi del
microprogramma se la control unit, la quale si preoccupa di comandare la parte di calcolo del processore,
è stata realizzata con tecnologia MICROPROGRAMMATA.
Possiamo immaginare la control unit come un dispositivo che colpo di clock dopo colpo di clock produce
delle uscite che servono ad esempio all’ALU, al banco dei registri o alla memoria per fargli compiere delle
operazioni.
La control unit è realizzabile utilizzando due diverse tecnologie:
MICROPROGRAMMATA: ha al suo interno una struttura analoga al processore che esegue dei
microprogrammi. Lo svantaggio di questa tecnologia è che è lenta perché deve accedere ogni volta
alla memoria; il vantaggio è che aggiungendo funzionalità al processore non bisognerà sostituire la
control unit, ma bisognerà soltanto aggiungere altre microistruzioni alla micro memoria.
CABLATA: costituita da un circuito digitale, pensata come una macchina a stati, cioè un circuito
sequenziale, costituito da flip-flop e porte logiche, con memoria che produce le uscite non solo
come funzione degli ingressi ma anche come funzione delle uscite agli istanti precedenti. Il
vantaggio di questa tecnologia è che la control unit è più veloce rispetto ad unità di controllo basata
su microprogrammi; lo svantaggio è che se si va a modificare il processore, ad esempio in caso di
upgrade, bisognerà cambiare completamente la control unit e riprogettarla per adattarla al nuovo
processore.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 16
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
STRUTTURA DEL PROCESSORE NO-PIPELINE Vediamo ora come un’istruzione viene eseguita all’interno di un processore NO-PIPELINE.
Di seguito è riportato lo schema del processore.
Nelle pagine successive verranno analizzati i singoli passaggi per i seguenti tipi di istruzioni:
Memory Reference (LOAD/STORE);
Register-Register ALU operation;
Register-Immediate ALU operation;
Branch.
COMPONENTI DEL PROCESSORE
REGISTRI
- PC: Program Counter, registro speciale che contiene l’indirizzo della memoria in cui il
processore troverà l’istruzione da eseguire;
- IR: Istruction Register, registro contenente l’istruzione correntemente in esecuzione;
- REGISTERS - GPR: General Purpose, registri generali indicati con una numerazione
progressiva (R0, R1, …), usati per contenere gli operandi e i risultati parziali durante
l’esecuzione delle istruzioni;
- A e B: registri temporanei
- IMM: Immediate, registro temporaneo per memorizzare l’immediato esteso di segno;
- ALU OUTPUT: registro di output dell’ALU;
- LMD: acronimo di Load Memory Data, registro in cui si memorizza il dato in uscita dalla
Data Memory;
- COND: registro flag di 1 bit per verificare il risultato della condizione.
MEMORIE (CACHE DI 1° LIVELLO)
- INSTRUCTION MEMORY: memoria contenente le istruzioni da eseguire;
- DATA MEMORY: memoria contenente i dati su cui verranno effettuate le operazioni.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 17
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ALTRI COMPONENTI
- ALU: Arithmetic Logic Unit, si occupa di eseguire le operazioni di tipo aritmetico/logico.
- MUX: Multiplexer, dispositivo capace di selezionare un singolo segnale elettrico fra diversi
segnali d’ingresso in base ad un valore specifico determinato dal segnale di controllo.
- SIGN EXT: modulo di estensione del segno.
- ADD: modulo sommatore.
DESCRIZIONE DETTAGLIATA DI OGNI PASSAGGIO
1^ FASE IF – INSTRUCTION FETCH
Dopo aver dato all’ Instruction Memory il contenuto di PC, questa
scarica l’istruzione generata nell’Instruction Register (IR).
Contemporaneamente il PC va in ingresso al modulo sommatore
(ADD) che riceve come altro ingresso un valore costante pari a 4 (4
byte – 32 bit – istruzione successiva); il risultato salvato in NPC (New
PC) sarà il nuovo valore del PC. Tutto questo vale se nell’ Instruction
Memory è presente l’istruzione, altrimenti si va in stallo (in attesa).
In sintesi: IR MEM[PC] NPC PC + 4
2^ FASE ID – INSTRUCTION DECODE
Ora che l’istruzione è nell’IR, quindi è all’interno del processore, viene
effettuata la sua decodifica e in contemporanea il processore esegue la pre-
carica dei coefficienti, ossia il prelievo dei bit dall’istruzioni che si
potrebbero riferire agli operandi e il salvataggio di essi nei GPR; i registri
che possibilmente contengono gli operandi saranno messi in registri
temporanei A e B, pronti per essere processati dall’ALU, mentre l’operando
che potrebbe indicare il registro destinazione verrà esteso in segno (portato
a 32 bit) e conservato nel registro temporaneo IMM (trattarlo come un
immediato non comporta nessun problema).
Al termine della decodifica il processore saprà il tipo dell’istruzione da
eseguire e quindi sapere se i 16 bit si riferivano ad un registro destinazione
o ad un immediato e se i registri A e B contengono gli operandi o semplici
indirizzi.
In sintesi: A Regs[IR6..10] B Regs[IR11..15] Imm ((IR16)
16##IR16..31)
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 18
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
3^ FASE EX – EXECUTION L’ALU opererà su tutti gli operandi preparati nella fase di decode, effettuando una delle quattro funzioni a
seconda del tipo d’istruzione:
Memory Reference (LOAD/STORE)
I MUX passano all’ALU il valore del registro A e il valore del registro
IMM; l’ALU li somma per formare l’indirizzo effettivo della memoria.
Il risultato viene inserito nel registro ALU OUTPUT;
In sintesi:
ALUOUTPUT A + IMM
Register-Register ALU instruction
I MUX passano all’ALU il valore del registro A e il valore del registro
B; l’ALU esegue l’operazione specificata dal codice operativo.
Il risultato viene inserito nel registro ALU OUTPUT;
In sintesi:
ALUOUTPUT A op B
Register-Immediate ALU instruction
I MUX passano all’ALU il valore del registro A e il valore del registro
IMM; l’ALU esegue l’operazione specificata dal codice operativo.
Il risultato viene inserito nel registro ALU OUTPUT.
In sintesi:
ALUOUTPUT A op IMM
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 19
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Branch
I MUX passano all’ALU il valore dell’NPC e il valore del
registro IMM; l’ALU li somma per calcolare l’indirizzo
della destinazione del salto.
Il risultato viene inserito nel registro ALU OUTPUT.
Il valore di A viene utilizzato per determinare se il salto
viene effettuato; l’operazione di confronto dipende dal
codice operativo dell’istruzione di branch (ad esempio
può essere l’istruzione di BEQZ).
In sintesi:
ALUOUTPUT NPC + IMM Cond ( A op 0 )
4^ FASE MEM – MEMORY ACCESS
Le uniche istruzioni attive in questa fase sono quelle LOAD, STORE e BRANCH
Memory Reference (LOAD)
Con l’indirizzo calcolato durante la fase precedente e memorizzato nel
registro ALUOUTPUT, si accede alla DATA MEMORY.
La Data Memory restituisce il dato richiesto che si memorizza nel registro
LMD.
In sintesi:
LMD Mem[ALUOUTPUT]
Memory Reference (STORE)
Con l’indirizzo calcolato durante la fase precedente
e memorizzato nel registro ALUOUTPUT, si accede
alla DATA MEMORY.
Il dato del registro B viene scritto nella Data
Memory a quell’indirizzo.
In sintesi:
Mem[ALUOUTPUT] B
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 20
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Branch
Se la condizione è verificata, il
segnale proveniente dal registro
flag COND fa da controllo, allora
il PC viene aggiornato con il
valore calcolato nella fase
precedente e memorizzato nel
registro ALUOUTPUT.
In caso contrario il PC verrà
aggiornato con il valore del
registro NPC.
In sintesi:
if (cond) PC ALUOutput else PC NPC
5^ FASE WB – WRITE BACK
Register-Register/Immediate ALU instruction
Il MUX passerà al banco dei registri GPR il valore
del registro ALUOUTPUT.
Questo valore andrà a salvarsi nel registro
identificato dal terzo operando.
Lo stesso discorso vale per le istruzioni
Register – Immediate.
Load instruction
Il MUX passerà al banco dei registri GPR il valore
del registro LMD.
Questo valore andrà a salvarsi nel registro
identificato dall’operando.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 21
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Tutto quanto spiegato funziona nell’ipotesi che il processore esegue un’istruzione per volta (NO-PIPELINE);
si noti che durante l’esecuzione dell’istruzione si attraversa il processore a fette, come se fosse un tubo,
tralasciando le operazioni effettuate e che quindi non servono più. Quindi l’idea è quella di immaginare il
processore come un tubo diviso in stadi, da qui PIPELINE; quando un’istruzione entra, esegue le sue
operazioni nel primo stadio e poi passa al secondo, posso far entrare una nuova istruzione. Questo significa
eseguire un’istruzione in un tempo approssimativamente più piccolo; quindi è necessario modificare il
processore avendo fra uno stadio ed un altro una serie di banchi che eseguiranno delle specifiche
operazioni.
Per concludere viene riportato uno schema per ogni tipo d’istruzione.
Riepilogo ISTRUZIONE LOAD
ISTRUZIONE ALU GPR op GPR
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 22
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ISTRUZIONE ALU GPR op IMM
ISTRUZIONE STORE
ISTRUZIONE BRANCH
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 23
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
TECNICA PIPELINE – TEMPO DI ESECUZIONE DI UN PROGRAMA La PIPELINE sfrutta la seguente osservazione: quando un’istruzione viene eseguita, attraversando il
processore a fette, lasciando alle sue spalle parti di esso che l’ha elaborata; per cui si potrebbero usare
queste parti per eseguire un’altra istruzione.
Prima di entrare nello specifico della PIPELINE vediamo se effettivamente questa struttura è conveniente;
supponiamo che un’istruzione per essere eseguita da un processore richieda un tempo T, definito tempo
medio.
Se un programma ha N istruzioni la sua esecuzione richiederà un tempo pari a NT, dove N non è un
numero di istruzioni statico (cioè quelle che compongono il listato) ma bensì dinamico, cioè quelle che
effettivamente vengono eseguite.
Potendo implementare una struttura a pipeline possiamo far sì che la seconda istruzione inizi la sua
esecuzione quando la prima istruzione libera la prima parte di processore.
Si osservi il seguente grafico:
La prima istruzione dura 5 colpi di clock (CC) T = 5 CC;
la seconda istruzione invece di partire al colpo di clock 6, quando è terminata la prima istruzione, inizia al
colpo di clock 2, questo è possibile perché al CC 2 la prima istruzione ha liberato la parte di processore che
accede alla IM (Instruction Memory). Anche la seconda durerà 5 CC.
Invece di durare un tempo pari a NT, il programma durerà:
𝑇 + 𝑁 − 1 𝑡
T: tempo di esecuzione della prima istruzione (in questo caso 5 CC)
t: tempo di una fase singola (in questo caso 1 CC), contare per N-1 volte. In generale vale: 𝑡 =𝑇
𝑛𝑙 𝑜𝑝𝑝𝑢𝑟𝑒
𝑇
𝑝𝑝
nl: numero di livelli pipeline (in questo caso 5 livelli).
pp: profondità della pipeline, per profondità si intende il numero d’istruzione contemporaneamente dentro
alla pipeline.
Queste ultime due grandezze coincidono, ma concettualmente sono due cose diverse.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 24
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Quindi:
𝑇 + 𝑁 − 1 𝑇
𝑛𝑙= 𝑇 +
𝑁𝑇
𝑛𝑙−
𝑇
𝑛𝑙=
𝑛𝑙𝑇 + 𝑁𝑇 − 𝑇
𝑛𝑙=
𝑁𝑇
𝑛𝑙+ 𝑛𝑙 − 1 𝑇
𝑛𝑙
con 𝑛𝑙−1 𝑇
𝑛𝑙 parametro trascurabile;
Sul termine 𝑁𝑇
𝑛𝑙 è possibile fare dei ragionamenti:
si è partiti dal presupposto che 𝑡 =𝑇
𝑛𝑙 , il quale potrebbe essere vero soltanto se il tempo di esecuzione di
un’istruzione fosse diviso in nl parti di durata uguale (in questo caso la pipeline si dice perfettamente
bilanciata), ma non è sempre possibile; si deduce che non è possibile imporre a piacere il valore di t.
Quindi il grafico presentato funzionerebbe correttamente se ciascuna fase durasse il tempo della fase più
lenta, che denominiamo TC; in realtà si dovrà considerare che nella struttura del processore pipeline fra
ogni passo c’è un blocco (latch - grigio nel disegno della pagina seguente) necessario se il processore lavora
su più istruzioni contemporaneamente, quindi bisogna considerare, oltre al tempo di lavoro netto per
effettuare il preciso passo, il tempo di lettura e scrittura dei latch; quindi il tempo di una fase diventerà:
𝑡 = 𝑇𝐿 + 𝑇𝐶 + 𝑇𝑆
TL: tempo di lettura del latch
TC: tempo di calcolo della fase più lenta
TS: tempo di scrittura del latch
Generalmente si pensa la pipeline costituita da 5,6 o 7 stadi, ma è possibile pensare la pipeline in altri due
modi:
UNDER-PIPELINE: numero di stadi ridotto, inferiore a 5;
t diventa più grande comportando la realizzazione di una CU più semplice.
SUPER-PIPELINE: numero di stadi alto, maggiore di 7;
t diventa più piccolo comportando la realizzazione di una CU più complessa.
Ovviamente tutto questo detto fino ad ora si può considerare in una idealizzazione del funzionamento della
pipeline; infatti bisogna considerare le situazioni in cui si perdono dei colpi di clock per effettuare
determinate istruzioni.
Si pensi alle istruzioni di branch:
al primo CC arriva questo tipo di istruzione;
al secondo CC per caricare l’istruzione successiva bisogna conoscere qual è questa istruzione da eseguire.
La prima istruzione deve calcolare l’indirizzo per effettuare il salto e salvarlo nel PC, ma questo verrà
effettuato in fasi successive quando l’ALU effettuerà le sue operazioni.
Per cui partiranno altre istruzioni, ma solamente nel momento in cui verrà aggiornato il PC verrà eseguita la
giusta istruzione; le istruzioni partite saranno bloccate con conseguente perdita di tempo. Per cui bisognerà
aggiungere al calcolo del tempo i colpi di clock sprecati.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 25
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESEMPIO
La prima è un istruzione di tipo R di somma fra i registri R2 e R3 con registro destinazione R1;
Regs R1 ← Regs[R2] + Regs[R3]
La seconda istruzione richiede di usare il registro R1 con il registro R5 per fare una differenza e scrivere il
risultato nel registro destinazione R4;
Regs R4 ← Regs R1 − Regs[R5]
È evidente che R1 non è ancora disponibile o meglio sono solo presenti dei bit che non hanno significato;
quindi la CU dovrà in qualche modo bloccare l’istruzione per poi farla ripartire quando R1 sarà disponibile.
Questo comporta una perdita di colpi di clock.
In seguito vedremo opportune soluzioni per risolvere questi problemi.
L’obiettivo per cui è stato mostrato questo esempio è quello di far comprendere che il tempo per eseguire
un programma dipende quindi da molti fattori.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 26
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
STRUTTURA DEL PROCESSORE PIPELINE Di seguito è riportato lo schema del processore.
Fondamentalmente rispetto al processore NO-PIPELINE ci sono delle grosse differenze:
nel processore NO-PIPELINE sono presenti vari registri temporanei come i registri IR, A, B, IMM,
ALUOUTPUT, ecc; mentre nel processore PIPELINE questi registri sono stati inseriti nei latch (blocchi grigi).
Questa scelta è dovuto al fatto che questo processore esegue più istruzioni per volta; se per esempio
un’istruzione si trova nell’ultima fase quella di WB, il MUX vedendo il codice operativo dell’IR sa quale dato
far andare nel banco dei registri. Nel caso di un processore no-pipeline non vi erano problemi perché l’IR
manteneva l’informazione per tutta la durata dell’esecuzione dell’istruzione; nel processore pipeline ogni
latch contiene il valore del registro IR che ogni colpo di clock si copia nel latch successivo, questo perché
con l’arrivo di una nuova istruzione l’IR viene modificato, per cui si avrebbe una perdita di dati. Quindi
tornado all’esempio, in cui l’istruzione si trova nella fase di WB, il MUX preleverà il valore del registro IR dal
latch che lo precede.
Si noti inoltre il MUX che si trova dopo l’ADD tra il PC e 4. Rispetto al no-pipeline si trova avanti perché è
importante che il PC sia aggiornato mentre l’istruzione termina la prima fase, per far si che si possa
prelevare la prossima istruzione.
Quindi ci sono alcuni registri che sono propagati latch per latch, chiamati sempre allo stesso modo del no-
pipeline, però per effettuare l’accesso bisogna specificare a quale latch ci si riferisce; ad esempio IF/ID.IR
per indicare il registro IR che si trova nel latch IF/ID.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 27
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Di seguito sono riportati gli eventi di ciascuno stadio della pipeline di MIPS.
Vediamo quali azioni dei vari stadi sono caratteristiche dell’organizzazione della pipeline. Nello stadio IF,
oltre a reperire l’istruzione e calcolare il nuovo valore di PC, memorizziamo tale nuovo valore sia in PC sia in
un registro di pipeline (NPC) per poterlo usare eventualmente in seguito per il calcolo dell’indirizzo di
destinazione di un salto. Nello stadio ID reperiamo i registri, estendiamo il segno dei 16 bit meno
significativi di IR e trasferiamo allo stadio successivo i valori di IR e NPC. Nello stadio EX eseguiamo
un’operazione nella ALU oppure calcoliamo un indirizzo, trasferendo allo stadio successivo il contenuto dei
registri IR e B (se si tratta di un’istruzione store); inoltre, se l’istruzione è una diramazione e il salto viene
effettuato, poniamo uguale a 1 il valore di cond. Nello stadio MEM eseguiamo le azioni riguardanti la
memoria, se richiesto scriviamo il registro PC e trasferiamo allo stadio finale i valori che sono ad esso
necessari. Infine, nello stadio WB aggiorniamo l’opportuno registro, in base al valore calcolato dalla ALU o
letto dall’istruzione load. Per semplicità trasferiamo sempre l’intero IR da uno stadio all’altro, anche se, al
procedere dell’istruzione all’interno della pipeline, è necessaria una porzione sempre più piccola di tale
informazione.
Bisogna tener sempre presente che ogni stadio è sempre operativo per un’istruzione diversa, per cui le
operazioni avvengono in contemporanea, però c’è una tempistica che evita la sovrascrittura dei registri.
IF/ID.NPC ← PC+4; IF/ID.PC ← (if ((EX/MEM.opcode == branch) || (EX/MEM.opcode == jump) & EX/MEM.cond)
{EX/MEM.ALUOutput} else {PC+4});
←
Se l’istruzione è una BEQZ allora:
EX/MEM.cond ← (if (ID/EX.A == 0) {1});
Se l’istruzione è una BNEZ allora:
EX/MEM.cond ← (if (ID/EX.A != 0) {1});
Bisogna considerare anche i casi in cui
l’istruzione è una BNQ o una BNE;
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 28
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Ricapitolando, si è visto come questo processore così strutturato può eseguire più istruzioni
contemporaneamente e come, quindi, alcune risorse devono essere replicate; idealmente si avrà
l’esecuzione di un’istruzione in un numero di fasi costante ma in realtà questo non sarà vero perché alcune
istruzioni o saranno avviate inutilmente oppure dovranno essere bloccate in attesa di un informazione che
deve essere prodotta dalle istruzioni precedenti. Si parla quindi di ALEE del processore che possono essere:
ALEE DI DATO: un’istruzione viene bloccata perché aspetta la disponibilità di un dato.
ALEE STRUTTURALI: un’istruzione viene bloccata perché aspetta la disponibilità dei componenti del
processore.
ALEE DI CONTROLLO: un’istruzione viene bloccata perché aspetta la modifica del PC, in casi
diramazione o salti
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 29
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
BREVE CENNO SULLE MEMORIE DEL PROCESSORE (CACHE DI 1°LIVELLO) – ACCESSO ALLA MEMORIA Nel processore ci sono due memorie cache di 1° livello distinte perché si ha bisogno di un’unità su cui scrivere e leggere le istruzioni e un’unità su cui scrivere e leggere i dati; devono essere distinte per evitare un alea strutturale gravissima, che comporterebbe uno spreco di colpi di clock. Questo idea di organizzazione è definita come architettura Harvard. Successivamente affronteremo la trattazione della memoria; ora ci soffermiamo su un singolo aspetto che è quello dell’ACCESSO ALLA MEMORIA. La memoria è pensata in questa maniera: LOAD: Viene inviato un indirizzo alla porta indirizzo fatto da un certo numero di bit e all’interno individuerò una parola, fra 2𝑛 parole, che uscirà fuori dalla porta dati. STORE: Viene inviato un indirizzo e un dato alla porta d’ingresso, l’indirizzo individuerà la locazione su cui andrà a scrivere il dato. Un requisito della memoria è la profondità di parola: cioè la parola in uscita avrà una certa quantità di byte che sarà un potenza di 2 (per esempio 32 o 64 bit). Supponiamo che i dati siano di 4 byte (32 bit), focalizziamo l’attenzione sul seguente tipo di accesso alla memoria:
ACCESSO ALLINEATO: i 4 byte verranno scritti/letti in posizioni che sono rigidamente fisse, in questa maniera:
Se si vuole leggere una parola che parte ad esempio dal byte 2 al byte 5 non è possibile farlo. Quindi l’indirizzo che la memoria riceve e che poi conterrà il dato che manderà in uscita è multiplo dell’unità su cui è allineata la memoria. Ad esempio se è allineata a 4 byte l’indirizzo sarà multiplo di 4. Quindi non è possibile accedere in maniera casuale. Questo tipo di accesso semplifica notevolmente la gestione del lavoro e della circuiteria interna della memoria.
Si parla di allineamento 4 byte intendendo che un indirizzo avrà gli ultimi due bit nulli: 16 bit punteranno ad una riga altri 16 ad una colonna; la cella di memoria corrispondente potrà andare in uscita o ricevere un dato. Bisogna comunque garantire che se per errore si dovesse accedere ad un dato che non è allineato, in qualche modo bisognerà saperlo leggere.
PORTA INDIRIZZO PORTA DATI
PORTA D’INGRESSO PORTA DI USCITA
0 3 4 7 8 11
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 30
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Ad esempio si supponga la seguente situazione di LOAD:
L O C U
La parola LOCU non potrà essere letta perché l’indirizzo non avrà gli ultimi due bit uguali a zero, ma solo l’ultimo. Per leggere la parola devo:
1. LOAD dei primi 4 byte; 2. LOAD dei successivi 4 byte; 3. SHIFT di 16 bit dei primi 4 byte; 4. SHIFT di 16 bit dei successivi 4 byte; 5. operazione di OR per ottenere la parola LOCU.
Si supponga ora la seguente situazione di STORE: Si vuole scrivere la parola LOCU a partire dall’indirizzo 15; non si deve però andare a modificare il contenuto degli altri indirizzi.
e R p L O C U h Per scrivere devo:
1. LOAD dei primi 4 byte, quindi a partire dall’indirizzo 12; 2. LOAD dei successivi 4 byte, quindi a partire dall’indirizzo 16; 3. STORE a partire dall’indirizzo 12, dei 4 byte modificati; 4. STORE a partire dall’indirizzo 16, dei successivi 4 byte modificati.
12 14 16
4 byte 4 byte
12 14 16
4 byte 4 byte
13 15 18 17
19
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 31
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ALEE STRUTTURALI – ALEE DI DATO Abbiamo visto, con il concetto di ALEE STRUTTURALI e ALEE DI DATO, che in realtà il processore stesso ha
comportamenti che lo allontanano da quelli ideali.
ALEE STRUTTURALE: un’istruzione viene bloccata perché aspetta la disponibilità dei componenti del processore. Si osservi la figura qui accanto; nel caso il processore non abbia una memoria separata per le istruzioni e per i dati si incorre in un blocco strutturale poiché l’istruzione 3 non può utilizzare il componente memoria; quindi questa istruzione, così come tutte quelle seguenti, verrà ritardata di un colpo di clock. La soluzione a questo tipo di problema è
l’utilizzo di un’architettura Harvard.
ALEE DI DATO: un’istruzione viene bloccata perché aspetta la disponibilità di un dato. Esistono conflitti di dati che teoricamente possono essere di quattro tipi:
1. READ AFTER WRITE (RAW): generato da dipendenze di dato tra istruzioni sequenziali “vicine”, cioè
un’istruzione tenta di leggere un registro prima che sia stato scritto; nel
processore intero, grazie alla corto circuitazione dell’ALU questo
problema non esiste a meno del caso delle istruzioni di load.
Nell’aritmetica floating point questo conflitto è molto rilevante.
DADD R0, R1, R2; // Write R0
DSUB R2, R0, R3; // Read R0
2. WRITE AFTER WRITE (WAW): si ha quando il valore di un registro viene aggiornato prima
dall'istruzione più recente e poi da quella meno recente. Quindi, la
seconda scrittura va persa. In un processore di tipo intero questo
problema non esiste perché quando un’istruzione è nella fase di WB
tutte le istruzioni precedenti sono terminate, ed essendo terminate
hanno già fatto la fase di WB. Nell’aritmetica floating point questo
conflitto è molto rilevante.
DADD R1, R0, R2; // Write R1
. . .
DSUB R1, R2, R3; // Write R1
3. WRITE AFTER READ (WAR): un’istruzione tenta di scrivere un registro prima che sia stato letto;
nel processore intero questo problema non esiste perché quando
l’istruzione è nella fase di WB tutte le altre saranno terminate e quindi
tutto procederà correttamente. Nell’aritmetica floating point questo
conflitto è molto rilevante.
DADD R0, R1, R2; // Read R1
DSUB R1, R2, R3 // Write R1
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 32
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
4. READ AFTER READ (RAR): non è una dipendenza. È possibile anche invertire l’ordine di esecuzione.
Di seguito sono riportati tre casi in base alle istruzioni schedulate.
1. ISTRUZIONI ALU: si osservi la figura qui accanto; il
registro destinazione (R1) della prima istruzione
(DADD) è un registro sorgente per la seconda
istruzione (DSUB) ma anche per la terza
istruzione (AND). R1 ospiterà effettivamente la
somma fra R2 e R3 nel quinto colpo di clock;
essendo il programma eseguito in pipeline, la
seconda istruzione porterà nel quarto colpo di
clock in ingresso all’ALU dei bit che non avranno
nessun significato. Lo stesso vale per le altre
istruzioni; solo l’ultima istruzione effettuerà
regolarmente la sua operazione, poiché sarà
stata effettuata la Write Back.
Verrà analizzata ora una tecnica per evitare questo tipo di blocco: si consideri la quarta istruzione che
parte tre colpi di clock dopo la prima istruzione: R1 viene scritto nel quinto colpo di clock (fase di WB). In
questa fase per l’istruzione OR, R1 verrà preso è messo nel registro A; bisognerà capire se R1 che andrò
a scrivere in A è quello che è stato scritto dalla fase di WB. Poiché prima avvengono le letture e poi le
scritture, in realtà non avrò l’effettivo valore di R1.
Si esamini la profondità della pipeline al quinto
colpo di clock , e le fasi che la costituiscono: tutte le
fasi dureranno quanto la fase più lenta, che è quella
di accesso alla memoria. La fase di WB è
estremamente veloce (legge ALUOutput oppure LMD e scrive in un registro); bisognerà comunque
eseguire WB in un tempo che è comunque legato alla durata della fase più lenta: per cui se viene
garantita una tempistica che esegue la fase WB nella prima metà del colpo di clock e la fase di carica dei
coefficienti A e B nella seconda metà, l’istruzione non darà nessun problema di esecuzione.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 33
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Risolta l’alea con la quarta istruzione schedulata, vediamo come risolvere il problema legato alle
istruzioni schedulate nel secondo e terzo colpo di clock.
In realtà per la seconda istruzione non serve che il risultato della somma fra R2 e R3 venga letto
direttamente dal registro R1, cioè interessa sottrarre a R5 la somma precedente che sarà possibile
trovare in EX/MEM.ALUOutput. Stesso discorso vale per la terza istruzione: il valore della somma lo
troverà in MEM/WB.ALUOutput.
Utilizzando questo metodo il processore cambia la sua struttura, dove in ingresso ai MUX, che decidono quale segnale mandare all’ALU, non si hanno soltanto i registri A e B oppure IMM ma si ha la possibilità di ricevere EX/MEM.ALUOutput oppure anche MEM/WB.ALUOutput. In questo modo non si avranno perdite di colpi di clock e quindi nessun blocco d’istruzioni. La Control Unit sarà un po’ più complessa perché dovrà
controllare i MUX e questo viene fatto attraverso una
logica che si basa sui comparatori, il cui compito è quello
di confrontare i registri. Sono presenti due comparatori
per ogni MUX.
Nel caso l’istruzione è a un colpo di clock dopo,
all’ingresso del comparatore si ha:
1. il campo *rs+ dell’IR dell’istruzione che sta in
fase di EX;
2. il campo *rd+ dell’IR dell’istruzione che sta in
fase di MEM.
Quindi il MUX, all’ingresso dell’ALU, farà passare EX/MEM.ALUOutput se sono uguali i valori ed è
verificato il codice operativo.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 34
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Nel caso l’istruzione è a due colpi di clock dopo, all’ingresso del comparatore si ha: 1. il campo *rs+ dell’IR dell’istruzione che sta in
fase di EX;
2. il campo *rd+ dell’IR dell’istruzione che sta in
fase di WB.
Quindi il MUX, all’ingresso dell’ALU, farà passare MEM/WB.ALUOutput se sono uguali i valori ed è
verificato il codice operativo.
Identico discorso vale per il secondo MUX a patto che si consideri il campo rt dell’IR e non rs.
Se entrambi i comparatori verificano l’uguaglianza dovrà essere dato in ingresso all’ALU il risultato della
seconda operazione, cioè quella che è ancora fra EX/MEM e quindi il primo caso.
All’interno di questa logica vi è anche una rete combinatoria che effettua il test sul codice operativo;
questo perché il risultato della comparazione è interessante solo se si sta considerando un’istruzione
ALU in cui i bit che si riferiscono al campo rd sono proprio i bit destinatari del risultato dell’operazione
ALU. L’uscita di questa rete combinatoria di test è in AND con il comparatore per verificare se
considerare o meno il risultato del comparatore.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 35
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
2. ISTRUZIONI LOAD: si osservi ora il caso in cui un registro è destinazione di un’operazione di tipo LOAD.
LD R1,0(R2)
DSUB R4,R1,R5
AND R6,R1,R7
Essendo R1 risultato di un’operazione di
LOAD il valore (che andrà in R1) sarà noto
solo dopo la fase di MEM è quindi sarà
presente nel latch MEM/WB.LMD; dal
punto di vista temporale questa
operazione avviene successivamente
rispetto a quando la seconda istruzione si
trova nella fase di EX; in questo caso il
processore andrà in stallo fermando così
tutte le istruzioni successive che
richiederanno quel dato. (ved. fig. sotto).
Invece se l’istruzione è schedulata due
colpi di clock dopo, e in ingresso all’ALU si
vuole il valore di R1, si andrà a prendere questo valore da MEM/WB.LMD; questo è il terzo ingresso
retro azionato che arriva al MUX. Occorrerà un altro comparatore (per ogni MUX) che prenderà il
registro sorgente dell’istruzione corrente ID/EX.IR*rs+ e lo confronterà con il registro destinazione
dell’istruzione due colpi di clock prima MEM/WB.IR*rd+. Il risultato sarà messo in AND con il segnale
d’uscita del circuito combinatorio che effettuerà il test su MEM/WB.IR[opcode]. Se si verificano i
controlli in ingresso all’ALU andrà MEM/WB.LMD.
È possibile evitare lo stallo organizzando, a livello del compilatore, il codice del programma in maniera
tale da non avere mai dopo una load un’istruzione che vuole come sorgente il destinazione
dell’istruzione di load. Questa è altre tecniche software aiutano il compilatore; dal punto di vista
hardware non ci sono soluzioni.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 36
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
3. ISTRUZIONE BRANCH: se la condizione di salto si verifica (al termine della fase EX) le istruzioni che erano
state avviate, poiché successive a
quella di salto, devono essere
abortite per poter proseguire con
l’istruzione ove si è saltati. Questo
significa che si perderanno dei colpi
di clock non per situazioni di stallo
ma per aver eseguito istruzioni
inutilmente; bisognerà cercare di
ridurre al minimo questi colpi di
clock sprecati. Solo alla quarta
istruzione si conoscerà il valore del
salto da effettuare e quindi può
essere effettuata la fase di IF con il
PC corretto.
Questo significa che saranno stati persi tre colpi di clock, cioè un’istruzione di salto è come se durasse
quattro istruzioni.
È possibile con una tecnica hardware ridurre i colpi di clock persi; l’operazione di calcolo dell’indirizzo in
cui saltare è effettuato nella fase di EX poiché li è presente l’ALU. Però si può accelerare questa
operazione pensando di effettuare questo calcolo nella fase ID, perché in fondo per il calcolo serve lo
spiazzamento e il PC, dati che in questa fase sono noti. Per effettuare il calcolo non bisogna dimenticare
che è necessaria l’ALU, la quale è utilizzata da un’altra istruzione; però effettivamente non è necessaria
un’altra ALU ma un semplice sommatore. Quindi si inserisce un sommatore aggiuntivo nella fase ID che
prende l’immediato esteso in segno, prende il PC e li somma; se la condizione è verificata IF/ID.PC verrà
aggiornato al valore calcolato. Il processore sarà così modificato in questi termini:
Con questa tecnica si avrà la perdita di un colpo di clock invece di due (non considerando l’istruzione di
branch).
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 37
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
MIPS PIPELINE OTTIMIZZATO
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 38
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
DELAY SLOT – TECNICA STATICA Si è visto come è possibile, aggiungendo un sommatore nella fase ID, conoscere se è dove saltare già alla
seconda fase dell’esecuzione dell’istruzione di salto; quindi nel momento in cui l’istruzione di salto si trova
nella terza fase verrà caricata nella fase IF l’istruzione con il PC aggiornato, questo significa che dal
momento in cui è stata caricata l’istruzione di salto al momento in cui viene caricata l’istruzione a cui si è
saltati, è stata caricata un’istruzione puntata da PC+4 (quindi non l’istruzione a cui si doveva saltare);
questo significa aver perso un colpo di clock, definito DELAY SLOT; il delay slot è quindi il ritardo che si
compie nell’esecuzione di un programma, ritardo sotto forma di stalli e quindi colpi di clock persi. Questo
ritardo deve essere ottimizzato nel modo migliore; le tecniche usate sono le seguenti:
PRIMO CASO
Si osservi questa situazione: vi è un’istruzione di
salto che controlla l’uguaglianza a zero di R2 ed
effettua un salto ad una certa istruzione. Per
ottimizzare il clock perso il compilatore prende
un’istruzione indipendente proveniente dalla
parte di codice precedente il salto e la mette
subito dopo l’istruzione di salto. Quindi viene
schedulata un’istruzione che va comunque
eseguita (DADD R1,R2,R3); il compilatore codifica
con un particolare codice operativo l’istruzione schedulata per far si che anche se la condizione di salto si
dovesse verificare deve essere comunque portata a termine.
SECONDO CASO
Si osservi questa situazione: vi è un’istruzione di
salto che controlla l’uguaglianza a zero di R1 che
è destinazione dell’istruzione precedente.
Questa situazione rende impossibile lo
spostamento dell’istruzione DADD R1,R2,R3 nel
delay slot; quindi questo viene riempito con
l’istruzione destinazione del salto. Si noti che
l’istruzione deve essere copiata e non spostata
per rendere possibile la prima iterazione; se il
salto si verifica, l’istruzione, che adesso si trova immediatamente dopo quella di salto, deve essere portata
a termine. Questa strategia è usata quando il salto ha una probabilità di venire eseguito, come nel salto
all’interno di un ciclo. Se la condizione non si verifica l’istruzione immediatamente dopo il salto deve essere
abortita con conseguente perdita di un colpo di clock.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 39
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
TERZO CASO
Si osservi questa situazione in cui il salto non si
verifica spesso, ad esempio il caso del
confronto; il codice viene riorganizzato
utilizzando istruzioni provenienti dalla sequenza
relativa al caso di non esecuzione del salto.
Perché l’ottimizzazione mostrata sia accettabile
bisogna che si possa eseguire l’istruzione
OR R7,R8,R9 quando il salto si comporta nel
modo non previsto. Per accettabile si intende
che il lavoro fatto divenga sì inutile, ma che il programma sia eseguito correttamente. Questo succede, ad
esempio, se R7 è un registro temporaneo non utilizzato quando il salto si comporta nel modo non previsto.
Se la condizione si verifica l’istruzione immediatamente dopo il salto deve essere abortita.
TECNICA SPECULATIVA – TECNICA DINAMICA Vediamo ora una tecnica speculativa, definita previsione speculativa di salto, che cerca di indovinare
mentre si effettua il fetch di un’istruzione di salto qual è l’istruzione da eseguire immediatamente dopo, al
successivo colpo di clock, senza avere stalli e quindi sprechi di colpi di clock.
Essendo una tecnica speculativa la control unit deve basarsi solamente su informazioni che conosce nella
fase IF, cioè solo il Program Counter. Con questo PC la CU va a leggere la seguente tabella:
essa contiene, in una data riga
(idealmente corrispondente al valore
del PC), il valore dell’indirizzo
destinazione dell’istruzione di salto,
che in precedenza si era andati ad
eseguire, altrimenti se è la prima
volta che si accede alla tabella con un
dato PC, questa verrà aggiornata e
quindi non sarà possibile effettuare la
predizione.
La CU quindi invece di far aggiornare
il PC con il valore PC+4, scriverà in PC
il valore corrispondente alla colonna
Predicted PC, cioè il valore
dell’indirizzo destinazione dell’istruzione di salto, cioè l’indirizzo a cui si era saltati l’ultima volta che si era
trovata l’istruzione di salto. Per fare questo però non è possibile avere una tabella che contenga tante righe
quanti sono i valori possibili del PC; per cui questa tabella è costituita da un numero predefinito di righe che
sono indirizzate dai 7 bit meno significativi del PC. Per evitare errori di accesso a PC errati questa tabella
contiene, nella colonna Look up, i 25 bit più significativi che costituiscono il PC (l’ultimo che ha fatto accesso
alla tabella); in questa maniera è possibile verificare se l’informazione cercata si riferisce al PC che ne fa
richiesta. Se i PC coincidono si dovrebbe prelevare il Predicted PC corrispondente e andarlo a mettere in PC;
però prima ancora di effettuare il prelievo bisogna controllare l’ultima colonna che contiene un bit di
controllo, il quali conferma se l’ultima volta si è effettuato il salto oppure no.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 40
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
PRESTAZIONI: caso di un loop nel quale si ha un certo numero di istruzioni e un’istruzione di salto;
la prima volta che si trova l’istruzione di salto non si ha a disposizione nessuna statistica nella tabella.
Quindi nel momento in cui si verifica la condizione verrà aggiornata la tabella con l’indirizzo destinazione
del salto e verrà modificato il bit di controllo (posto a 1). La prima volta sarà stato eseguito il fetch di
un’istruzione successiva a quella di salto, che poi sarà abortita nel caso il salto si dovesse verificare. Il resto
del loop procede correttamente, poiché ora la tabella è aggiornata e quindi non vi è perdita di nessun colpo
di clock per attendere il calcolo della destinazione del salto; al momento dell’ultima iterazione, quando il
salto non si verifica, la tabella darà ancora in uscita l’indirizzo destinazione del salto e quindi nel PC verrà
caricato automaticamente il Predicted PC; poi però l’istruzione verrà abortita perché non si verificherà la
condizione, per cui vi è una perdita di un colpo di clock. Quindi con questa tecnica si ha, con N iterazioni, un
errore alla prima iterazione, N-1 iterazioni corrette e un altro errore all’ultima iterazione.
Nel caso si ritorni allo stesso loop, accedendo alla tabella si avrà il bit a zero nell’ultima colonna e quindi si
scommetterà che il salto non si dovrà effettuare commettendo così un errore mandando in fetch
un’istruzione che poi dovrà essere abortita; la tabella dovrà essere aggiornata commettendo così sempre
l’errore all’ultima iterazione; quindi in totale in questa situazione si perdono comunque due colpi di clock.
Questa situazione può essere descritta dal seguente diagramma a stati:
STATO 0: salto non verificato
STATO 1: salto verificato
Quando si è nello stato 0 vorrà dire che il salto non dovrà essere effettuato; se effettivamente la condizione
non si verifica si rimane nello stato 0, altrimenti si passa nello stato 1, in cui vale in maniera duale lo stesso
discorso.
È possibile migliorare questa tecnica se si considera anche la storia passata e non solo quello che è successo
l’ultima volta; in questa maniera è possibile costruire una macchina a quattro stati, cioè questo significa
avere nell’ultima colonna della tabella due bit di controllo anziché uno.
La seguente figura mostra la macchina a stati che permette di considerare la storia passata.
STATO 00: certezza assoluta di salto non verificato
STATO 01: predizione di salto non verificato
STATO 10: predizione di salto verificato
STATO 11: certezza assoluta di salto verificato
Quando si è nello stato 11 vorrà dire che il salto dovrà essere effettuato; se effettivamente il salto si verifica
si rimane sempre nello stesso stato, altrimenti si va nello stato 10, in cui si predice comunque la verifica del
salto in base al fatto che le ultime volte il salto si era verificato; quando si è in questo stato se
effettivamente il salto non si verifica bisognerà passare nello stato 00, altrimenti si ritorna nello stato 11.
Quando si è nello stato 00 vorrà dire che il salto non dovrà essere effettuato, e vale in maniera duale lo
stesso discorso.
0 1
NON ESEGUITO
NON ESEGUITO
ESEGUITO
ESEGUITO
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 41
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Quindi utilizzando due bit anziché uno, un salto condizionato che privilegia la sua esecuzione o la sua non-
esecuzione (come accade molto frequentemente) sarà soggetto di una previsione errata solamente una
volta. I due bit saranno utilizzati per codificare i quattro stati del sistema.
Vediamo come a livello del compilatore è possibile migliorare l’esecuzione dei programmi. Esistono due
tecniche di ottimizzazione: srotolamento del loop e pipeline da programma.
SROTOLAMENTO DEL LOOP
Questa tecnica punta a ridurre le istruzioni non indispensabili durante l’esecuzione del loop in modo da
rendere il programma più veloce.
Prima di vedere dettagliatamente come funziona questa tecnica, per comprenderla meglio si consideri il
seguente codice che implementa un loop per sommare gli elementi di due vettori:
Questo programma dovrebbe durare (9 ∙ 𝑁) + 1 colpi di clock; ma poiché ci sono colpi di clock persi a
causa di alcuni stalli provocati da:
istruzione di load che ha come destinazione R5 che è sorgente dell’istruzione successiva;
istruzione di controllo su R6 che non è ancora disponibile;
istruzione BNEZ;
il programma dura (12 ∙ 𝑁) + 1 colpi di clock. Per eliminare i colpi di clock persi è possibile spostare
istruzioni indipendenti nelle zone del codice che comportano degli stalli, ottenendo così il seguente codice
con (9 ∙ 𝑁) + 1 colpi di clock:
DADDI R6,R0,N
LD R4,R1(0)
LD R5,R2(0)
DADD R4,R4,R5
SD R3(0),R4
DADDI R1,R1,#8
DADDI R2,R2,#8
DADDI R3,R3,#8
DADDI R6,R6,#-1
BNEZ R6,-9
stallo
stallo
stallo
DADDI R6,R0,N
LD R4,R1(0)
LD R5,R2(0)
DADDI R1,R1,#8
DADD R4,R4,R5
SD R3(0),R4
DADDI R6,R6,#-1
DADDI R2,R2,#8
BNEZ R6,-8
DADDI R3,R3,#8
DIVENTA
DADDI R6,R0,N
LD R4,R1(0)
LD R5,R2(0)
DADD R4,R4,R5
SD R3(0),R4
DADDI R1,R1,#8
DADDI R2,R2,#8
DADDI R3,R3,#8
DADDI R6,R6,#-1
BNEZ R6,-9
stallo
stallo
stallo
Istruzioni necessarie
Istruzioni di gestione
R1 punta al vettore A
R2 punta al vettore B ⇒ C[i] = A[i] + B[i]
R3 punta al vettore C
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 42
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Si noti, comunque, che oltre alle quattro istruzioni necessarie se ne trovano sempre cinque per gestire il
loop; allora bisogna cercare di semplificare il loop eliminando quelle istruzioni “non indispensabili”.
È possibile pensare di codificare l’indirizzi degli elementi di A, B e C in maniera tale che siano espressi in una
forma caratterizzata da un certo immediato e un certo registro (che farà da spiazzamento). Si noti che le
due load e la store sono legate tra di loro dal fatto che tutte e tre le operazioni punteranno sempre ad un
identico elemento del vettore (ad esempio: salvo nel quarto di C la somma fra il quarto di A con il quarto di
B); quindi è possibile pensare di avere un unico registro che permetterà di indirizzare il generico i-esimo
elemento di un vettore. Quindi l’indirizzo delle load e della store è espresso in questi termini: l’immediato
sarà l’indirizzo del primo elemento del rispettivo vettore, mentre il registro farà da indice per gli elementi.
Gestendo gli indirizzi in questo modo, da tre comandi per gestire l’accesso ai tre dati se ne avrà soltanto
uno, bisognerà lavorare solo su di un registro.
Per cui supponendo per esempio che il primo valore di A è all’indirizzo 1000, il primo di B è all’indirizzo
2000 e il primo di C è all’indirizzo 3000 è possibile avere il seguente codice:
DADDI R1,R0,N
DADDI R1,R1,#-1
DMULI R1,R1,#8
LD R2,R1(1000)
LD R3,R1(2000)
DADDI R1,R1,#-8
DADD R2,R2,R3
BNEZ R1,-6
SD (3008)R1,R2 //3008 perché R1 è stato decrementato
In questa maniera ho per fare quattro istruzioni di calcolo, necessarie, due di gestione; per cui un overhead
del 50%. A questo punto per diminuire questo overhead si può utilizzare la tecnica dello srotolamento del
loop.
Questa tecnica attua due stratagemmi per raggiungere il suo obiettivo:
1. Ridurre le istruzione di gestione del loop;
2. Mettere a disposizione un numero maggiore d’istruzioni effettive di calcolo per avere più
opportunità di trovare le istruzioni da inserire al posto degli stalli.
Srotolare il loop significa prendere il codice e “ricopiarlo” per ottenere un’altra iterazione; in realtà non si
ricopia interamente il loop ma solamente le istruzioni necessarie, quelle di calcolo e utilizzando altri registri
per effettuare le operazioni di load e di add. Quindi il loop dell’esempio precedente srotolato e ottimizzato
è il seguente:
LD R2,R1(1000)
LD R3,R1(2000)
LD R5,R1(992) //utilizzo un altro registro
LD R6,R1(1992) //utilizzo un altro registro
DADD R2,R2,R3
DADD R5,R5,R6
SD (3000)R1,R2
SD (2992)R1,R5
DADDI R1,R1,#-16
BNEZ R1,-10
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 43
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Srotolato il loop ci si ritrova parecchio codice, che può essere riorganizzato in maniera tale da gestire gli
eventuali stalli che si vengono a creare.
Come si può notare questa tecnica ha lo svantaggio di incrementare l’uso dei registri e del codice.
È intuibile considerare un numero di registri che sia un sottomultiplo della dimensione del vettore, in modo
tale da srotolare il loop senza lasciare residui del vettore. Se non si fa questa considerazione, è facile notare
che alla fine del loop si processeranno indirizzi di memoria che non sono parte del vettore.
PIPELINE DA PROGRAMMA
Consideriamo sempre l’esempio precedente, la somma tra vettori, però con dati floating point;
si consideri per vera questa sintassi:
L.D A(i)
L.D B(i)
ADD.D C(i),A(i),B(i)
S.D C(i)
La pipeline da programma parte dalla seguente osservazione: poiché non è possibile effettuare subito
ADD.D (non si ha ancora a disposizione i dati sorgenti), e poi S.D, allora si effettua la somma dei dati di cui si
è fatta la load all’iterazione precedente; quindi saranno passati diversi colpi di clock, tanti quanti ne sono
necessari per avere a disposizioni i valori nei registri. Stesso discorso per la store, andando a salvare il
risultato dell’iterazione ancora precedente a quella che ADD sta gestendo. In questa maniera evito lo
spreco dei colpi di clock.
Chiarita l’idea di funzionamento, vediamo ora come la si implementa modificando il codice in questa
maniera:
L.D A(i+2)
L.D B(i+2)
ADD.D C(i+1),A(i+1),B(i+1)
S.D C(i)
Il codice è modificato in maniera tale che quando si sta facendo la store dell’iterazione i-esima si sta
memorizzando in memoria il risultato che ADD.D aveva calcolato all’iterazione precedente, quindi
all’iterazione i-1 ADD.D calcola A(i)+B(i) e all’iterazione i-esima C(i) viene scritto in memoria.
Per chiarire meglio vediamo un esempio:
iterazione i = 9;
L.D A(9+2=11);
L.D B(9+2=11);
iterazione i = 10;
ADD.D C(10+1=11),A(10+1=11),B(10+1=11); con A e B dati che sono stati caricati
nell’iterazione precedente i = 9;
iterazione i = 11;
S.D C(11); calcolato nell’iterazione precedente i = 10;
Quindi un loop dovrà essere fatto per N-2 iterazioni (0÷N-3).
Vediamo ora cosa succede alla prima e all’ultima iterazione del loop:
PRIMA ITERAZIONE: al momento della store si scriverà in memoria qualcosa che non sarà stato ancora
calcolato;
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 44
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ULTIMA ITERAZIONE: al momento delle load si caricheranno dati che non verranno mai processati.
Allora è necessario strutturare questa pipeline con un transitorio di riempimento e un transitorio di
svuotamento; cioè il programma è visto come un tubo in cui entrano le istruzioni di iterazioni differenti, in
cui vi è un transitorio di caricamento nel quale si ha:
L.D A(0)
L.D B(0)
L.D A(1)
L.D B(1)
ADD.D C(0),A(0),B(0)
Dopo questo transitorio parte il loop effettivo dove i vale zero e quindi:
L.D A(2)
L.D B(2)
ADD.D C(1),A(1),B(1)
S.D C(0)
Quando si arriva a N-3 sarà stata fatta l’ultima store C(N-3), sarà stata calcolata C(N-2) e saranno fatte le
ultime load A(N-1) e B(N-1);
per cui dopo il loop si dovrà fare un transitorio di svuotamento nel quale si ha:
ADD.D C(N-1),A(N-1),B(N-1)
S.D C(N-2)
S.D C(N-1)
Dove questo transitorio di svuotamento completa il transitorio di caricamento. In tutto vengono fatte le
operazioni legate a due cicli, quelli che da 0 a N-3 cicli del loop + due dei transitori portano effettivamente
ad aver lavorato da 0 a N-1, cioè per N elementi del vettore.
Con la pipeline da programma si risolve il problema degli stalli tra un’istruzione ed un'altra. Il vantaggio di
questa tecnica è che continua a tenere impegnati quei registri che si avevano nel caso di loop normale,
mentre lo svantaggio rispetto alla srotolamento è che non diminuiscono le istruzioni di controllo.
Il compilatore utilizzerà la tecnica dello srotolamento quando il codice contiene un numero d’istruzioni di
controllo che è proporzionalmente rilevante, altrimenti utilizzerà la tecnica del pipeline da programma; per
cui la scelta della tecnica risulta forzata e dipendente dal numero di istruzioni che costituiscono il codice, o
meglio dal numero di istruzioni di calcolo e di controllo che costituiscono il programma.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 45
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZI DI RIEPILOGO
ESERCIZIO 1 Scrivere le microfasi della seguente istruzione:
S.D 1200(R3), F4
per un MIPS ad architettura pipeline con bus a 32 bit;
In pratica questo esercizio richiede come può essere effettuato il trasferimento di 64 bit (store di un
double), con il minor numero di stalli, in cui vi è il vincolo della memoria con un bus a 32 bit.
È chiaro che se si vuole scrivere in memoria 64 bit, mentre ne posso scrivere soltanto 32 bit alla volta,
bisognerà pensare un’istruzione che avrà al suo interno due fasi MEM.
L’istruzione S.D 1200(R3),F4 equivale all’istruzione: F4##F5 →64 M[1200+R3] Cioè:
F4 → M[1200+R3]
F5 → M[1204+R3]
Le fasi IF e ID sono le seguenti:
FASE IF
IF/ID.IR ← Mem[PC]
IF/ID.NPC ← PC + 4
FASE ID ID/EX.A ← Regs[IF/ID.IR[rs]]
ID/EX.B ← Regs[IF/ID.IR[rt]]
ID/EX.IR ← IF/ID.IR
ID/EX.NPC ← IF/ID.NPC
ID/EX.Imm ← sign-extend(IF/ID.IR[immediate field])
µPC ← MM[IF/ID.IR[opcode]]
L’ultima istruzione permette di effettuare la decodifica dell’istruzione; vengono letti i bit del codice
operativo come un indirizzo per accedere alla MAPPING MEMORY (MM), nella quale per quel particolare
codice operativo si troverà un nuovo indirizzo di una micro memoria che è alla base dell’esecuzione della
logica supervisionata dalla control unit.
Fin qui non ci sono problemi, poiché queste due fasi sono sempre condotte alla stessa maniera per tutte le
istruzioni; al termine del decode si conosce l’istruzione e quindi si intraprendono le operazioni specifiche da
eseguire.
Vediamo due soluzioni: la prima effettua due fasi EX e due fasi MEM per eseguire l’istruzione, quindi la si
può ipotizzare come due istruzioni di store distinte, mentre la seconda soluzione cerca di avere una fase EX
e due fasi MEM, di cui una incorpora una fase EX per il calcolo dell’indirizzo successivo.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 46
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
PRIMA SOLUZIONE
FASE EXE1
EX/MEM.ALUOUTPUT ← ID/EX.A + ID/EX.Imm
EX/MEM.B ← ID/EX.B
FASE MEM1
Mem[EX/MEM.ALUOUTPUT] ← EX/MEM.B
FASE EXE2
EX/MEM.ALUOUTPUT ← EX/MEM.ALUOUTPUT + 4
EX/MEM.B ← ID/EX.IR[rt+1] //con rt + 1 accedo a F5 (a livello concettuale)
FASE MEM2
Mem[EX/MEM.ALUOUTPUT] ← EX/MEM.B
Si noti che questo microprogramma, prevedendo 6 fasi, non presenta alcun vantaggio, in termini di
prestazioni, rispetto all'esecuzione di 2 distinte istruzioni di store.
Senza dire che la fase EXE2 e MEM2 potrebbero causare stalli alle istruzioni successive che nella pipeline
competerebbero con questa per l'uso dell’ALU e della Memoria.
SECONDA SOLUZIONE
Volendo migliorare le prestazioni, si può prevedere una duplicazione del EX/MEM.ALUOUTPUT (un secondo
registro EX/MEM.ALUOUTPUT2 per referenziare la seconda metà della doppia parola) ed una sua
strutturazione auto incrementante per svincolare l'ALU.
Quindi si può pensare che la fase EXE2 può avvenire contemporaneamente alla fase MEM1; questo è
possibile perché in un primo istante si legge EX/MEM.ALUOUTPUT e poi in un secondo istante, dopo che
l’accesso a memoria è stato eseguito, lo si aggiorna. Lo stesso per EX/MEM.B, il quale viene in un primo
momento trasferito in memoria e poi riceve ID/EX.IR[rt+1]
In tal caso si avrebbe:
FASE EXE1
EX/MEM.ALUOUTPUT ← ID/EX.A + ID/EX.Imm
EX/MEM.B ← ID/EX.B
FASE MEM1 (comprende anche la fase EXE2)
Mem[EX/MEM.ALUOUTPUT] ← EX/MEM.B
EX/MEM.ALUOUTPUT2 ← EX/MEM.ALUOUTPUT + 4
EX/MEM.B ← ID/EX.IR[rt+1]
FASE MEM2
Mem[EX/MEM.ALUOUTPUT2] ← EX/MEM.B
1* SEMICICLO
2* SEMICICLO
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 47
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Con questa scrittura, questa istruzione prevedrebbe 5 fasi, sebbene la presenza di MEM2 causerebbe uno
stallo alle istruzioni successive, qualora l'istruzione I immediatamente seguente ad essa faccia
effettivamente riferimento a memoria durante la sua fase MEM:
(SD): IF ID EX MEM1 MEM2
(I): IF ID EXE Stallo MEM WB
Quindi se l’istruzione I è una istruzione di load o di store ci sarà uno stallo al momento della sua fase MEM.
Si noti però che nel primo semiciclo della fase MEM1 oltre ad accedere alla memoria, si sta utilizzando
l’ALU per calcolare il nuovo indirizzo; per cui l’istruzione I avrebbe anche la sua fase EXE in stallo. Per cui lo
stallo andrebbe messo prima della fase EXE, quindi non si avrà poi lo stallo per la fase MEM, cioè la
situazione diventerebbe la seguente:
(SD): IF ID EX MEM1 MEM2
(I): IF ID Stallo EXE MEM WB
Nel secondo caso lo stallo si avrebbe sempre e comunque, perché tutte le istruzioni fanno uso dell’ALU;
mentre nel primo caso, con un opportuna modifica, lo stallo si avrebbe solo se l’istruzione I effettivamente
fa riferimento alla memoria.
Per risolvere il conflitto fra MEM1 e la fase EXE dell’istruzione I bisogna pensare di modificare parte
dell’hardware del processore; poiché MEM1, oltre all’accesso alla memoria, non fa altro che una somma
per il calcolo dell’indirizzo successivo, allora è possibile aggiungere un sommatore nella fase MEM, il quale
ha il compito di determinare il nuovo indirizzo in modo tale che non venga occupata e utilizzata l’ALU. Il
processore eseguirà così in parallelo la fase MEM1 e la fase EXE2; la modifica da apportare e quindi la
seguente:
EX/MEM.ALUOUTPUT va in ingresso
alla Data memory e ad un sommatore
predisposto per calcolare il secondo
indirizzo; quest’ultimo dovrà essere
scritto in EX/MEM.ALUOUTPUT2 e
non in EX/MEM.ALUOUTPUT perché
è usato dall’istruzione che in quel
momento è nella fase EX e che quindi
sta usando l’ALU e il suo risultato
andrà in EX/MEM.ALUOUTPUT.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 48
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Con questa tecnica viene evitato il conflitto fra MEM1 e la EXE dell’istruzione I nel caso questa non è una
load o una store; altrimenti si avrà solo uno stallo. Con queste migliorie bisognerà leggermente modificare
la C.U. e l’hardware per gestire il sommatore e il nuovo registro; è una soluzione utile nel caso il processore
esegue spesso istruzioni di store.
ESERCIZIO 2 Relativamente ad una architettura RISC con 5 stadi di pipeline si progetti la circuiteria aggiuntiva da
provvedere alla CPU per gestire in una singola istruzione operazioni di accesso ad uno stack di memoria,
definendo le micro operazioni da compiere nei 5 stadi della pipeline relativamente all’istruzione:
POP Rb (Rb registro ricevente il dato prelevato dallo stack).
Si preveda il controllo di stack overflow e stack underflow.
Bisogna fare delle ipotesi:
bisogna considerare se lo stack lavoro con indirizzi crescenti o decrescenti;
l’indirizzo, che punta all’area di memoria in cui si vuole scrivere o leggere i dati, considerarlo
puntatore al primo vuoto oppure all’ultimo pieno.
Innanzitutto bisogna gestire l’ultima richiesta, cioè bisogna controllare le situazioni di overflow e underflow
dello stack.
Si consideri il seguente modello di stack in cui si hanno tre registri, uno contente l’indirizzo di TOP (TS) dello
stack, uno contenente l’indirizzo di BOTTOM (BS) dello stack e uno contente l’indirizzo dello STACK
POINTER (SP).
Si prevedano inoltre due comparatori che in uscita hanno rispettivamente le seguenti condizioni:
Ipotizzando che SP punti alla prima cella vuota dello stack il quale si riempie per indirizzi crescenti si ha:
COND1 che è 1 nel caso in cui SP sia maggiore di
TS ad indicare l’overflow;
COND2 che è 1 nel caso in cui SP sia uguale a BS
ad indicare l’underflow
In queste ipotesi il microcodice di’un operazione POP potrebbe essere il seguente: (l’operazione POP non è una semplice una operazione di load, ma bisogna anche modificare il valore di SP)
FASE IF IF/ID.IR ← Mem[PC];
IF/ID.NPC ← PC + 4;
FASE ID ID/EX.A ← IF/ID.IR[rs];
ID/EX.B ← IF/ID.IR[rt];
ID/EX.IR ← IF/ID.IR;
ID/EX.NPC ← IF/ID.NPC;
µPc ← MM[IF/ID.IR[opcode]];
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 49
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
FASE EXE (if (COND2) µPc ← MM[gestione interrupt stack underflow]);
EX/MEM.SP ← ID/EX.SP - 4;
FASE MEM MEM/WB.LMD ← Mem[EX/MEM.SP];
FASE WB Regs[MEM/WB.IR[Rb] ← MEM/WB.LMD; // con Rb registro ricevente il dato prelevato dallo stack
In una pipeline vista a 5 stadi sembra quindi che il miglior modo di operare con uno stack e quello con SP
puntatore al primo vuoto.
Questo esercizio richiedeva di analizzare il caso di un’istruzione POP; vediamo ora come si complicano le
cose nel caso d’istruzione PUSH.
Se SP è sempre puntatore al primo vuoto l’operazione da effettuare per prima è quella di scrittura nello
Stack e poi di aggiornamento con incremento di SP; questo significa utilizzare l’ALU dopo la fase MEM e di
conseguenza un peggioramento di prestazioni. Allora può sembrare non conveniente avere SP puntatore al
primo vuoto, ma meglio averlo puntatore all’ultimo pieno, in maniera tale da incrementare SP e poi
accedere alla memoria per scrivere.
Per cui bisogna decidere una tecnica che vada bene per un caso e trovare una soluzione per evitare stalli
nell’altro caso; questo è possibile inserendo, come nell’esercizio precedente, un sommatore nella fase
MEM che effettui l’aggiornamento di SP.
Bisogna però prestare attenzione, poiché stiamo considerando comunque un’architettura pipeline, ai casi
in cui si presentano più istruzioni PUSH o POP contemporaneamente, ad esempio:
1°CASO: istruzione POP seguita da un’istruzione POP
prima istr: POP IF ID EX MEM WB
seconda istr: POP IF ID EX MEM WB
Questa situazione non presenta alcun tipo di problema poiché nel momento in cui la seconda istruzione
effettua la sua fase EX il valore SP sarà già stato aggiornato per cui tutto procede senza problemi.
2°CASO: istruzione PUSH seguita da un’istruzione PUSH
prima istr: PUSH IF ID EX MEM WB
seconda istr: PUSH IF ID EX MEM WB
Questa situazione non presenta alcun tipo di problema poiché nel momento in cui la seconda istruzione
effettua la sua fase EX il valore SP sarà già stato aggiornato dal sommatore, presente nella fase MEM della
prima istruzione, per cui tutto procede senza problemi.
3°CASO: istruzione POP seguita da un’istruzione PUSH
prima istr: POP IF ID EX MEM WB
seconda istr: PUSH IF ID EX MEM WB
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 50
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Questa situazione non presenta alcun tipo di problema poiché nel momento in cui la seconda istruzione
effettua la sua fase EX il valore SP sarà già stato aggiornato per cui tutto procede senza problemi.
4°CASO: istruzione PUSH seguita da un’istruzione POP
prima istr: PUSH IF ID EX MEM WB
seconda istr: POP IF ID stallo EX MEM WB
Questa situazione presenta un stallo della fase EX dell’istruzione POP; questo problema è dovuto al fatto
che soltanto al termine della fase MEM dell’istruzione PUSH il sommatore aggiornerà SP, per cui non potrà
essere eseguita contemporaneamente la fase EX dell’istruzione POP poiché SP non è ancora aggiornato.
Per evitare questo stallo è possibile pensare di eseguire l’aggiornamento di SP direttamente nella fase EX
dell’istruzione PUSH; vediamo in dettaglio cosa si dovrebbe fare:
Nella fase EX passiamo SP al latch EX/MEM e tramite l’ALU (quindi non serve più il sommatore)
l’aggiorniamo e lo passiamo al latch ID/EX; per cui in microcodice si ha:
FASE EXE
EX/MEM.SP ← ID/EX.SP
ID/EX.SP ← ID/EX.SP + 4
In questo modo al termine della fase EXE il valore di SP risulterà aggiornato, per cui l’istruzione POP
successiva non dovrà più stallare poiché ora il dato sarà disponibile.
prima istr: PUSH IF ID EX MEM WB
seconda istr: POP IF ID EX MEM WB
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 51
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 3 Considerando di voler aggiungere al set di istruzioni del MIPS le istruzioni ADDL e SUBL (la “L” sta per long,
inteso come “doppia word intera”) scrivere in RTL i microprogrammi utili ad interpretarle, indicando le più
opportune modifiche architetturali.
(bisogna supporre che l’ALU del MIPS possa operare con soli dati da 32 bit e che quindi anche i registri sono
a 32 bit).
Nel caso non sia possibile compattare l’istruzione in 5 fasi di pipeline, giustificarne il perché.
Verosimilmente l’operazione da effettuare sarà ad esempio:
ADD R10,R4,R6
ADD R11,R5,R7
Quindi dividiamo l’operazione in due; ma bisogna prestare attenzione al bit di carry prodotto dalla prima istruzione; per cui la seconda istruzione dovrà considerare l’eventuale bit di carry che si sarà propagato e conservato nella PSW (Process Status Word), un registro ausiliario del processore che contiene una serie di flag che tengono traccia di quello che è appena successo nell’ALU.
Poiché l’istruzione ADDL sommerà operandi in doppia lunghezza è utile fare delle considerazioni sui registri: rs e rt rappresentano i registri che contengono i 32 bit meno significativi; rs' e rt' rappresentano i registri che contengono i 32 bit più significativi; con l’accortezza che rs' e rt' non siano scritti da nessuna parte, cioè l’istruzione conterrà, considerando l’esempio, solo il codice 4 e 6, il sistema poi saprà che si sta facendo riferimento a dei dati in doppia parola e che la seconda parte della parola è nei registri adiacenti. Lo stesso vale per il registro destinazione: rd (rd') rappresenta il registro destinazione che conterrà i 32 bit meno significativi (più significativi) del risultato.
Le fasi IF e ID sono le seguenti:
FASE IF
IF/ID.IR ← Mem[PC]
IF/ID.NPC ← PC + 4
FASE ID ID/EX.A ← Regs[IF/ID.IR[rs]]
ID/EX.B ← Regs[IF/ID.IR[rt]]
ID/EX.IR ← IF/ID.IR
ID/EX.NPC ← IF/ID.NPC
ID/EX.Imm ← sign-extend(IF/ID.IR[immediate field])
µPC ← MM[IF/ID.IR[opcode]]
FASE EXE1 (occorre memorizzare il carry nel bit c della PSW) EX/MEM.IR ← ID/EX.IR EX/MEM.ALUOUTPUT ← ID/EX.A + ID/EX.B
ID/EX.A ← Regs[IF/ID.IR[rs']]
ID/EX.B ← Regs[IF/ID.IR[rt']]
PSW[c] ← 𝑐𝑎𝑟𝑟𝑦
Sfruttando una suddivisione in semicicli, ID/EX.A e ID/EX.B sono letti nel primo semiciclo e scritti nel secondo.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 52
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
FASE EXE2 (comprende la fase MEM1) MEM/WB.IR ← EX/MEM.IR
MEM/WB.ALUOUTPUT ← EX/MEM.ALUOUTPUT
EX/MEM.ALUOUTPUT ← ID/EX.A + ID/EX.B + PSW[c]
Sfruttando una suddivisione in semicicli, EX/MEM.ALUOUTPUT è letta nel primo semiciclo, scritta nel secondo.
FASE WB1 (comprende la fase MEM2)
Regs[MEM/WB.IR[rd]] ← MEM/WB.ALUOUTPUT
MEM/WB.ALUOUTPUT ← EX/MEM.ALUOUTPUT
Sfruttando una suddivisione in semicicli, MEM/WB.ALUOUTPUT è letta nel primo semiciclo, scritta nel secondo.
FASE WB2
Regs[MEM/WB.IR[rd']] ← MEM/WB.ALUOUTPUT
µPC ← 0
Pensata così l’istruzione termina in sei fasi; analizziamo ora i conflitti che potrebbe generare:
prima istr: ADDL IF ID EX1 EX2 WB1 WB2
seconda istr: qualsiasi IF ID EX MEM WB
per la seconda istruzione vi è uno stallo nel momento in cui vi è la fase EX (avviene in contemporanea con la
EX2) e nel momento della fase ID poiché provoca incoerenza in quanto EX1 sta scrivendo nei registri A e B e
a lo stesso sta facendo ID. Per cui inserendo lo stallo prima della fase ID si ottiene:
prima istr: ADDL IF ID EX1 EX2 WB1(MEM1) WB2(MEM2)
seconda istr: qualsiasi IF stallo ID EX MEM WB
È possibile migliorare la situazione considerando che se le operazioni in doppia precisione fossero molto
frequenti, potremmo pensare di utilizzare dei latch A, B, ALUOUTPUT capaci di contenere 64 bit, invece di
32, evitando la seconda fase di prelievo degli operandi (nella fase EX1) che obbligano di fatto ad uno stallo
l'istruzione successiva, in quanto ne impediscono l'ID.
Comunque l’ALU continuerebbe a processare gli operandi in due tempi ciascuno da 32 bit: avremmo
comunque la necessità di avere due fasi di EXE (e conseguente stallo delle istruzioni successive in conflitto
strutturale sull'ALU, risolvibile inserendo un sommatore nella fase EX2 in modo tale da non usare l’ALU). In
questo modo bisognerà potenziare la C.U. e aggiungere hardware; non si ottiene quindi nessun
miglioramento per cui conviene avere un’ALU a 64 bit.
In maniera analoga a quanto appena visto vale per l’ipotetica istruzione SUBL, considerando il bit di borrow
(riporto) della PSW invece del bit di carry.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 53
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 4 Scrivere in RTL i microprogrammi utili ad interpretare l’istruzione:
LW R1,(#1000,R2)
per una architettura MIPS con bus dati a 32 bit, considerando eventuali conflitti che si verrebbero a creare
con le istruzioni ad essa successive nell'implementazione pipeline.
Per LW R1, (#1000, R2) si intende:
R1 ← Mem[Mem[1000 + R2]]
Cioè verosimilmente si dovrebbero effettuare, per esempio, queste due istruzioni:
LW R6,1000(r2)
LW R1,0(R6)
Le fasi per svolgere queste due istruzioni dovrebbero essere le seguenti:
prima istr: LW R6,1000(R2) IF ID EX MEM WB
seconda istr: LW R1,0(R6) IF ID EX MEM WB
Ci sarà bisogno di uno stallo poiché la seconda LW deve calcolare R6 + 0 per avere l’indirizzo, e quindi la EX
della seconda istruzione deve stallare; ma poiché essendo zero il secondo addendo della somma, allora con
una corto-circuitazione della memoria, in cui l’uscita della memoria va alla porta indirizzo della memoria
stessa, si evita lo stallo. Questa operazione vale solamente in questo caso, poiché la seconda load deve
effettuare una somma con zero. Quindi bisognerà modificare la C.U.
Per cui con questi accorgimenti non si hanno stalli e l’istruzione successiva terminerebbe al colpo di clock 6.
Quindi per ottimizzare il microcodice di questa istruzione, che prevede un doppio accesso a memoria,
supponiamo nella architettura MIPS, un collegamento dall'uscita dati della memoria al registro
EX/MEM.ALUOUTPUT. In tal caso, il microcodice, potrebbe essere:
FASE IF
IF/ID.IR ← Mem[PC]
IF/ID.NPC ← PC + 4
FASE ID ID/EX.A ← Regs[IF/ID.IR[rs]]
ID/EX.B ← Regs[IF/ID.IR[rt]]
ID/EX.IR ← IF/ID.IR
ID/EX.NPC ← IF/ID.NPC
ID/EX.Imm ← sign-extend(IF/ID.IR[immediate field])
µPC ← MM[IF/ID.IR[opcode]]
FASE EX EX/MEM.ALUOUTPUT ← ID/EX.A + ID/EX.Imm
EX/MEM.IR ← ID/EX.IR
FASE MEM1 EX/MEM.ALUOUTPUT ← Mem[EX/MEM.ALUOUTPUT]
MEM/WB.IR ← EX/MEM.IR
FASE MEM2
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 54
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
MEM/WB.LMD ← Mem[EX/MEM.ALUOUTPUT]
FASE WB Regs[MEM/WB.IR[rd]] ← MEM/WB.LMD
Pensata così l’istruzione termina in sei fasi; analizziamo ora i conflitti che potrebbe generare:
prima istr: LW IF ID EX MEM1 MEM2 WB
seconda istr: qualsiasi IF ID EX MEM WB
La fase di MEM2 della prima istruzione provoca un problema con la fase MEM della seconda istruzione solo
se quest’ultima è un’istruzione di load o di store, altrimenti la fase MEM è una sola fase di passaggio. Per
cui si potrebbe far precedere l’istruzione LW solo da istruzioni che non effettuano load o store.
Il vero problema sorge nel momento in cui la seconda istruzione entra in fase di WB; questo problema è
semplicemente risolvibile potenziando il canale che porta i dati nei registri.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 55
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 5 Progettare un microprogramma in linguaggio RTL da associare ad una istruzione:
RTI (return from interrupt)
per una macchina MIPS nei due casi:
- salvataggio del PC in un registro IAR (Interrupt address return)
- salvataggio del PC in uno stack, facendo ipotesi su come è gestito lo stack.
Per semplicità si trascuri il ripristino dei registri e della parola di stato.
L’istruzione RTI permette di ritornare alla normale esecuzione di un programma dopo che è stata servita
l’interruzione. Il microprogramma ad essa associato può essere:
FASE IF
IF/ID.IR ← Mem[PC]
IF/ID.NPC ← PC + 4
FASE ID ID/EX.A ← Regs[IF/ID.IR[rs]]
ID/EX.B ← Regs[IF/ID.IR[rt]]
ID/EX.IR ← IF/ID.IR
ID/EX.NPC ← IF/ID.NPC
ID/EX.Imm ← sign-extend(IF/ID.IR[immediate field])
µPC ← MM[IF/ID.IR[opcode]]
Consideriamo prima il caso in cui il PC sia stato salvato nell’IAR, quindi nei casi di interrupt mascherati, cioè
nei casi in cui l’interrupt non viene interrotto, in maniera tale da non perdere il PC.
FASE EXE
EX/MEM.ALUOUTPUT ← IAR
FASE MEM
MEM/WB.ALUOUTPUT ← EX/MEM.ALUOUTPUT
FASE WB
PC ← MEM/WB.ALUOUTPUT
µPC ← 0
L’IAR viene caricato nel PC per ripristinare il valore del PC quando c’è stata l’interruzione e viene resettato il
µPC a 0 per fare il fetch della successiva istruzione.
Anche se l’istruzione porta via cinque fasi provocherebbe comunque degli stalli per le prossime istruzioni,
perché il fetch non potrà essere effettuato in quanto il PC sarà disponibile solo dopo la fase di WB. Per cui
se si gestisce così l’istruzione si avrebbe una situazione del genere:
prima istr: RTI IF ID EX MEM WB
seconda istr: (istr. con PC corretto) IF stallo stallo stallo IF ID EX MEM WB
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 56
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Per cui è necessario effettuare il WB il prima possibile; questo si può ottenere cortocircuitando
direttamente IAR con il PC consentendo di ridurre ad uno solo gli stalli (nella fase di EXE si avrebbe
direttamente PC ← IAR). Per cui si ottiene:
prima istr: RTI IF ID EX MEM WB
seconda istr: (istr. con PC corretto) IF stallo IF ID EX MEM WB
Un ulteriore miglioramento potrebbe essere ottenuto a livello di scheduling, inserendo dopo l'istruzione RTI
le ultime due istruzioni di procedura di gestione dell’interrupt, in maniera tale da non sprecare colpi di
clock; si ottiene così questa situazione:
prima istr: RTI IF ID EX MEM WB
seconda istr: istr N-2 IF ID EX MEM WB
terza istr: istr N-1 IF ID EX MEM WB
quarta istr: (istr. con PC corretto) IF ID EX MEM WB
dove:
N-2 è la terz’ultima istruzione di gestione dell’interrupt;
N-1 è la penultima istruzione di gestione dell’interrupt
Vediamo ora il caso in cui il PC venga salvato nello STACK, quindi nei casi di interrupt non mascherabili, cioè
nei casi in cui l’interrupt può essere interrotto, e il valore del PC non viene perso poiché viene salvato nello
stack; al momento del termine delle procedure di gestione degli interrupt, si procede con il prelievo dallo
stack dei rispettivi PC.
Si suppone che lo STACK risieda in memoria per indirizzi crescenti e che lo Stack Pointer punti all’ultima
locazione piena.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 57
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
FASE EXE
EX/MEM.ALUOUTPUT ← SP
SP ← SP - 4
FASE MEM
MEM/WB.LMD ← Mem[EX/MEM.ALUOUTPUT]
FASE WB
PC ← MEM/WB.LMD
µPC ← 0
Nella fase di EXE avviene il caricamento nel EX/MEM.ALUOUTPUT dello SP e il contemporaneo decremento
dello SP per puntare all’elemento successivo.
Come nel primo caso si ottengono degli stalli che portano l’istruzione con il PC corretto a cominciare al
sesto colpo di clock.
Con uno opportuno scheduling dell’istruzioni, simile al precedente caso, è possibile anche in questo caso
evitare i colpi di clock persi.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 58
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 6
Disegnare la CPU di una architettura ad accumulatore e commentarne le caratteristiche. Inoltre,
progettarne il ciclo di esecuzione delle istruzioni, descrivendo in RTL il funzionamento del programma:
LD 1200
ADD 1204
ST 1200
specificando anche qual è il suo scopo.
L’architettura ad accumulatore si differenzia perché non ha tutti i registri, ma soltanto un registro,
chiamato registro accumulatore (ACC); questo registro contiene l’operando sorgente e riceve l’operando
risultato. Il funzionamento dell’architettura è il seguente;
1. Al registro ACC vengono passati:
a) Codice operativo;
b) Un operando, che è un indirizzo di memoria;
2. Il contenuto del registro ACC diventa il primo operando;
3. Viene letta la memoria è il valore viene usato come secondo operando;
4. Calcolo del risultato;
5. Scrittura nel registro ACC.
Il programma da descrivere richiede: 1. Caricare il contenuto che si trova in memoria all’indirizzo 1200 nel registro ACC;
ACC ← M[1200]
2. Sommare il contenuto di ACC con il valore contenuto in memoria all’indirizzo 1204 (il risultato andrà in ACC);
ACC ← ACC + M[1204]
3. Salvare il risultato, ovvero il contenuto di ACC, all’indirizzo di memoria 1200.
M[1200] ← ACC Come è facile notare questa architettura non permette una gestione in pipeline dell’istruzioni.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 59
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Un esempio di processore ad Accumulatore può essere il seguente:
In cui:
1. L'Accumulatore sostituisce il banco di registri General Purpose.
2. Esso è vincolato ad uno dei due ingressi dell'ALU (l'ingresso In1; questo consente all'architettura di avere
un solo bus sorgente in ingresso all'ALU) e funge inoltre da EX/MEM.A
3. L'Accumulatore è anche una destinazione privilegiata per l'uscita dell'ALU (il demux, dal punto di vista
funzionale non ha alcuna utilità potendo direttamente connettere sul bus D l'uscita dell'ALU in scrittura e
l'ACC in lettura come tutti gli altri registri, ma la sua presenza evidenzia didatticamente il fatto che
l'Accumulatore è il ricettore privilegiato dei dati in uscita dall'ALU).
4. Il registro speciale SAR (Subroutine Address Return) serve per una gestione semplificata delle procedure
e memorizza l'indirizzo di rientro (non sono consentiti annidamenti di procedure).
5. Il registro speciale IAR (Interrupt Address Return) serve per una gestione semplificata degli interrupt e
memorizza l'indirizzo di rientro (sono consentiti solo interrupt esterni e a loro volta non interrompibili).
Queste caratteristiche determinano anche una semplificazione importante sul formato istruzione della
macchina che richiede solo la specifica di un indirizzo di memoria come operando sorgente, essendo l'altro
operando sorgente ed il destinazione costituiti di default dall'accumulatore.
Si può quindi supporre un formato istruzione:
4 bit for opcode 28 bit for immediate field
(assumendo che solo 4 bit di CO siano sufficienti per codificare le operazioni ammesse).
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 60
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Per il ciclo di esecuzione delle istruzioni di questa macchina si possono supporre le seguenti fasi:
Instruction Fetch, in cui si preleva l'istruzione e si incrementa il PC:
IR ← Mem[PC]
PC ← PC+4
L’ultima istruzione sarebbe l’insieme di queste tre operazioni:
S ← PC
D ← In0+4
PC ← D
Addressing e Instruction Decode in cui viene preparato l'indirizzamento alla memoria e decodificata
l'istruzione:
MAR ← IR AND #0FFFFFFF
µPC ← MM[IR[opcode]]
La prima istruzione sarebbe l’insieme di queste tre operazioni, in cui viene effettuato il mascheramento del
codice operativo:
S ← IR
D ← In0 AND #0FFFFFFF
MAR ← D
Poi a seconda del tipo di operazione si ha:
LOAD ALU STORE BCOND
FASE MEM:
LMDR ← Mem[MAR]
FASE EXE/WB:
ACC ← LMDR+0
µPC ← 0
FASE MEM:
LMDR ← Mem[MAR]
FASE EXE/WB:
ACC ← LMDR op ACC
µPC ← 0
FASE MEM:
Mem[MAR] ← ACC
µPC ← 0
FASE SETPC:
if COND:
PC ← MAR (via ALU)
µPC ← 0
INT (da sistema) RTI JSUB RET (from subroutine)
FASE STPC:
IAR ← PC
FASE SETPC:
PC ← MAR (via ALU)
µPC ← 0
FASE SETPC:
PC ← IAR
µPC ← 0
FASE STPC:
SAR ← PC
FASE SETPC:
PC ← MAR (via ALU)
µPC ← 0
FASE SETPC:
PC ← SAR
µPC ← 0
Dove:
MEM è la fase di accesso alla memoria;
EXE/WB è la fase di calcolo effettivo e di aggiornamento dell'Accumulatore;
STPC (Store PC) è la fase in cui viene memorizzato il PC prima di gestire un interrupt o saltare ad una
subroutine;
SETPC è la fase di impostazione (o ripristino istruzioni di return) del PC.
La sua codifica in RTL si ottiene banalmente trascrivendo in sequenza opportunamente le microistruzioni
relative alle fasi come definito nella prima parte dell'esercizio rispettivamente per una Load, per una
operazione ALU (somma) e per una Store.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 61
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Per cui si ha:
LD 1200
FASE IF
IR ← Mem[PC]
PC ← PC+4
FASE ADD/ID
MAR ← IR AND #0FFFFFFF
µPC ← MM[IR[opcode]]
FASE MEM
LMDR ← Mem[MAR] (MAR == 1200)
FASE EXE/WB
ACC ← LMDR+0
µPC ← 0
ADD 1204
FASE IF
IR ← Mem[PC]
PC ← PC+4
FASE ADD/ID
MAR ← IR AND #0FFFFFFF
µPC ← MM[IR[opcode]]
FASE MEM
LMDR ← Mem[MAR] (MAR == 1204)
FASE EXE/WB
ACC ← LMDR op ACC (op == +)
µPC ← 0
ST 1200
FASE IF
IR ← Mem[PC]
PC ← PC+4
FASE ADD/ID
MAR ← IR AND #0FFFFFFF
µPC ← MM[IR[opcode]]
FASE MEM
Mem[MAR] ← ACC (MAR == 1200)
µPC ← 0
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 62
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
PARTE SECONDA
PARTE SECONDA
MEMORIE CACHE
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 63
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
GERARCHIA DI MEMORIA
Nella figura qui affianco è riportata la struttura
gerarchica di un sistema di memorie. Quello che
è interessante vedere è che la dimensione
(capacità) dei vari blocchi di memoria aumenta
con l’allontanarsi dal processore; si osserva
anche che allontanandosi dalla CPU diminuisce
la velocità di accesso alle informazioni e il costo
rapportato al byte.
BREVE CENNO SU:
MECCANISMO A FINESTRA DEI REGISTRI L’ideale sarebbe avere una CPU con molti
registri, veloci e convenienti; ma mettere a
disposizione un numero elevato di registri
all’interno del processore non sarebbe
conveniente, poiché in realtà questo porterebbe
a reperire informazioni in maggior tempo.
Infatti si riesce ad accedere in maniera diretta e veloce ai registri, proprio se questi sono in numero limitato;
inoltre poiché ogni registro ha un nome identificativo univoco, nel caso in cui si vuole avere un numero
molto più ampio di registri bisognerebbe puntare ad un registro specificando un numero di bit molto più
grande e questo significherebbe avere un’istruzione con tre operandi, ciascuno dei quali con un elevato
numero di bit; quindi l’istruzione avrebbe un numero troppo grande per individuare solo i registri. In seguito
ci si accorgerà che quando nel processore si inserisce una memoria cache, in pratica, si riesce a
implementare la logica a più registri attraverso il meccanismo a finestra; il progettista può decidere di
inserire nel processore più di 32 o 64 registri, ma dando la visibilità alla CPU solo ad un numero ristretto di
registri. Questo meccanismo è utile nei casi in cui vi è una chiamata alla procedura di gestione di un
interrupt; la procedura potrebbe utilizzare i registri per scriverci delle informazioni necessarie all’esecuzione.
Il meccanismo permette di far puntare la CPU ad altri registri, in maniera tale da non far sovrascrivere i dati
e inoltre questo meccanismo permette di non effettuare, o comunque limitare, il salvataggio dei registri
nello stack (è richiesto solo il salvataggio di PC e del PSW e di un codice che identifica di quanto è stata
spostata la finestra).
PRINCIPI FONDAMENTALI DELLA GERARCHIA DI MEMORIA
TRASPERENZA DEI LIVELLI: ogni livello intermedio della gerarchia è “trasparente” al processore e
“simula” il processore per il livello immediatamente inferiore, mentre “simula” la memoria per il
livello immediatamente superiore. Per comprendere meglio questo concetto, si consideri questo
esempio:
supponiamo che la memoria centrale chiede dei dati ai dischi;
dal punto di vista dei dischi è come se fosse il processore a richiedere i dati, quindi la memoria per il
livello sottostante simula il processore;
la cache (livello immediatamente superiore) è vista come processore dalla memoria, ma
quest’ultima simula la memoria per la cache.
Per cui, dal punto di vista del processore tutto ciò che sta sotto è memoria.
Co
sto/b
yte
1° LIVELLO
2° LIVELLO
MEMORIA CENTRALE
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 64
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
PRINCIPI DI LOCALITA’: la CPU richiede dati seguendo due principi di località:
- LOCALITA’ SPAZIALE: quando una cella di memoria viene referenziata, le celle vicine (ad
essa contigue) hanno un’alta probabilità di essere a loro volta referenziate di lì a poco;
questo principio si applica bene alle istruzioni di un programma, ma anche ai vettori ed alle
matrici;
- LOCALITA’ TEMPORALE: quando una cella di memoria viene referenziata, è probabile che
presto venga referenziata di nuovo; questo principio si applica bene soprattutto ai dati ed
alle variabili.
Questi principi suggeriscono l’uso dei blocchi; un blocco è una quantità d’informazione che ha la
caratteristica di essere contigua in memoria, quindi la memoria sarà divisa in un numero fisso di locazioni
contigue. In questo modo quando una memoria dovrà dare alla
memoria di livello superiore un dato le passerà l’intero blocco
contenente il dato richiesto; anche se può sembrare di perdere del
tempo, in questo modo vengono rispettati i principi e allo stesso
tempo analizzando le prestazioni ci si accorge che questa è una
scelta ottimale.
Supponiamo che un i-esimo livello superiore chieda un dato che si
trova ad un qualsiasi indirizzo del livello inferiore. Il tempo, affinché il livello superiore possa avere a
disposizione il dato, è possibile descriverlo in questo modo:
𝑇 = 𝑇𝐿𝑖−1+ 𝑇𝑆𝑖
Dove:
𝑇𝐿𝑖−1 è 𝑖𝑙 𝑡𝑒𝑚𝑝𝑜 𝑑𝑖 𝐿𝑒𝑡𝑡𝑢𝑟𝑎 𝑑𝑎𝑙 𝑙𝑖𝑣𝑒𝑙𝑙𝑜 𝑖𝑛𝑓𝑒𝑟𝑖𝑜𝑟𝑒 𝑖 − 1
𝑇𝑆𝑖 è 𝑖𝑙 𝑡𝑒𝑚𝑝𝑜 𝑑𝑖 𝑆𝑐𝑟𝑖𝑡𝑡𝑢𝑟𝑎 𝑎𝑙 𝑙𝑖𝑣𝑒𝑙𝑙𝑜 𝑠𝑡𝑒𝑠𝑠𝑜 𝑖
Se si sta facendo lettura dal disco il tempo di lettura dipenderà da tre fattori, quali: tasso di trasferimento,
tempo di ricerca e tempo di latenza rotazionale; di cui due sono tempi meccanici, per cui il tempo di
accesso è più alto rispetto se la lettura è effettuata ad esempio in memoria centrale.
Per cui al momento di una lettura di un dato, si effettua un prelievo di un blocco contenente il dato, poiché
per il principio di località temporale è possibile che il secondo dato, che eventualmente sarà richiesto, sia
compreso fra quelli prelevati; quindi questa scelta porta ad un minor tempo per la lettura di un insieme di
dati, rispetto al tempo per leggere un singolo dato per volta.
Questa filosofia è applicata alla piramide gerarchica; quando la CPU chiede un dato alla memoria cache, se
questa non c’è l’ha, lo chiederà al livello sottostante insieme ad un blocco di dati. Lo stesso vale per gli altri
livelli.
Essendo ogni livello più piccolo del precedente, non si ha una corrispondenza 1 ad 1; per cui bisogna gestire
quattro fondamentali problemi.
QUATTRO DOMANDE PER LA CLASSIFICAZIONE DELLE GERARCHIE DI MEMORIE I problemi che si presentano quando si mettono in relazione i diversi livelli di una gerarchia di memorie
sono bene evidenziati dalle seguenti quattro domande:
D1) Dove è possibile mettere un blocco nel livello superiore? (allocazione del blocco)
D2) Come è possibile trovare un blocco quando è nel livello superiore? (identificazione del blocco)
D3) Quale blocco deve essere sostituito in caso di fallimento di accesso? (sostituzione del blocco)
D4) Cosa succede nel caso di una scrittura? (strategia di scrittura)
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 65
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Consideriamo ora le cache più in dettaglio esaminando le risposte alle quattro domande sulle gerarchie di
memorie.
MEMORIE CACHE Un po’ di storia e curiosità
La prima cache nella storia dei calcolatori è stata descritta in un articolo di Wilkes nel 1965; l’abstract
dell’articolo sostanzialmente cita: “si discute dell’utilizzo di una memoria veloce, di 32’000 parole, supporto
di una memoria centrale più lenta, di 1'000'000 di parole, in modo tale che il tempo di accesso effettivo sia
più vicino a quello di una memoria veloce che a quello di una memoria lenta.”
Questa idea, al tempo innovativa, porta, solo dopo tre anni, alla realizzazione del primo calcolatore dotato
di memoria cache, presso l’università di Cambridge. Per fare questo occorreva una tecnologia diversa, più
veloce, da quella utilizzata per la memoria centrale, infatti vennero utilizzati i DIODI TUNNEL, però essendo
questa tecnologia, all’epoca molto ingombrante, potevano essere realizzate memorie di piccole dimensioni.
Proprio a causa delle grandi dimensioni è famoso l’aneddoto sulla parola “debug”: “Il 9 settembre del 1945
Grace Murray Hopper (ufficiale e matematico di gran valore) che prestava servizio in Virginia presso la
marina militare degli Stati Uniti stava cercando di trovare l'errore che inceppava il computer basato su un
sistema Harvard Mark II, quando decise di controllare lo stanzone contenente l’intero sistema, trovò un
insetto che girovagava allegramente (prima di morire) in mezzo ai circuiti e che era la causa del
malfunzionamento, dopo aver rimosso l’insetto, il tenente lo incollò sui suoi appunti e annotò: «1545. Relay
#70 Pannello F (falena) nel relay. Primo vero caso di bug trovato>>”. Questo registro è conservato presso lo
Smithsonian National Museum of American History.
Da allora il termine "bug" entrò nell'informatica per indicare un errore di programmazione.
STRATEGIE DI ALLOCAZIONE DEI BLOCCHI
Si suppone, per semplicità, che la memoria centrale sia costituita da 32 blocchi e la memoria cache
costituita da 8 blocchi; si vuole prelevare un dato, all’indirizzo x, dalla memoria centrale e caricarlo in cache.
Questo dato è interno ad uno dei 32 blocchi che costituiscono la memoria centrale; ad esempio si consideri
questa situazione: il blocco contenente il dato x è il numero (16)8.
Indirizzo di blocco (memoria centrale) N.
bl
oc
co
0 1 2 3 4 5 6 7 1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
3
0
3
1
3
2
3
3
3
4
3
5
3
6
3
7
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 66
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
I vincoli sulla posizione dei blocchi creano tre categorie di cache:
CACHE COMPLETAMENTE ASSOCIATIVA – Se un blocco può essere messo ovunque nella cache, in una qualsiasi posto chiamato “linea”, essa è definita completamente associativa.
0 1 2 3 4 5 6 7
CACHE AD INDIRIZZAMENTO DIRETTO – Se ogni blocco può comparire in un'unica linea della cache, allora essa è definita a indirizzamento diretto. La linea nella cache si ottiene tramite una operazione di mascheramento ai bit che identificano il blocco; per cui essendo 𝟏𝟔 𝟖 = 𝟎𝟎𝟏𝟏𝟏𝟎 𝟐 e dato che la cache è di 8 linee, bisognerà prendere 3 bit dei 6 che identificano il blocco; quindi se considero i primi 3 bit incorrerò sicuramente in sovrascritture, poiché nel momento in cui bisognerà caricare ad esempio il blocco adiacente, 17, questo andrà a scriversi comunque nel blocco 1, determinando la perdita dei dati precedentemente contenuti. Per cui si considerano gli ultimi 3 bit e quindi il blocco 16 viene caricato nella linea 𝟏𝟏𝟎 𝟐 = 𝟔 𝟖. Questa operazione equivale a: 𝑖𝑛𝑑𝑖𝑟𝑖𝑧𝑧𝑜 𝑑𝑖 𝑏𝑙𝑜𝑐𝑐𝑜 10 𝑀𝑂𝐷 𝑛𝑢𝑚𝑒𝑟𝑜 𝑒𝑓𝑓𝑒𝑡𝑡𝑖𝑣𝑜 𝑑𝑖 𝑙𝑖𝑛𝑒𝑒 𝑛𝑒𝑙𝑙𝑎 𝑐𝑎𝑐𝑒
Considerando l’esempio si ha: 14 𝑀𝑂𝐷 8 = 6
0 1 2 3 4 5 6 7
Questo metodo di allocazione dei blocchi è il più semplice che si possa avere, ma è il meno consigliabile dal
punto di vista del Principio di Località Temporale.
CACHE SET ASSOCIATIVA – Se un blocco può essere messo in un insieme ristretto di posizioni nella cache, essa è definita set-associativa. Un insieme o set è un gruppo di due o più blocchi della cache. Un blocco viene prima messo in
corrispondenza di un insieme e poi può essere messo in precisa posizione dell’insieme. Di solito, l’insieme
o set viene individuato dalla seguente operazione:
(𝑖𝑛𝑑𝑖𝑟𝑖𝑧𝑧𝑜 𝑑𝑖 𝑏𝑙𝑜𝑐𝑐𝑜) 10 𝑀𝑂𝐷 (𝑛𝑢𝑚𝑒𝑟𝑜 𝑒𝑓𝑓𝑒𝑡𝑡𝑖𝑣𝑜 𝑑𝑖 𝑠𝑒𝑡 𝑛𝑒𝑙𝑙𝑎 𝑐𝑎𝑐𝑒)
Considerando l’esempio si ha: 14 𝑀𝑂𝐷 4 = 2.
Questa operazione equivale a leggere gli ultimi due bit dei 6 che identificano il set: 001110.
0 1 2 3 4 5 6 7
0 1 0 1 0 1 0 1
Set. 0 Set. 1 Set. 2 Set. 3
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 67
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
STRATEGIE DI RICERCA E IDENTIFICAZIONE
Dall’indirizzo di memoria proveniente dalla CPU la cache estrae l’etichetta e la confronta con tutte le
etichette presenti nella Tag Memory della cache, a cui corrisponde una dato nella effettiva memoria dati
della cache se la sua organizzazione è completamente associativa.
Se invece la cache è di tipo set-associativo, l’etichetta estratta viene confrontata con tutte le Tag Memory
appartenenti all’unico insieme deputato a contenere il blocco ricercato.
Infine, nel caso di cache a indirizzamento diretto l’etichetta estratta viene confrontata con l’unica possibile
Tag Memory.
Le memorie cache di tipo set-associativo ed ad indirizzamento diretto suddividono un indirizzo di memoria
in tre campi:
Etichetta Indice Spiazzamento nel blocco
- Etichetta: serve per identificare il blocco ricercato;
- Indice: serva a individuare il set (set-associativa) o il blocco (indirizzamento diretto);
- Spiazzamento nel blocco: è utilizzato per selezionare il dato (parola) desiderato nel blocco.
Le memorie cache completamente associative suddividono un indirizzo di memoria in due soli campi:
Etichetta Spiazzamento nel blocco
A questa conclusione si giunge considerando che, se la dimensione totale viene mantenuta, un incremento
della associatività comporta un aumento del numero dei blocchi per insieme; di conseguenza diminuisce il
numero degli insiemi e aumenta la dimensione dell’etichetta. Cioè il confine tra l’etichetta e l’indice si
sposta verso destra via via che si aumenta l’associatività.
La necessità che l’accesso alla cache sia veloce richiede che i confronti tra le etichette siano fatti in
parallelo. Perciò nel caso di cache completamente associative vi saranno in parallelo tanti confronti (e
quindi tanti comparatori) quanti sono i blocchi in cui è suddivisa la cache stessa (nell’esempio si avranno 8
comparatori); nel caso di cache set-associative vi saranno in parallelo tanti confronti (e quindi tanti
comparatori) quanti sono i blocchi che costituiscono i set in cui è suddivisa la cache stessa (nell’esempio si
avranno 2 comparatori); infine, nel caso di una cache a indirizzamento diretto si avrà solo un confronto (e
quindi un solo comparatore).
Ci deve essere poi un modo per vedere se un blocco nella memoria cache non contiene informazioni valide.
Il metodo più comune consiste nell’aggiungere un bit di validità (Validity bit) all’etichetta che indica la
validità dell’indirizzo contenuto nell’etichetta stessa. Tale indirizzo non viene considerato se il bit non ha un
valore alto.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 68
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
STRATEGIE DI SOSTITUZIONE (fallimenti di accesso)
La CPU chiede alla memoria cache un dato che in essa non è presente: allora la memoria deve caricare un
blocco che contiene questo dato dal livello sottostante.
Nel caso di organizzazione a indirizzamento diretto, lo schema è così semplice che non ci sono alternative:
soltanto un blocco viene controllato quando si effettua un accesso alla memoria e solo quel blocco può
essere sostituito.
Nel caso di organizzazione completamente associativa e set associativa è possibile operare una scelta fra
tre metodi:
1. METODO RANDOM: i blocchi candidati alla sostituzione in questo caso vengono scelti in modo
casuale. Affinché il metodo sia efficace si deve avere una bassa probabilità di sostituire un blocco
appena caricato, cosa che è tanto più garantita quanto maggiore è il numero dei blocchi. Questo è il
motivo per cui tale metodo è indicato per le memorie cache completamente associative. Un
vantaggio della scelta casuale è la semplicità della realizzazione circuitale.
2. METODO LRU (Last Recently Used): il blocco che viene sostituito quando si adotta questo metodo è
quello che è rimasto inutilizzato per il periodo di tempo più lungo. Tale strategia si basa sul
Principio di Località Temporale: se è probabile che le linee usate di recente siano riutilizzate, allora
il miglior candidato alla sostituzione è la linea che è stata usata meno di recente. Per ridurre la
possibilità di eliminare informazioni che presto saranno di nuovo necessarie, gli accessi alle linee
vengono registrati. Vediamo come considerando l’organizzazione set associativa (le stesse
considerazioni sono valide per la completamente associativa): ogni linea all’interno di un set viene
dotato di un contatore di utilizzo. Ogni qualvolta si utilizza una linea si azzera il suo contatore e si
incrementa di una unità il contatore delle altre linee dello stesso set; in tal modo i contatori delle
linee non utilizzate avranno un valore più elevato. La linea il cui contatore presenta il valore più alto
è quello non usata da più tempo. Nel caso in cui tutte le linee avessero i contatori a zero, si
prenderà allora la prima linea. Questo metodo va bene quando le linee del set sono poche, perché
devono essere eseguiti molti confronti.
In generale, se n sono le linee del set, avremo 𝑛(𝑛 − 1) confronti e quindi sarà necessaria una rete
di 𝑛(𝑛 − 1) comparatori. È chiaro allora che quando il numero delle linee da tenere sotto controllo
cresce, la strategia LRU diventa sempre più costosa e, d’altra parte, sempre più di frequente
fornisce risultati approssimativi.
Si consideri la seguente situazione in cui inizialmente la linea candidata LRU è la linea 0 :
LINEA USATA ALL’ISTANTE / 3 2 1 0 0 2 3 1
LINEA CANDIDATA LRU 0 0 0 0 3 3 3 1 0
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 69
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Non è detto che questo metodo
convenga sempre; analizzando la
tabella qui affianco è facile notare
infatti che aumentando dimensione
e associatività (linee in un set) LRU
e RANDOM si uguagliano e questo
avviene per due motivi:
- nella scelta fra più linee, anche casualmente, è facile che ne venga selezionata qualcuna che non
serve subito;
- nella scelta fra più linee, il metodo LRU diventa meno preciso.
3. METODO FIFO (First In First Out): consiste nel sostituire il blocco che era stato utilizzato N accessi
prima, indipendentemente dal fatto che sia stato utilizzato o meno negli ultimi N-1 accessi. In pratica il sistema funziona grazie a uno shift register, ossia un registro a scorrimento costituito da un serie di celle in cui, per ogni colpo di clock, il contenuto di una cella passa alla cella successiva; si osservi questo esempio:
È evidente che il metodo non è rigoroso dal punto di vista del Principio di Località Temporale,
perché si rischia di sostituire un blocco che è stato referenziato di recente.
Dal punto di vista dei costi, si può facilmente notare, che il metodo LRU richiede una complessità di
realizzazione superiore al metodo FIFO.
FALLIMENTI DI ACCESSO ALLA CACHE – legge delle tre C Un modello intuitivo del comportamento delle memorie cache attribuisce tutti i fallimenti a una delle tre
cause che seguono:
1. Obbligatorietà (Compulsory): al primo accesso un blocco non è presente nella cache e deve esservi
trasferito. Tali fallimenti vengono definiti fallimenti di partenza a freddo (cold start misses) oppure
fallimenti di primo accesso (first reference misses).
2. Capacità (Capacity): se la cache non può contenere tutti i blocchi necessari all’esecuzione di un
programma, i fallimenti causati dalla capacità sono quelli connessi ai blocchi che devono essere
scartati e ripresi più tardi.
3. Conflitto (Conflict): se la strategia di piazzamento dei blocchi è set-associativa oppure a
indirizzamento diretto, vi saranno dei fallimenti dovuti ai conflitti (oltre a quelli obbligatori o di
capacità) causati dai blocchi che bisogna scartare e recuperare più tardi perché troppi blocchi
devono essere caricati nello stesso insieme. Essi sono detti anche fallimenti per collisione (collision
misses).
LINEA
3
LINEA
1
LINEA
2
LINEA
5
LINEA
4
LINEA
3
LINEA
1
LINEA
2
LINEA
5 Linea 4
Blocco che verrà sostituito
(la tabella riporta il numero di fallimenti per 1000 istruzioni)
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 70
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
STRATEGIE DI SCRITTURA NELLA CACHE
Innanzitutto bisogna dire che le letture dominano gli accessi alla cache. Tutti gli accessi per le istruzioni
sono letture, inoltre molte istruzioni non scrivono in memoria. Sembrerebbe quindi che ottimizzando le
operazioni di lettura si migliorerebbero le prestazioni della cache. Ciò è vero solo parzialmente. La legge di
Amdahl stabilisce infatti che progetti mirati a ottenere alte prestazioni non possono trascurare le
operazioni di scrittura.
L’operazione più frequente, cioè la lettura di una linea, può essere resa facilmente più veloce effettuandola
contemporaneamente alle operazioni di lettura e verifica dell’etichetta. Perciò la lettura della linea, può
iniziare non appena il suo indirizzo è disponibile. Se l’accesso riesce, allora la linea viene passata subito alla
CPU. Se invece fallisce non c’è alcun beneficio, ma neppure un danno.
Questo non succede per le operazioni di scrittura. Il processore specifica la dimensione del dato da scrivere;
solo una particolare parte della linea può essere modificata.
In generale ciò significa che sulla linea viene eseguita una sequenza leggi –> modifica –> scrivi: viene letta la
linea originale, ne viene modificata una parte e, infine, viene scritta la linea con il nuovo valore.
Oltretutto, la modifica della linea non può iniziare finché l’etichetta non è stata controllata per verificare la
riuscita dell’accesso. Poiché la valutazione dell’etichetta non può avvenire in parallelo, le operazioni di
scrittura richiedono più tempo di quelle di lettura.
Perciò è la politica di scrittura che distingue molti progetti di memorie cache.
Le strategie di scrittura più tipiche sono due:
1. WRITE THROUGH: l’informazione viene scritta sia nel blocco della cache, sia
nel blocco del livello inferiore della memoria. Nel caso di politica write
through, lo stato in cui si trova la CPU che aspetta il termine di
un’operazione di scrittura prende il nome di stallo di scrittura (write stall), in
effetti l’operazione di scrittura avviene alla velocità della memoria centrale.
Un’ottimizzazione utilizzata di solito per ridurre il tempo di stallo consiste
nell’inserimento di un buffer di scrittura che consente al processore di
proseguire mentre la memoria viene modificata. Questo buffer è costituito nella seguente maniera:
essendo un buffer è organizzato da un insieme di celle in coda; vi è lo spazio non solo per contenere i
dati ma anche, per ogni cella, un’etichetta che indica in quale indirizzo della memoria il dato deve
essere scritto. Inoltre nell’etichetta vi è anche una sorta di bit di validità, il quale assicura che se nel
buffer vi è un dato ripetuto ma modificato, viene invalidato quello che deve ancora uscire; in questa
maniera il processo di scrittura in memoria centrale è velocizzato.
Comunque, uno stallo di scrittura è possibile anche in presenza di un buffer di scrittura, poiché esso è di
dimensioni limitate.
2. WRITE BACK: l’informazione viene scritta solo nel blocco della cache. Il
blocco della cache modificato viene scritto nella memoria principale solo
quando viene sostituito.
Definizione: Un blocco in una cache di tipo Write Back viene definito pulito
(clean) o sporco (dirty) a seconda che l’informazione immagazzinata nella
cache sia uguale o diversa da quella presente nel livello inferiore di memoria.
I vantaggi della strategia WT sono: semplice implementazione; cache sempre clean; il livello gerarchico
inferiore dispone della copia più recente dei dati.
CPU
CACHE
MEMORIA CENTRALE I/O
CPU
CACHE
MEMORIA CENTRALE I/O
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 71
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
I vantaggi della strategia WB sono: le operazioni di scrittura avvengono alla velocità della cache; scritture
multiple eseguite sullo stesso blocco richiedono una sola operazione di scrittura.
Bisogna comunque considerare che l’architettura di un elaboratore prevede anche la presenza dell’I/O; per
cui è necessario analizzare il comportamento di queste due tecniche nelle situazioni in cui vengono
effettuati Input e Output di blocchi da e verso l’I/O.
INPUT (I/O MEM. CENTRALE): in entrambe le tecniche nel caso in cui l’I/O vada a modificare un
blocco della memoria centrale, in cache si avranno i dati, contenuti in quel blocco, scaduti (se quel
blocco è stato precedentemente scritto in cache);
OUTPUT (MEM. CENTRALE I/O): con la tecnica Write Back l’I/O troverà dei dati scaduti in
memoria centrale, cosa che non succede con la tecnica Write Through.
Per ridurre la frequenza delle operazioni di scrittura dei blocchi quando vengono sostituiti viene
comunemente utilizzato un bit di modifica (dirty bit).
Definizione: Il bit di modifica (dirty bit) è un bit di stato che indica se il blocco, durante la sua permanenza
nella cache, è stato modificato. Se è rimasto invariato, il blocco non viene scritto, visto che il livello inferiore
di memoria contiene le stesse informazioni della cache.
ELETTRONICA DELLE MEMORIE È possibile realizzare memorie utilizzando le seguenti due tecnologie:
SRAM (Static RAM): il contenuto è mantenuto costante nel tempo (finché c’è tensione di alimentazione), per cui non è necessario il refresh della memoria; la sua realizzazione richiede 6 transistor per ogni cella memorizzante un singolo bit. Questo tipo di realizzazione richiede un maggiore spazio fisico, ma in compenso offre maggiore velocità; è tipicamente usata nelle cache all’interno dei processori.
DRAM (Dynamic RAM): il contenuto è mantenuto per un periodo che dipende dal tempo di scarica del condensatore, per cui è necessario il refresh della memoria; la sua realizzazione richiede 1 transistor e 1 condensatore per ogni cella memorizzante un singolo bit. Questo tipo di realizzazione richiede un minore spazio fisico, ma non offre elevate velocità (causa del refresh); è tipicamente usata nelle realizzazioni di memorie centrali.
Circuito di una cella di memoria SRAM.
Circuito di una cella di memoria DRAM.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 72
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
VALUTAZIONE DELLE PRESTAZIONI DELLA MEMORIA CACHE Prima di valutare le prestazioni, fondamentali per la progettazione di una memoria cache, è utile chiarire
alcuni concetti fondamentali.
La CPU indirizza solo la memoria principale; l’indirizzo generato dalla CPU viene però intercettato dalla
cache. Se la cache possiede questo indirizzo, l’accesso a memoria ha avuto successo (HIT); se non vi è
questo indirizzo, l’accesso a memoria non ha avuto successo (MISS) e la cache invia un segnale al piedino di
WAIT del processore per bloccare il clock. La cache realizza un effettivo vantaggio in velocità solo se i dati
rispettano i due principi di località visti in precedenza. Infatti, all’accensione di un computer, questo sarà
lento, perché deve rispettare l’obbligatorietà, cioè è obbligato a caricare certi dati distanti in memoria tra
loro.
Di seguito vengono definiti i significati di: Hit Rate, Miss Rate, Hit Time e Miss Penality.
HIT RATE: percentuale di tentativi di accesso che hanno avuto successo;
MISS RATE: percentuale di tentativi di accesso falliti, per cui: 𝑀𝑅 = 1 −𝐻𝑅;
HIT TIME: tempo di accesso al livello inferiore della gerarchia di memoria, che comprende anche il
tempo necessario a determinare se l’accesso ha successo oppure fallisce;
MISS PENALITY (Penalizzazione di fallimento): tempo necessario a sostituire un blocco nel livello
superiore con un blocco preso dal livello inferiore più il tempo impiegato per trasferire le
informazioni al centro che li aveva richieste, la CPU.
La penalizzazione di fallimento viene a sua volta suddivisa in due componenti: il tempo di accesso, ossia il
tempo necessario per accedere alla prima parola del blocco richiesto dopo che è stato rilevato il fallimento,
ed il tempo di trasferimento, che indica il tempo utilizzato per trasferire le altre parole del blocco.
Il tempo di accesso è collegato alla latenza del livello inferiore nella gerarchia di memoria, mentre il tempo
di trasferimento è collegato alla larghezza di banda del canale tra i due livelli di memoria.
Vediamo ora come è possibile effettuare una misura delle prestazioni di una memoria cache considerando
il tempo di CPU, il quale può essere diviso nei cicli che la CPU spende eseguendo il programma e in quelli
che la CPU trascorre in attesa di risposta dal sistema di memoria. Perciò:
𝑻𝑬𝑴𝑷𝑶 𝑫𝑰 𝑪𝑷𝑼 =
= 𝑪𝑰𝑪𝑳𝑰 𝑫𝑰 𝑪𝑷𝑼 𝑰𝑵 𝑬𝑺𝑬𝑪𝑼𝒁𝑰𝑶𝑵𝑬 + 𝑪𝑰𝑪𝑳𝑰 𝑫𝑰 𝑺𝑻𝑨𝑳𝑳𝑶 𝑰𝑵 𝑴𝑬𝑴𝑶𝑹𝑰𝑨 ∗ 𝑻𝑬𝑴𝑷𝑶 𝑫𝑬𝑳 𝑪𝑰𝑪𝑳𝑶 𝑫𝑰 𝑪𝑳𝑶𝑪𝑲
Per semplificare la valutazione delle alternative durante il progetto della cache spesso si adotta l’ipotesi che
tutti gli stalli di memoria siano dovuti alla cache. Ciò è vero per molte macchine; anche in quelle macchine
che non verificano tale ipotesi, la cache è la causa principale degli stalli, benché questi non siano dovuti
esclusivamente ad essa. Per chiarire il senso della formula scritta sopra bisogna stabilire se il ciclo di clock
utilizzato per un accesso alla cache debba essere considerato parte dei cicli di CPU in esecuzione o parte dei
cicli di stallo di memoria. Entrambe le ipotesi sono plausibili, ma la più comunemente accettata è quella
secondo cui i cicli per un accesso riuscito vanno inclusi nei cicli di CPU in esecuzione.
I cicli di stallo di memoria possono quindi essere definiti in termini di numero di accessi alla memoria per
programma, di penalizzazione di fallimento (misurata in cicli di clock) e miss rate per operazioni di lettura e
di scrittura: 𝑪𝑰𝑪𝑳𝑰 𝑫𝑰 𝑺𝑻𝑨𝑳𝑳𝑶 𝑰𝑵 𝑴𝑬𝑴𝑶𝑹𝑰𝑨 = 𝑪𝑰𝑪𝑳𝑰 𝑫𝑰 𝑺𝑻𝑨𝑳𝑳𝑶 𝑰𝑵 𝑳𝑬𝑻𝑻𝑼𝑹𝑨 + 𝑪𝑰𝑪𝑳𝑰 𝑫𝑰 𝑺𝑻𝑨𝑳𝑳𝑶 𝑰𝑵 𝑺𝑪𝑹𝑰𝑻𝑻𝑼𝑹𝑨 =
= 𝑳𝑬𝑻𝑻𝑼𝑹𝑬 𝑰𝑵 𝑴𝑬𝑴𝑶𝑹𝑰𝑨
𝑷𝑹𝑶𝑮𝑹𝑨𝑴𝑴𝑨∗ 𝑴𝑰𝑺𝑺 𝑹𝑨𝑻𝑬 𝑷𝑬𝑹 𝑳𝑬 𝑳𝑬𝑻𝑻𝑼𝑹𝑬 ∗ 𝑷𝑬𝑵𝑨𝑳𝑰𝒁𝒁𝑨𝒁𝑰𝑶𝑵𝑬 𝑫𝑰 𝑭𝑨𝑳𝑳𝑰𝑴𝑬𝑵𝑻𝑶 𝑷𝑬𝑹 𝑳𝑬 𝑳𝑬𝑻𝑻𝑼𝑹𝑬 +
𝑺𝑪𝑹𝑰𝑻𝑻𝑼𝑹𝑬 𝑰𝑵 𝑴𝑬𝑴𝑶𝑹𝑰𝑨
𝑷𝑹𝑶𝑮𝑹𝑨𝑴𝑴𝑨∗ 𝑴𝑰𝑺𝑺 𝑹𝑨𝑻𝑬 𝑷𝑬𝑹 𝑳𝑬 𝑺𝑪𝑹𝑰𝑻𝑻𝑼𝑹𝑬 ∗ 𝑷𝑬𝑵𝑨𝑳𝑰𝒁𝒁𝑨𝒁𝑰𝑶𝑵𝑬 𝑫𝑰 𝑭𝑨𝑳𝑳𝑰𝑴𝑬𝑵𝑻𝑶 𝑷𝑬𝑹 𝑳𝑬 𝑺𝑪𝑹𝑰𝑻𝑻𝑼𝑹𝑬
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 73
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
La relazione che lega la penalizzazione di fallimento alla dimensione del blocco e la relazione che lega il miss rate alla dimensione del blocco sono riportate nelle seguenti figure:
Queste rappresentazioni si basano sull’ipotesi che la dimensione del livello superiore della memoria non
cambi; osservando il primo grafico si può notare che la parte della penalizzazione di fallimento correlata al
tempo di accesso rimane costante al variare della dimensione del blocco; il tempo di trasferimento, invece,
cresce proporzionalmente alla dimensione del blocco. Osservando il secondo grafico si nota che
l’incremento delle dimensioni di un blocco provoca una diminuzione del miss rate fino a quando la
riduzione dei fallimenti collegati alle maggiori dimensioni dei blocchi (località spaziale) è superiore
all’aumento dei fallimenti collegato con la diminuzione del numero dei blocchi (località temporale).
In pratica, ciò che succede è che man mano che la dimensione di un blocco cresce, la parte del blocco che
non viene utilizzata è così grande da sovrapporsi a informazioni utili presenti in precedenza nella cache; a
questo punto il miss rate comincia a crescere. Il punto della curva, sulla destra, in cui il miss rate inizia ad
aumentare al crescere delle dimensioni del blocco viene a volte definito punto di contaminazione (pollution
point).
Per cui si è portati a scegliere la dimensione del blocco pari al minimo della curva; effettuando questa scelta
si va a minimizzare il Miss Rate, ma l’obiettivo del progettista è quello di scegliere la dimensione del blocco
che permetta di avere il più piccolo possibile il tempo medio di accesso alla memoria e non del numero di
fallimenti; il tempo medio di accesso alla memoria è pari a:
𝑻𝑬𝑴𝑷𝑶 𝑴𝑬𝑫𝑰𝑶 𝑫𝑰 𝑨𝑪𝑪𝑬𝑺𝑺𝑶 𝑨𝑳𝑳𝑨 𝑴𝑬𝑴𝑶𝑹𝑰𝑨 = 𝑯𝑰𝑻 𝑻𝑰𝑴𝑬 + 𝑴𝑰𝑺𝑺 𝑹𝑨𝑻𝑬 ∗ 𝑷𝑬𝑵𝑨𝑳𝑰𝒁𝒁𝑨𝒁𝑰𝑶𝑵𝑬 𝑫𝑰 𝑭𝑨𝑳𝑳𝑰𝑴𝑬𝑵𝑻𝑶
Per cui il valore da scegliere è approssimativamente il punto minimo preso sulla curva ottenuta dal
prodotto dei due grafici:
Pollution Point
x
Dimensione del blocco da considerare: arrotondare alla potenza di 2 più vicina
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 74
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
SCHEMA RIASSUNTIVO DEI VANTAGGI/SVANTAGGI DELLE TECNICHE E DEI METODI ANALIZZATI
ASSOCIATIVITA’ DIMENSIONE BLOCCHI POLITICA LRU BUFFER DI SCRITTURA
VANTAGGI
- Minor numero di
conflitti
- Benefici in cache di
medie dimensioni
- Minor numero di
etichette
- Minor Miss Rate per
cache a bassa
associatività
- Minor stallo di scrittura
SVANTAGGI
- Maggiori costi:
ampiezza delle
etichette e
aggiunta di
comparatori
- Politica di
sostituzione più
costosa
- Maggior tempo di
trasferimento
- Maggior costo
hardware
- Maggior costo
hardware
aumentando
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 75
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
FUNZIONAMENTO LOGICO DI UNA MEMORIA CACHE
Per descrivere il funzionamento logico verranno presi in esame due casi reali: la memoria cache del
PowerPC e quella del processore Motorola 68000
Cache PowerPC
CARATTERISTICHE:
- FORMATO ISTRUZIONI: 32 bit
- ORGANIZZAZIONE DELLA CACHE: Cache istruzioni e dati separate;
- DIMENSIONE DELLA CACHE: 16 Kbyte per ciascuna cache;
- ASSOCIATIVITA’ DELLA CACHE: Set associativa a 4 linee;
- SOSTITUZIONE: tecnica LRU;
- DIMENSIONE DEI BLOCCHI: 32 Byte (8 word da 4 byte per ogni blocco);
- GESTIONE DELLE OPERAZIONI DI SCRITTURA: prevalentemente Write back, ma anche Write
Through.
Stando a queste caratteristiche ogni set è di 128 Byte; per cui essendo la cache di 16 Kbyte si hanno 128
set, infatti: 16384
128= 128.
L’etichetta di ogni linea oltre a comprendere l’indirizzo ha 2 bit (xy) per codificare 4 stati:
- 2 stati per codificare il cambio di parola e la validità della linea (CHANGE BIT & VALID BIT);
- 2 stati per codificare situazioni particolari quando la cache è utilizzata nei sistemi multi processorie.
L’indirizzo di 32 bit inviato alla cache viene suddiviso in tre campi:
20 bit 7 bit 5 bit
- Il campo costituito dai 5 bit meno significativi dell’indirizzo serve per puntare ai 32 byte interni al
blocco;
- Il campo costituito dai 7 bit indirizza in maniera diretta uno dei 128 set;
- Il campo costituito dai 20 bit serve per effettuare il confronto con l’etichette delle quattro linee del
set individuato.
Il confronto avverrà in parallelo: i 20 bit vengono inviati in parallelo a quattro comporatori, ciascuno dei
quali riceverà come secondo operando un’etichetta. Se l’uguaglianza è verificata in uscita da uno dei
quattro comparatori vi è un 1; poi l’uscita alta del comparatore viene messa in AND con il Valid Bit per
assicurare la validità della linea; se la validità è verificata il dato è quindi presente in cache (HIT).
I 7 bit fungono da selettori per dei multiplexer che devono selezionare quale linea deve andare in ingresso
al comparatore per il confronto dell’etichetta.
L’uscita della AND va in ingresso a un demultiplxer il quale manderà sulla linea selezionata il risultato
dell’intero lavoro, ovvero il dato richiesto dalla CPU.
32 bit
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 76
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Di seguito è riportata un figura che implementa il funzionamento logico della cache del PowerPC.
xy: codificano se la linea è valida o meno; ------- : LINEE 00 ------- : LINEE 01 ------- : LINEE 10 ------- : LINEE 11 = : COMPARATORE : PORTA AND
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 77
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Cache MOTOROLA 68000
CARATTERISTICHE:
- FORMATO ISTRUZIONI: 32 bit
- ORGANIZZAZIONE DELLA CACHE: Cache istruzioni e dati separate;
- DIMENSIONE DELLA CACHE: 4 Kbyte per ciascuna cache;
- ASSOCIATIVITA’ DELLA CACHE: Set associativa a 4 linee;
- SOSTITUZIONE: tecnica RANDOM;
- DIMENSIONE DEI BLOCCHI: 16 Byte (4 word da 4 byte per ogni linea);
- GESTIONE DELLE OPERAZIONI DI SCRITTURA: Write back o Write Through
Stando a queste caratteristiche ogni set è di 64 Byte; per cui essendo la cache di 4 Kbyte si hanno 64 set,
infatti: 4096
64= 64.
L’etichetta di ogni linea oltre a comprendere l’indirizzo ha 2 bit, uno per identificare la validità (Valid Bit) e
uno per identificare la modifica (Dirty Bit, questo bit è presente per ogni word); quindi avendo un bit di
modifica per ogni parola, nel caso di gestione Word Through, in memoria centrale verrà sostituita la sola
word interessata e non l’intero blocco.
L’indirizzo di 32 bit inviato alla cache viene suddiviso in tre campi:
22 bit 6 bit 4 bit
- Il campo costituito dai 4 bit meno significativi dell’indirizzo serve per puntare ai 16 byte interni al
blocco;
- Il campo costituito dai 6 bit indirizza in maniera diretta uno dei 64 set;
- Il campo costituito dai 22 bit serve per effettuare il confronto con l’etichette delle quattro linee del
set individuato.
Il confronto avverrà in parallelo: i 22 bit vengono inviati in parallelo a quattro comporatori, ciascuno dei
quali riceverà come secondo operando un’etichetta. Se l’uguaglianza è verificata in uscita da uno dei
quattro comparatori vi è un 1; poi l’uscita alta del comparatore viene messa in AND con il Valid Bit per
assicurare la validità della linea; se la validità è verificata il dato è quindi presente in cache (HIT).
I 6 bit fungono da selettori per dei multiplexer che devono selezionare quale linea deve andare in ingresso
al comparatore per il confronto dell’etichetta.
L’uscita della AND va in ingresso a un demultiplxer il quale manderà sulla linea selezionata il risultato
dell’intero lavoro, ovvero il dato richiesto dalla CPU.
La figura che implementa il funzionamento logico della cache del Motorola 68000 è simile a quella del
PowePC con dovuti accorgimenti vista la minima differenza di funzionamento.
32 bit
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 78
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
INTERAZIONE DELLE MEMORIE CACHE IN UN SISTEMA COMPLESSO
PROBLEMATICHE RELATIVE ALL’I/O
Si consideri un sistema in cui la memoria cache ha una tecnica di gestione della scrittura di tipo Write
Through; come già detto con questa gestione la memoria centrale riceverà sempre aggiornamenti dalla
cache, per cui vi sarà sempre coerenza fra i blocchi di cache e di memoria centrale. Il problema sorge
quando il modulo I/O effettua operazioni di scrittura in memoria centrale. Questa operazione comporta dei
dati scaduti in memoria cache.
Quindi il sistema deve essere in qualche maniera modificato per evitare questo tipo di problematica.
Innanzitutto è impensabile collegare I/O e cache in modo tale da effettuare input direttamente in memoria
cache; questa soluzione risolverebbe i problemi relativi ai conflitti ma porta a far diventare la cache il “collo
di bottiglia” dell’intero sistema, abbattendo le sue prestazioni.
Per cui una soluzione può essere quella di far “monitorare” dalla cache l’input da parte dell’I/O in memoria
centrale; questo monitoraggio può essere fatto sia cambiando il Valid Bit del blocco che eventualmente
cambierà di valore, soluzione semplice, oppure, poichè il dato è ancora sul bus, è possibile prelevarlo è
scriverlo all’interlo del blocco interessato aggiornandolo, operando così una scelta meno dispendiosa ma
forse inutile (il blocco potrebbe non essere più utilizzato).
PROBLEMATICHE RELATIVE AI SISTEMI MULTICORE
La memoria centrale è condivisa fra più memorie cache di diverse CPU; la connessione fra una singola cache
e la memoria centrale non avviene in maniera indipendente dalle altre connessioni, ma attraverso un bus
che è osservato e monitorato da tutte le cache, in maniera tale che se la tecnica di gestione è Write
Through ed una cache sta scrivendo in memoria centrale, le altre cache potranno eventualmente
aggiornare i loro blocchi se interessati dall’operazione di scrittura.
CPU 1 CPU 2 CPU 3
CACHE CACHE CACHE
MEM. CENTRALE I/O
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 79
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
MIGLIORAMENTO DELLE PRESTAZIONI DELLA BANDA PASSANTE DI UNA MEMORIA La banda passante della memoria è quel parametro che identifica la quantità d’informazione che è possibile
leggere e scrivere nella data memoria in un determinato tempo:
𝐵 =𝐼
𝑇 𝑏𝑦𝑡𝑒
𝑠
Essendo un rapporto è possibile aumentare la banda passante in due modi: aumentando l’informazione
oppure dimunendo il tempo.
Vediamo due tecniche di architettura che portano ad aumentare l’informazione o a diminuire il tempo.
Il primo approccio consiste nel realizzare dei Banchi multipli di memoria paralleli: Si consideri una certa tecnologia che fornisce una certa banda passante; è semplice ottenere una banda
maggiore se si considera ad esempio la seguente situazione.
Quattro moduli di memoria da 1Kbyte per formare un memoria di 4Kbyte (dal punto di vista esterno la
memoria risulta un unico chip di 4Kbyte); ogni modulo ha una propria banda passante b. Se ad esempio una
parola da 4 byte è contenuta in un singolo modulo, la si otterebbe in un determinato tempo; però se la
stessa parola, la si va ad immaginare divisa in ogni modulo di memoria (1 byte per ogni modulo), si ottiene
la stessa banda che è aumentata di quattro. Semplicemente ogni byte che compone la parola è scritto allo
stesso indirizzo; essendo la memoria di 4K sarà indirizzata da indirizzi a 12 bit. Questo indirizzo avrà la
particolarità di avere i due bit meno significativi uguali a zero, i restanti 10 bit vengono mandati alla porta
indirizzi di ogni modulo da un 1K. Con questi 10 bit ogni chip individuerà un byte che andrà in uscita dal
chip. Questi 8 bit che escono, da ciascun modulo, messi insieme formano i 32 bit del dato.
10 bit 00
Una tecnica meno semplice è quella dei Banchi Interlacciati: questa tecnica permette di ridurre il tempo. Consideriamo ad esempio sempre i 4 moduli distinti i quali in un certo tempo in uscita hanno 32 bit (per cui
ogni modulo può essere pensato come un insieme dei banchi multipli di memoria visti in precedenza). Ogni
modulo è di 1 Kbyte, per cui ricevono un indirizzo di 10 bit; dovendo tirare fuori 32 bit (parole di 4 byte) dei
10 bit che ne ricevono i due meno significativi sono uguali a zero.
L’indirizzo che arriva all’intera memoria è un’indirizzo di 12 bit, di cui i due meno significativi sono uguali a
zero; i 10 bit rimanenti, a loro volto sono suddivisi in 2 bit meno significativi e 8 bit più significativi.
La word non sarà suddivisa nei vari moduli, ma sarà messa per intera in un modulo. Per cui ogni modulo
conterrà word intere, con questa logica:
MODULO 1 MODULO 2 MODULO 3 MODULO 4
Ind. 0 WORD 0 WORD 1 WORD 2 WORD 3
Ind. 1 WORD 4 WORD 5 WORD 6 WORD 7
Ind. 2 WORD 8 WORD 9 WORD 10 WORD 11
Per cui in ingresso ad ogni modulo si hanno gli 8 bit più significativi dei 12 più 2 bit uguali a zero.
4 Kbyte
1Kbyte
1Kbyte
1Kbyte
1Kbyte
32 bit
8 bit 8 bit 8 bit 8 bit
12 bit
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 80
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
8 bit 00
Poi i 32 bit uscenti da ogni singolo modulo vanno in un MUX che userà i 2 bit meno significativi dei 12 come
selettore per decidere quale indirizzo da 32 bit deve passare.
I 10 bit in ingresso ai moduli andranno a cercare la parola richiesta, la quale andrà poi in ingresso al MUX
per la selezione: ad esempio se i 10 bit richiedono la word che si trova all’indirizzo 2, i moduli daranno in
uscita rispettivamente:
MODULO 1 word 8;
MODULO 2 word 9;
MODULO 3 word 10;
MODULO 4 word 11;
Queste word andranno in ingresso al MUX che ne selezionerà una grazie ai 2 bit di selezione;
la figura che riassume la tecnica dei moduli interlacciati è la seguente.
8 bit 2 bit 00
Con questa tecnica è vero che per il prelievo della prima word si impiegherà più tempo, dovuto al selettore
(T + ts), ma nel momento in cui si va a chiedere la seconda word, questa sarà subito pronta, infatti il tempo
di attesa sarà solo quello del selettore (ts). Così via per le altre word.
Questa tecnica funziona sicuramente se applicata alla memoria centrale, poiché la cache chiede alla
memoria centrale blocchi di word consecutive, mentre non si applica alla memoria cache perché la CPU
chiede solo word, per cui si vuole realizzare una tecnica più veloce.
4 Kbyte
1Kbyte
1Kbyte
1Kbyte
1Kbyte
32 bit 32 bit 32 bit 32 bit
32 bit
12 bit
8 bit 00
8 bit 00
8 bit 00
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 81
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ORGANIZZAZIONE DELLE MEMORIE A SEMICONDUTTORE Le memorie a semiconduttore sono costituite da celle organizzate in righe e colonne che realizzano una
geometria quadrata; viene effettuata questa scelta seguendo due considerazioni:
1. La prima considerazione da fare è di tipo strutturale: è chiaro che un dispositivo costituito da materiale
semiconduttore ha una fragilità maggiore rispetto ad un altro materiale, per cui la forma quadrata
rende difficoltosa la rottura.
2. La seconda considerazione, che è il vero motivo per cui si preferisce una geometria quadrata, è
prettamente riferita al modo in cui la memoria viene indirizzata: nel momento in cui si forniscono a
questo dispositivo dei bit che devono essere codificati per individuare qual è la cella interessata, è bene
che questa decodifica avvenga attraverso la specifica delle rige e delle colonne, nel senso che invece di
avere un sistema che riceve, ad esempio per una memoria di un 1 Kbyte, 10 bit di indirizzo e li
decodifica per arrivare ad indirizzare una cella, è meglio che l’operazione di input/output della cella
avvenga attraverso due decodifiche “simultane” ciascuna delle quali prende un certo numero di bit
dell’indirizzo; la combinazione di queste due decodifiche permette l’accesso alla cella.
Essendo le decodifiche simultanee allora questo meccanismo funzionerebbe anche nel caso in cui la
geometria fosse rettagolare; tuttavia se l’operazioni di decodifica non avvengono parallelamente, ma in
serie, prima una e poi l’altra, allora risulta utile utilizzare una geometria quadrata. Questo perché i due
blocchi di decodifica sono identici, ricevono lo stesso numero di bit, per cui è immediato pensare di
utilizzarne solamente uno il quale prima riceve un numero di bit per individuare la riga e poi riceve i restanti
bit per individuare la colonna; allora la memoria sarà costituita da un decodificatore che riceve in un primo
istante, ad esempio di un indirizzo di 10 bit, solo 5 bit i quali verranno decodificati per individuare la riga. In
un secondo istante riceverà i restanti 5 bit i quali verranno decodificati per individuare la colonna.
La riga individuata, viene mandata su un buffer di riga; su questo buffer andrà ad operare il risultato della
decodifica per individuare la colonna, e quindi infine si accede alla cella interessata.
Sembrerebbe, utilizzando questo metodo, di rendere la memoria lenta e quindi di avere una perdita di
prestazioni, invece, non solo si risparmia sul decodificatore e sul numero di piedini che costituiscono la
memoria, ma anche sui tempi di accesso ai dati; i dati immediatamente successivi non richiederano la
ricodifica della riga, la quale è già presente sul buffer, ma solo la decodifica della colonna. Per cui solo il
primo dato farebbe risultare lento questo tipo di organizzazione.
In questa figura è riportata una tipica
struttura a matrice quadrata (8x8) di una
memoria ad accesso casuale (RAM).
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 82
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZI DI RIEPILOGO ESERCIZIO 1 Dimensionare i campi (etichetta, set, spiazzamento) dell’indirizzo a una memori di 4 MByte qualora essa sia
associata ad una cache da 256 KB con parole di 4 Byte e blocchi da 16 Byte nel caso di indirizzamento
set-associativo (set di 8 blocchi).
Per indirizzare una memoria di 4 MB sono sufficienti 22 bit, da suddividere in etichetta (parte più
significativa), set, spiazzamento (parte meno significativa). Il campo spiazzamento, per poter indirizzare uno
fra 16 byte deve richiedere 4 bit, di cui gli ultimi 2 impostati a "00", in quanto le parole indirizzate sono di 4
byte. Essendo il numero dei set pari a 256 𝐾𝐵
8∗16𝐵= 211, 11 bit saranno necessari al campo set per selezionare
in maniera diretta il set di interesse. Quindi, per differenza, i 7 (= 22 − 11 − 4) bit più significativi
costituiranno il campo etichetta.
INDIRIZZO (22 bit)
ETICHETTA SET SPIAZZAMENTO
xxx xxxx yyy yyyy yyyy zz00
(x, y, z indicano dei bit di valore non specificato).
ESERCIZIO 2 Dato uno spazio di indirizzi di 4 GB specificare i campi e le etichette che si strutturano per l’uso di cache nei
seguenti casi:
1. cache set associativa a 4 set da 16 blocchi, ciascun blocco comprendente 64 words
2. cache ad indirizzamento diretto con 128 blocchi da 32 words
3. cache completamente associativa di 16 MB con 256 blocchi.
Il processore invia un indirizzo pensando di avere una memoria di 4 GB per cui l’indirizzo richiede 32 bit per
indirizzare una word (4 Byte).
Cache set associativa a 4 set da 16 blocchi con ciascun blocco da 64 words per cui la cache sarà così
costituita:
SET 0 SET 1 SET 2 SET 3
Il campo indirizzo, dovendo puntare all'interno di un blocco ad una fra 64 words, utilizzerà 8 bit (di cui gli
ultimi due pari a 0).
Essendo 4 i set, 2 bit saranno nel campo per indirizzare il set, e i rimanenti 32 − 8 − 2 = 22 bit più
significativi comporranno l'etichetta.
(x, y, z indicano dei bit di valore non specificato).
INDIRIZZO (32 bit)
ETICHETTA SET SPIAZZAMENTO
xx xxxx xxxx xxxx xxxx xxxx yy zzzz zz00
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 83
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Cache ad indirizzamento diretto con 128 blocchi da 32 words;
numero di blocchi in memoria = 4 𝐺𝐵
32∗4 𝑏𝑦𝑡𝑒 = 225;
numero di bit necessari per indirizzare un blocco in memoria = 25 bit, di cui la parte meno significativa di
𝑙𝑜𝑔2(128) = 7 bit sarà utilizzata per puntare al blocco in cache e i rimanenti 25 − 7 = 18 bit di etichetta.
(x, y, z indicano dei bit di valore non specificato).
Cache completamente associativa di 16 MB con 256 blocchi
Se la cache è completamente associativa allora il blocco può essere inserito in una qualsiasi posizione della
cache; per questo avrà bisogno, per l’etichetta, dell’intero indirizzo del blocco, a meno degli N bit meno
significativi utili a puntare alla specifica parola all'interno del blocco. Nella fattispecie, si ha:
numero di byte di un blocco = 16 𝑀𝐵
256 = 216 byte
Da cui:
N = 16 bit (di cui i 2 meno significativi pari a "00" per puntar a parole di 4 byte.
(x, y, z indicano dei bit di valore non specificato).
INDIRIZZO (32 bit)
ETICHETTA LINEA SPIAZZAMENTO
xx xxxx xxxx xxxx xxxx yyy yyyy zzz zz00
INDIRIZZO (32 bit)
ETICHETTA SPIAZZAMENTO
xxxx xxxx xxxx xxxx zzzz zzzz zzzz zz00
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 84
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
PARTE TERZA
PARTE TERZA
PROCESSORE SCALARE
ARCHITETTURA FLOATING POINT
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 85
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
PROCESSORE FLOATING POINT Vediamo ora come è possibile estendere la pipeline MIPS per gestire operazioni con dati floating point.
Le fasi di IF, ID, MEM e di WB sono analoghe a quelle per gestire dati interi; i gruppi di registri saranno
diversi da quelli interi, ma comunque elettronicamente identici.
Ciò che veramente cambia è quello che avviene nella fase EX; mentre nell’aritmetica intera si ha l’ALU che
in un tempo più o meno simile effettua una qualsiasi operazione, nell’aritmetica in virgola mobile questo
non è più vero, infatti le stesse operazioni con dati floating point richiedono tempi abbastanza diversi di
esecuzione. Ad esempio si pensi alle operazioni da effettuare per una addizione di due numeri floating
point:
Confronto degli esponenti;
Shift della mantissa del numero che ha esponente minore di un numero di posti pari alla differenza
degli esponenti;
Somma delle due mantisse;
Aggiornamento dell’esponente a quello maggiore;
Tutto questo, ovviamente, non può essere fatto in un tempo analogo a quello necessario per una somma di
due interi.
Essendo quindi la durata delle operazioni significativamente diversa, si hanno di fronte due scelte: una
scelta può essere quella di ridurre la frequenza del clock del sistema andando a dilatare il tempo di una fase
rendendolo pari a quella della fase più lenta, in questo modo il processore eseguirà, in pipeline, le sue
operazioni sempre in 5 fasi ma con tempi molto più lunghi, però comunque ogni fase sarà sempre in
contemporanea ad altre e soprattutto sempre in ordine.
Alternativamente per eseguire operazioni con dati floating point è possibile pensare di far durare la fase EX
non un colpo di clock sufficientemente ampio, ma un numero di colpi di clock quant’è la durata del clock
che si adatta meglio per misurare la singola fase all’interno del processore. In questo modo le istruzioni
avranno fasi che durano il minimo indispensabile; nonostante questa tecnica possa sembrare più
vantaggiosa è possibile avere il caso in cui un’istruzione, che potrebbe durare molto più dei soliti cinque
colpi di clock, ad esempio una divisone floating point che ha la fase EX lunga circa venti colpi di clock, e
quindi la fase EX verrebbe dilatata, e se successivamente quando questa è ancora in esecuzione dovesse
entrare nella pipeline un’altra istruzione che utilizza meno colpi di clock, questa terminerebbe prima. Per
cui si ha quello che viene definita TERMINAZIONE DELLE ISTRUZIONI FUORI ORDINE, cioè un’istruzione
successiva ad un’altra termina prima.
Finché l’istruzione successiva lavora con numeri interi non ci sono problemi, questo perché l’istruzione
floating point utilizza dati che si trovano nei registri dedicati ai dati floating point, mentre l’istruzione intera
utilizza dati che si trovano nei registri dedicati ai dati interi.
Però se l’istruzione successiva, operante anch’essa con dati floating point termina prima, ad esempio è una
somma, potrebbero causarsi problemi seri; per cui è molto facile il verificarsi dei tre azzardi di dato: RAW,
WAR, WAW. Per far fronte a questi problemi la control unit risulterà molto più complessa, poiché dovrà
monitorare attentamente le unità di calcolo che, per una scelta appropriata, non sono tutte assemblate in
un unico blocco. Questa scelta è alla base per evitare il congelamento dell’unità di calcolo da parte di quelle
istruzioni che richiedono un fase EX molto ampia.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 86
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Di seguito è riportata una figura che riassume la logica delle unità di calcolo separata, con i tre blocchi
aggiuntivi per le operazioni floating point.
È evidente che se un’istruzione, come ad esempio una divisione, occupa per molto tempo il divisore, una
possibile istruzione successiva che richiede anch’essa il divisore andrà in stallo finché l’istruzione
precedente non avrà rilasciato l’unità di elaborazione. Per cui è possibile pensare di organizzare in pipeline
anche le varie unità di calcolo, in maniera tale da poter far ricevere altri dati, non quando l’istruzione
precedente finisce e libera l’unità ma, bensì, quando libera la parte iniziale dell’unità.
La seguente figura riassume la logica della pipeline applicata alle unità di calcolo.
Per cui il processore nella fase EX è pensato in maniera diversa.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 87
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Qui accanto è riportata una figura in cui si
vede come le unità di calcolo, non pipeline,
interagiscono con il banco dei registri.
È presente uno Scoreboard il quale è un
meccanismo logico che regola l’accesso ai
registri, verificando che non vi siano conflitti
precedentemente citati.
La presenza di un ulteriore moltiplicatore è
giustificata dal fatto che statisticamente da
un punto di vista della prestazioni non è
efficiente aspettare sette colpi di clock tra
una moltiplicazione ed un’altra. Per cui ad
esempio non è conveniente aggiungere un
sommatore in più.
È immediato pensare allora di aggiungere un
divisore in più a questa struttura, visto che
un’operazione di divisione porta via circa 24
colpi di clock; in realtà questo non è stato fatto sia perché statisticamente le divisioni sono operazioni meno
frequenti rispetto alle moltiplicazioni e sia perché un divisore, dal punto di vista hardware, è notevolmente
più complesso.
Di seguito è riportata la tabella con un riepilogo di alcune le istruzioni che costituiscono il sottoinsieme di
istruzioni di MIPS64®.
Tipo di istruzione/codice
operativo Significato dell’istruzione
Virgola mobile:
operazioni in virgola
mobile in formato SP e DP
ADD.D, ADD.S, ADD.PS Addiziona numeri in DP, in SP e coppie di numeri in SP
SUB.D, SUB.S, SUB.PS Sottrai numeri in DP, in SP e coppie di numeri in SP
MUL.D, MUL.S, MUL.PS Moltiplica numeri in DP, in SP e coppie di numeri in SP
MADD.D, MADD.S, MADD.PS Moltiplica e addiziona numeri in DP, in SP e coppie di numeri in SP
DIV.D, DIV.S, DIV.PS Dividi numeri in DP, in SP e coppie di numeri in SP
CVT._._
Istruzioni di conversione: CVT.x.y converte dal tipo x al tipo y, che
possono essere L (interi a 64 bit), W( interi a 32 bit), D(DP) o S(SP).
Entrambi gli operandi sono registri in virgola mobile.
C.__.D, C.__.S Confronti tra DP e SP; al posto di __ ci può essere: LT; GT, LE, GE, EQ,
NE; imposta il bit opportuno nel registro di stato per la virgola mobile
MFC1, MTC1 Copia da 32 bit in/da registri in virgola mobile da/in registri interi
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 88
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
SCHEDULING DELLE ISTRUZIONI FLOATING POINT Le unità di calcolo floating point hanno una latenza che non è simile indipendentemente dalle operazioni; la
differenza, in termini di colpi di clock, fra una operazione ad aritmetica intera e una in floating point
comincia ad essere significativa. Una scelta semplice sarebbe quella di dimensionare il clock in base
all’operazione che richiede più tempo, facendo sì che dilatando la latenza sia possibile effettuare tutte le
operazioni; però questo determina uno spreco di tempo soprattutto nei casi in cui un programma fa uso
solo ed esclusivamente dell’unità in aritmetica intera, poiché queste operazioni dovranno durare quanto la
più lunga operazione in floating point. Allora non si dilata il clock ma si garantisce all’unità floating point un
certo numero di colpi di clock per le operazioni da effettuare, consentendo di eseguire velocemente le
istruzioni che non fanno uso delle unità floating point.
Il problema che si viene a creare è che questi tempi portano inevitabilmente a degli stalli e conflitti
precedentemente analizzati; ad esempio una operazione di divisione in aritmetica floating point seguita da
una operazione di load, le quali utilizzano uno stesso registro destinazione, terminerebbe dopo
quest’ultima, generando evidentemente un conflitto di tipo WAW.
DDIV.D F4 … …
LOAD F4 … …
Per cui queste tipo di problematiche portano a realizzare unità di calcolo più sofisticate in modo tale da
diminuire il tempo sprecato dovuto alla dilatazione del clock.
Si utilizza l'algoritmo di Tomasulo, algoritmo sviluppato dal ricercatore dell'IBM Robert Tomasulo per
permettere l'esecuzione fuori ordine delle istruzioni. La sua prima implementazione si è avuta nell'unità in
virgola mobile del IBM 360/91. Questo algoritmo si differenzia dallo scoreboarding per l'utilizzo della
rinominazione dei registri. Mentre lo scoreboarding risolve le Write-after-Write (WAW) e le Write-after-
Read (WAR) con gli stalli, l'algoritmo di Tomasulo permette l'esecuzione di altre istruzioni. Inoltre
l'algoritmo di Tomasulo prevede un bus comune per fornire i valori calcolati a tutte le reservation station.
L'algoritmo migliora l'esecuzione parallela delle istruzioni e fornisce prestazioni migliori dello
scoreboarding.
Lo scheduling delle istruzioni dovrà prevedere alcune variazioni:
1. FASE DI DECODIFICA: bisogna fare attenzione affinché non vi siano conflitti di dato effettivi, per cui
la fase di decodifica viene scissa in due stadi ben distinti:
1. ISSUE: fase in cui l’istruzione viene decodificata controllando che non vi
siano azzardi strutturali, etichettata come istruzione floating point e
inserita in una coda d’istruzioni floating point, una coda flessibile la quale
permette di non stallare in caso di conflitti di struttura, in cui le unità di
calcolo sono occupate; le istruzioni possono essere anticipate rispetto ad
altre se hanno la relativa unità di calcolo disponibile.
2. READ OPERANDI: fase che legge gli operandi, dopo aver verificato che non
vi siano conflitti di dato, in maniera tale che gli operandi siano messi in
ingresso alle unità senza generare conflitti.
2. FASE DI ESECUZIONE: esecuzione delle istruzioni in base allo scheduling previsto dall’algoritmo di
Tomasulo.
3. SCRITTURA DEI RISULTATI: i risultati, attraversi un bus comune, vengono scritti nel banco dei
registri e in quelle unità di calcolo che eventualmente aspettano un risultato per svolgere la propria
operazione.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 89
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ALGORITMO DI TOMASULO Questo algoritmo si basa su dei buffer, sempre interni al processore, chiamati STAZIONI DI PRENOTAZIONE.
Questi buffer, presenti in ingresso per ogni elemento floating point del processore, ricevono gli operandi,
quando disponibili, dal banco dei registri floating point (FP Registers) (un po’ come i registri A, B e Imm
presenti nel latch ID/EX per il processore intero). Questi dati sono passati alle stazioni di prenotazione solo
quando il secondo stadio della fase di decode ha accertato l’assenza di eventuali conflitti di dato; viceversa
se il registro non è ancora disponibile, poiché ad esempio è registro destinazione di una operazione ancora
in fase di esecuzione, non potrà andare nella stazione di prenotazione. Quando il registro sarà disponibile
sul Common Data Bus (CDB) per andare nel banco dei registri, questo verrà intercettato per andare
direttamente nella stazione di prenotazione che lo attendeva. Se i dati contenuti nella stazione sono
completi allora questi vanno in entrata all’unità che effettuerà la relativa operazione.
Analogamente si ragiona per le operazioni di lettura/scrittura della memoria; l’esecuzione è gestita in
maniera tale che i registri interessati siano disponibili per evitare conflitti.
CAMPI DELLE STAZIONI DI PRENOTAZIONI
1. BUSY: campo di un bit che indica se la stazione di prenotazione è disponibile.
2. OP: campo che indica l’operazione che dovrà essere eseguita.
3. Vj: campo che indica dove è contenuto il valore del primo registro sorgente.
4. Vk: campo che indica dove è contenuto il valore del secondo registro sorgente.
5. Qj: campo che indica se il primo registro sorgente è disponibile o meno; assume valore zero quando
è disponibile; valori diversi da zero per indicare l’unità che sta utilizzando il registro.
6. Qk: campo identico a Qj ma si riferisce al secondo registro sorgente.
7. A: campo che contiene l’indirizzo sorgente/destinazione per le operazioni di load/store.
È importante sottolineare che le stazioni di prenotazione per le unità di load conterranno solo i campi Busy,
Op ed A, poiché il primo operando dell’istruzione è un registro destinazione, il cui valore verrà
eventualmente prelevato dal CDB; mentre le stazioni di prenotazione per le unità di store conterranno i
campi Busy, Op, Vj, Qj, A, poiché l’operando dell’istruzione è un registro sorgente e va per tanto
monitorato.
BUSY OP Vj Vk Qj Qk
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 90
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Quindi se si ha la possibilità di caricare una certa istruzione perché l’unità di calcolo interessata è
disponibile, allora si procede con la fase di licenziamento. L’istruzione, che è stata prelevata e si trova nella
coda di istruzioni floating point, dopo aver terminato lo stadio ISSUE, va nella stazione di prenotazione
relativa all’unità che dovrà usare per eseguire la sua operazione, cominciando così la fase di esecuzione. Se
uno o entrambi gli operandi non sono disponibili allora bisognerà aspettare che questi lo diventano sul
CDB.
Infine dopo un certo numero di colpi di clock avviene la scrittura dei risultati e la stazione di prenotazione
diventa libera.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 91
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Analizziamo ora un esempio di applicazione dell’algorimto di Tomasulo ad un programma, considerando le seguenti caratteristiche del calcolatore: 1. Numero di colpi di clock per le varie operazioni:
1 colpi di clock per operazioni di somma e sottrazione;
10 colpi di clock per operazioni di moltiplicazione;
40 colpi di clock per operazioni di divisione.
2. Numero di unità di calcolo:
3 unità per operazioni di somma/sottrazione;
2 unità per operazioni di moltiplicazione/divisione.
3. Numero di canali per l’accesso alla memoria:
3 canali;
Il listato del programma è il seguente:
LD F6, 34+, R2
LD F2, 45+, R3
MULTD F0, F2, F4
SUBD F8, F6, F2
DIVD F10, F0, F6
ADDD F6, F8, F2
È facile notare, come questo listato presenti una serie di conflitti di dato.
La situazione iniziale si può schematizzare con la seguente figura, figura che verrà riportata più volte per
spiegare passo – passo lo svolgimento delle istruzioni:
PARTE SUPERIORE
- Sulla sinistra sono riportate le istruzioni, indicando il
valore j e k.
- Al centro vi è una tabella di riepilogo, nella quale sono
monitorate le varie fasi di ciascuna istruzione: indicando
l’istante (colpo di clock) in cui l’istruzione viene
decodificata (Issue), completata (Comp) e istante in cui
avviene la scrittura dei risultati (Result).
- Sulla destra vengono monitorate le risorse per
permettere le operazioni di load: disponibilità (Busy),
indirizzo (Address).
PARTE CENTRALE
- È riportata la situazione delle Stazioni di Prenotazione (Reservation Stations) indicando il tempo per
portare a termine l’operazione (Time), il nome della stazione (Name), e i vari campi che caratterizzano
queste stazioni.
PARTE INFERIORE
- È indicato il colpo di clock effettivo e lo stato dei registri.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 92
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CLOCK 1
Viene decodificata la prima istruzione e
viene occupata la Load1 con l’indirizzo
34+R2. Nel monitor dei registri viene
segnalato che F6 è destinazione di una
operazione di load, per cui non è pronto.
CLOCK 2
Viene decodificata la seconda istruzione e
viene occupata la Load2 con l’indirizzo
45+R3. Nel monitor dei registri viene
segnalato che F2 è destinazione di una
operazione di load, per cui non è pronto.
CLOCK 3
Viene decodifica la terza istruzione e
viene occupata la Stazione Mult1
completando i campi che la
caratterizzano.
Busy: Yes
Op: MULTD
Vj: non è disponibile, bisogna attendere
il termine della load, infatti il campo Qj
segnala che l’operando è destinazione di
una load.
Vk: R(F4)
Qj: Load2
Per cui il moltiplicatore è occupato ma un sorgente non è ancora disponibile. Nel monitor dei registri viene
segnalato che F0 è destinazione di una operazione svolta da un moltiplicatore, per cui non è pronto.
Contemporaneamente è terminata la load della prima istruzione: attenzione è terminata l’accesso in
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 93
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
memoria, ma non sono ancora disponibili i risultati, ovvero non è stato effettuato il Write Back. Per cui
viene riportato l’istante 3 in corrispondenza di Comp.
CLOCK 4
Viene decodifica la quarta istruzione e
viene occupata la Stazione Add1
completando i campi che la
caratterizzano.
Busy: Yes
Op: SUBD
Vj: M(A1)
Vk: non è disponibile, bisogna
attendere il termine della load, infatti il
campo Qk segnala che l’operando è
destinazione di una load.
Qk: Load2
Per cui il sommatore è occupato ma un sorgente non è ancora disponibile. Nel monitor dei registri viene
segnalato che F8 è destinazione di una operazione svolta da un sommatore, per cui non è pronto.
Contemporaneamente è terminata la load della seconda istruzione: identico discorso del caso precedente;
per cui viene riportato l’istante 4 in corrispondenza di Comp.
Contemporaneamente sono disponibili i risultati della prima load; per cui viene riportato l’istante 4 in
corrispondenza di Result e nel monitor dei registri viene segnalato che F6 è disponibile in M(A1) per cui è
pronto.
CLOCK 5
Viene decodifica la quinta istruzione e
viene occupata la Stazione Mult2
completando i campi che la
caratterizzano.
Busy: Yes
Op: DIVD
Vj: non è disponibile, bisogna attendere
il termine della operazione svolta dal
moltiplicatore, infatti il campo Qj
segnala che l’operando è destinazione di
una operazione svolta da un
moltiplicatore.
Vk: M(A1)
Qj: Mult1
Per cui il moltiplicatore è occupato ma un sorgente non è ancora disponibile. Nel monitor dei registri viene
segnalato che F10 è destinazione di una operazione svolta da un moltiplicatore, per cui non è pronto.
Contemporaneamente sono disonibili i risultati della seconda load; per cui viene riportato l’istante 5 in
corrispondenza di Result e nel monitor dei registri viene segnalato che F2 è disponibile in M(A2) per cui è
pronto.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 94
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Tutte le stazioni (Add1 & Mult1) che erano in attesa di usare F2 possono mandare in ingresso alle rispettive
unità di calcolo i sorgenti per effettuare l’operazione indicata in Op. Le operazioni di calcolo potranno
cominciare è i rispettivi colpi di clock mancanti alla conclusione sono riportati in corrispondenza del campo
Time.
CLOCK 6
Viene decodifica la sesta istruzione e
viene occupata la Stazione Add2
completando i campi che la
caratterizzano.
Busy: Yes
Op: ADDD
Vj: non è disponibile, bisogna attendere
il termine della operazione svolta dal
sommatore, infatti il campo Qj segnala
che l’operando è destinazione di una
operazione svolta da un sommatore.
Vk: M(A2)
Qj: Add1
Per cui il sommatore è occupato ma un sorgente non è ancora disponibile. Nel monitor dei registri viene
segnalato che F6 è destinazione di una operazione svolta da un sommatore, per cui non è pronto.
Vengono decrementati i valori presenti in corrispondenza del campo Timer.
CLOCK 7
Termina l’istruzione SUBD; i risultati
non sono ancora disponibili, per cui
viene riportato l’istante 7 in
corrispondenza di Comp.
Vengono decrementati i valori presenti
in corrispondenza del campo Timer.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 95
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CLOCK 8
Sono disponibili i risultati della SUBD;
per cui viene riportato l’istante 8 in
corrispondenza di Result e nel monitor
dei registri viene segnalato che F8 è
disponibile in M-M per cui è pronto.
Viene decrementato il valore presente
in corrispondenza del campo Timer
della Mult1.
Tutte le stazioni (Add2) che erano in
attesa di usare F8 possono mandare in
ingresso alle rispettive unità di calcolo i
sorgenti per effettuare l’operazione
indicata in Op. Le operazioni di calcolo potranno cominciare è i rispettivi colpi di clock mancanti alla
conclusione sono riportati in corrispondenza del campo Time.
CLOCK 9
La situazione resta invariata.
Vengono decrementati i valori presenti
in corrispondenza del campo Timer.
CLOCK 10
Termina l’istruzione ADDD; i risultati
non sono ancora disponibili, per cui
viene riportato l’istante 10 in
corrispondenza di Comp.
Vengono decrementati i valori presenti
in corrispondenza del campo Timer.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 96
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CLOCK 11
Sono disponibili i risultati della ADDD;
per cui viene riportato l’istante 11 in
corrispondenza di Result e nel monitor
dei registri viene segnalato che F6 è
disponibile in M-M+M per cui è pronto.
Viene decrementato il valore presente
in corrispondenza del campo Timer
della Mult1.
CLOCK 12 – 13 – 14 La situazione resta invariata; procede l’operazione svolta da Mult1. Vengono decrementati i valori presenti
in corrispondenza del campo Timer.
CLOCK 15
Termina l’istruzione MULTD; i risultati
non sono ancora disponibili, per cui
viene riportato l’istante 15 in
corrispondenza di Comp.
CLOCK 16 Sono disponibili i risultati della MULTD;
per cui viene riportato l’istante 16 in
corrispondenza di Result e nel monitor
dei registri viene segnalato che F0 è
disponibile in M*F4 per cui è pronto.
Tutte le stazioni (Mult2) che erano in
attesa di usare F0 possono mandare in
ingresso alle rispettive unità di calcolo i
sorgenti per effettuare l’operazione
indicata in Op. Le operazioni di calcolo
potranno cominciare è i rispettivi colpi
di clock mancanti alla conclusione sono
riportati in corrispondenza del campo Time.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 97
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CLOCK 17 ÷ 55 La situazione resta invariata; procede l’operazione svolta da Mult2. Vengono decrementati i valori presenti
in corrispondenza del campo Timer.
CLOCK 56 Termina l’istruzione DIVD; i risultati non sono ancora disponibili, per cui viene riportato l’istante 56 in corrispondenza di Comp.
CLOCK 57 Sono disponibili i risultati della DIVD; per cui viene riportato l’istante 57 in corrispondenza di Result e nel monitor dei registri viene segnalato che F10 è disponibile in Result per cui è pronto.
Questo programma termina dopo 57 colpi di clock. Si può notare come il licenziamento avviene in maniera
ordinata; l’esecuzione e il termine delle istruzioni è del tutto imprevedibile, ossia è FUORIORDINE dal punto
di vista temporale, ma comunque in ordine dal punto di vista logico.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 98
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Per concludere si possono quindi mettere in evidenza i vantaggi e gli svantaggi derivanti dall’uso di questo
algoritmo;
VANTAGGI 1. Eliminazione degli stalli dovuti agli azzardi di tipo WAW e WAR;
2. Se più istruzioni attendono uno stesso risultato e per esempio l’istruzione ha disponibile l’altro
operando, queste istruzioni possono accedere simultaneamente sul CDB per prelevare il risultato
senza attendere la scrittura nel registro;
SVANTAGGI
1. Maggiore complessità;
2. Problema legato alle memorie associative, ossia quelle memorie che vengono utilizzate in funzione
del contenuto delle memorie stesse, cioè si accede alla memoria prelevando i dati fornendo alla
memoria stessa informazioni sui dati e non sui loro indirizzi; queste memorie sono richieste per
interfacciare le stazioni di prenotazione con il CDB;
3. Accesso multiplo al CDB, poiché esso deve servire più unità contemporaneamente, per cui questo
limita le performance;
4. La gestione delle istruzioni fuoriordine complica la gestione degli interrupt.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 99
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
PARTE QUARTA
PARTE QUARTA
ALTRI TIPI DI PROCESSORE
PROCESSORI VLIW
PROCESSORI SUPERSCALARI
PROCESSORI VETTORIALI
MULTICORE
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 100
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
PROCESSORI VLIW
I processori VLIW, acronimo di Very Long Istruction Word, permettono di accedere alla memoria istruzioni
prelevando più istruzioni in un solo colpo di clock; se queste istruzioni usano unità di calcolo distinte, allora
è possibile farle partire contemporaneamente a gruppi. Ovviamente questa logica richiede una memoria
tale da poter conferire in un colpo di clock un’istruzione lunga per esempio 128 bit (32 𝑏𝑖𝑡 𝑥 4 𝑖𝑠𝑡𝑟𝑢𝑧𝑖𝑜𝑛𝑖).
Il principale vantaggio è che un istruzione così grande va a codificare istruzioni diverse, le quali richiedono
unità diverse; l’istruzione VLIW è scompattata in tanti campi quanti sono le unità di calcolo del processore:
per cui l’istruzione VLIW codifica un certo numero d’istruzioni che prevedono l’uso di unità funzionali
distinte (è chiaro che non vi è nessun vantaggio nel prelevare più istruzioni che usano la stessa unità di
calcolo).
Quindi, se l’istruzione VLIW è da 128 bit il compilatore codifica un’istruzione molto lunga che al suo interno
è spacchettata in 4 campi da 32 bit, ciascuno dei quali contiene un’istruzione particolare.
ISTRUZIONE VLIW DA 128 bit:
32 bit 32 bit 32 bit 32 bit
In ogni campo vi sarà un’istruzione da 32 bit associata ad una specifica unità di calcolo; il compilatore si
preoccupa di scrivere nei campi opportuni le istruzioni.
Se in un programma non ci sono istruzioni che fanno uso di una unità funzionale, nel relativo campo verrà
posta la dicitura NO-OP.
Quindi teoricamente con una istruzione VLIW si può avere l’avvio simultaneo di N istruzioni scalari, dove N
è il numero di unità presenti; però se il compilatore non riesce a gestire in maniera efficiente questa logica,
sia per mancanza d’istruzioni che usano unità funzionali particolari e sia perché ci sono troppe istruzioni che
usano una stessa unità, allora questo processore comincia a perdere prestazioni. Il compilatore per cercare
di gestire efficientemente il tutto usa tecniche particolari quali, ad esempio, la tecnica dello srotolamento
del loop.
Si consideri il seguente esempio:
Il processore VLIW possiede le seguenti caratteristiche:
2 unità per l’accesso a memoria;
2 unità per operazioni FP;
1 unità per operazioni intere e branch;
Memoria con banda passante da 160 bit.
Per cui essendo 5 le unità funzionali, e la banda passante da 160 bit l’istruzione VLIW sarà costituita da 5
campi, ciascuno dei quali di 32 bit:
32 bit 32 bit 32 bit 32 bit 32 bit
UNITA’ 1 UNITA’ 2 UNITA’ 3 UNITA’ 4
UNITA’ ACC. MEM.
1
UNITA’ FP 1
UNITA’ FP 2
UNITA’ INTERA/BRANCH
UNITA’ ACC. MEM.
2
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 101
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Il listato del programma già ottimizzato, con la tecnica dello srotolamento del loop eseguita per sette volte,
è il seguente:
1 LOOP: L.D F0,0(R1)
2 L.D F6,-8(R1)
3 L.D F10,-16(R1)
4 L.D F14,-24(R1)
5 L.D F18,-32(R1)
6 L.D F22,-40(R1)
7 L.D F26,-48(R1)
8 ADD.D F4,F0,F2
9 ADD.D F8,F6,F2
10 ADD.D F12,F10,F2
11 ADD.D F16,F14,F2
12 ADD.D F20,F18,F2
13 ADD.D F24,F22,F2
14 ADD.D F28,F26,F2
15 S.D 0(R1),F4
16 S.D -8(R1),F8
17 S.D -16(R1),F12
18 S.D -24(R1),F16
19 S.D -32(R1),F20
20 S.D -40(R1),F24
21 DSUBUI R1,R1,#56
22 BNEZ R1,LOOP
23 S.D 8(R1),F28 ; 8-56 = -48 per cui S.D -48(R1),F28
Brevemente questo programma somma gli elementi di un vettore, memorizzato a partire da R1, con una
costante memorizzata in F2.
Riempendo i campi con logica, per ogni singolo colpo di clock, dell’istruzione VLIW si ottiene la seguente
situazione:
Si nota come alcune VLIW hanno due o tre campi NO – OP.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 102
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
È possibile ottimizzare ancora di più il codice spostando la BNEZ al colpo di clock 8, evitando così lo stallo;
questa ottimizzazione richiede anche la modifica logica di altre istruzioni.
Nonostante in questo caso un’istruzione VLIW permeterebbe di eseguire 5 istruzioni
contemporaneamente, si ha solo una media di 2,5 istruzioni per colpo di clock; per cui questo processore
starebbe lavorando con una efficienza del 50%, percentuale che dipende quindi dal programma e dal
compilatore.
Con un processore scalare che svolge le 23 istruzioni in pipeline, si sarebbero ottenuti sette risultati in 23
colpi di clock, oppure 3.3 colpi di clock per ogni iterazione; mentre con il processore VLIW che esegue le 23
istruzioni in 9 colpi di clock, si ottengono sette risultati in 9 colpi di clock, oppure 1.3 colpi di clock per ogni
iterazione, quindi vi è un’accelerazione di circa il 60%.
Concludendo, questo tipo di processore richiede:
Una Control Unit non molto complessa rispetto a quella presente nei processori scalari per gestire i
floating point: è il compilatore che organizza le istruzioni;
Un compilatore diverso, capace di gestire questo tipo di assemblamento delle istruzioni;
Memoria con una banda maggiore, per permettere di prelevare in un unico colpo di clock
un’istruzione costiuita da un numero grande di bit;
Incremento del codice, dovuto allo strotolamento.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 103
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CC 1 CC 2 CC 3 CC 4 CC 5
PROCESSORI SUPERSCALARI
Il processore SUPERSCALARE sfrutta, come il VLIW, il fatto che le varie unità funzionali del processore sono
ridondanti se pensate a livello della singola istruzione; nei processori scalari se un’istruzione sta usando
l’ALU intera non può esserci una istruzione che vada ad occupare ed ad usare l’ALU FP.
Nei processori superscalari questo parallelismo è possibile:
Per cui vi è un potenziamento della memoria che prevede la lettura parallela di due istruzioni, una intera ed
una floating point; quindi queste istruzioni vengono avviate nella pipeline in contemporanea, poiché
ognuna andrà ad utilizzare l’unità di cui necessità.
Nel migliore delle ipotesi questo processore permette l’avvio di due istruzioni in contemporanea.
Il compilatore dovrà preoccuparsi di scrivere il programma in maniera tale che le istruzioni siano in coppia,
una intera e una floating point, per ottenere una pipeline ideale di questo tipo:
Quando vi è la fase di fetch saranno letti dalla memoria 64 bit, due istruzioni, sperando
che i primi 32 siano relativi ad un’istruzione intera e i restanti 32 relativi ad una
istruzione floating point. Dopo il prelievo, il Program Counter dovrà essere
incrementato di 8.
Se la coppia d’istruzioni è dello stesso tipo, allora chiaramente, solo la prima istruzione
verrà processata e l’altra verrà avviata al colpo di clock successivo. Però è possibile
prendere l’istruzione in attesa in coppia con la successiva, sfasando così tutte le
successive coppie; in questo caso il PC dovrà essere incrementato di 4 e non di 8.
Concludendo, questo tipo di processore richiede:
Una Control Unit non molto complessa rispetto a quella presente nei processori scalari per gestire i
floating point: è il compilatore che organizza le istruzioni;
Un compilatore diverso, capace di gestire questo tipo di assemblamento delle istruzioni;
Memoria con una banda maggiore, per permettere di prelevare in un unico colpo di clock due
istruzioni;
MEM. ISTR.
UNITA’ INTERA
UNITA’ FLOATING
POINT
MEM. DATI
Istruzione intera
Istruzione Floating
point
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 104
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
PROCESSORI VETTORIALI
Il processore VETTORIALE nasce dall’idea di codificare con un’istruzione classica una grande mole di lavoro.
Questo è realizzato estendendo il set delle istruzioni con istruzioni vettoriali, le quali hanno come sorgenti e
destinazioni dei vettori.
Nei casi di uso dei vettori, cosa che spesso capita nei programmi, invece di avere dei loop, con una sola
istruzione vettoriale è possibile codificare una determinata operazione (ovviamente nell’ipotesi che i vettori
da trattare abbiano un numero di elementi al massimo pari al numero di elementi che i registri vettoriali
possono contenere).
Per cui in sinstesi le idee alla base dei processori vettoriali sono:
Codifica delle istruzioni per le operazioni vettoriali;
Dotare il processore di unità che operino efficientemente con i vettori, cioè, ad esempio, l’unità di
accesso alla memoria deve saper efficientemente prelevare i vettori dalla memoria (la memoria
riceverà dall’ALU solo l’indirizzo del primo elemento, poi essa stessa dovrà automaticamente
calcolarsi l’indirizzi degli altri elementi);
Registri vettoriali idonei in grado di contenere dei vettori: questi registri hanno una dimensione ben
definita (decisa in fase di progettazione), per cui le dimensioni dei vettori devono rientrare in quelle
dei registri.
Per cui quando si devono svolgere operazioni fra vettori, attraverso una codifica molto compatta, si ha la
possibilità di rendere esplicita una quantità di calcolo abbastanza ampia, che tra l’altro opera su dati che
non creano conflitto fra di loro. Di conseguenza si definiscono operazioni vettoriali tutte quelle operazioni
che non generano conflitti di dato (somma, sottrazione, moltiplicazione, ecc.), mentre operazioni come
media o determinante di una matrice non sono gestite dalla CPU come operazione vettoriale.
È chiaro che accedere a dati vettoriali richiede una unità di memoria dati ottimizzata; i dati vettoriali
devono essere organizzati in una determinata maniera. Il prelievo di un’istruzione vettoriale è uguale al
prelievo di un’istruzione classica, poiché si accede alla memoria istruzioni; mentre il prelievo dalla memoria
dati deve essere ottimizzato.
Una esempio d’istruzione vettoriale è il seguente:
ADDV V1,V2,V3
L’istruzione ADD è seguita dalla lettera V la quale indica che l’istruzione si riferisce ad una operazione
vettoriale. V1,V2,V3 sono registri vettoriali; la CPU avrà necessariamente dei registri vettoriali i quali sono
costituiti da un numero fisso di registri scalari logicamente uniti, identificati con un unico nome. Per cui i
registri vettoriali hanno una ampiezza definita. Bisogna però fare attenzione alle dimensioni da scegliere in
fase di progettazione; aumentando/diminuendo il numero dei registri vettoriali e quindi di conseguenza
diminuendo/aumentando la dimensione del singolo registro aumentano/diminuiscono i bit utili alla
identificazione dei registri all’interno dell’istruzione. Inoltre diminuire la dimensione del singolo registro,
comporterebbe dei problemi quando si devono gestire vettori con dimensioni maggiori rispetto alla
lunghezza dei registri vettoriali, problema che verrà comunque gestito, come vederemo in seguito, con una
scomposizione in tanti più piccoli problemi vettoriali in cui i vettori hanno dimensioni minori.
Analogalmente se si aumenta la lunghezza dei singoli registri è molto probabile che parte del registro
rimanga inutilizzata quando si opera con vettori di dimensioni ridotte. Per cui è chiaro che bisogna trovare
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 105
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
un compromesso; nel caso preso in esame, la CPU VETTORIALE ha i registri vettoriali costituti da 64
elementi.
Di seguito è riportata la tabella di alcune tipiche istruzioni vettoriali.
OPERAZIONI DI LOAD E STORE L’operazione di caricamento in un registro vettoriale da memoria è definita con la seguente sintassi:
LV [reg],[ind]
[reg]: registro in cui si andrà ad ospitare il vettore;
[ind]: indirizzo da cui parte il vettore in memoria;
Dulamente l’operazione di salvataggio in memoria del contenuto di un registro vettoriale è definita con la
seguente sintassi:
SV [ind],[reg]
Per entrambe le operazioni è messo a disposizione un dispositivo simile al noto DMA (Direct Memory
Access), il quale ricevuto l’indirizzo del primo elemento del vettore calcola gli indirizzi dei restanti elementi;
questo dispositivo è interno alla memoria dati.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 106
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Per cui, grazie a questo dispositivo, è possibile avere al termine della fase MEM dell’istruzione LOADV il
primo elemento del vettore nella corrispondente cella del registro destinazione; per ogni colpo di clock
successivo si avrà a disposizione, nella specifica cella del registro destinazione, l’elemento successivo del
vettore.
Quindi è evidente che se la memoria consente una banda passante maggiore che permette, ad esempio, la
lettura di due dati in un solo colpo di clock, al termine della fase MEM saranno disponibili, nelle rispettive
celle del registro vettoriale destinazione, i primi due elementi del vettore.
Sfruttando la disponibilità di alcuni elementi del vettore ancor prima che questo sia completamente
caricato nel registro destinazione, è possibile poter eseguire istruzionI che devono elaborare gli elementi,
come questo esempio:
1cc 2cc 3cc 4cc 5cc 6cc 7cc 8cc 9cc
LOADV V2,… IF ID EX MEM WB
LOADV V3,… IF ID EX MEM WB
ADDV V1,V2,V3 stallo IF ID EX MEM WB
STOREV …,V1 IF ID EX MEM WB
(Considerando idealmente che il sommatore abbia una latenza di 1 cc)
L’istruzione ADDV V1,V2,V3 potrà effettuare la somma degli elementi presenti nelle celle dei registri V2,V3
senza dover attendere l’intero caricamento del vettore. Lo stesso vale per la STOREV …,V1 che può
cominciare a memorizzare in memoria gli elementi disponibili nelle celle di V1.
Attenzione, questo calcolo non viene eseguito in circa 5 colpi di clock; poiché per completare l’intera
operazione bisogna attendere che tutti gli elementi del vettore vengano processati. Per cui il
completamento dell’operazione richiesta avverrà dopo un numero di colpi di clock dipendenti dal numero
di elementi che si devono processare.
Tutto questo è possibile poiché, come descritto precedentemente, le unità di calcolo si basano su logica
pipeline.
L’istruzione LVWS I vantaggi che questa CPU offre sono assicurati se gli elementi sono memorizzati in memoria centrale in
maniera sequenziale; infatti in memoria i vettori sono allocati in locazioni consecutive.
Questo non avviene quando ad esempio si estrae da una matrice un qualsiasi vettore colonna, essendo le
matrici generalmente allocate per righe; per questo caso attraverso un’unica istruzione si risolve il
problema: vi è un numero che dirà al famoso modulo simile al DMA di quanto deve saltare per accedere
all’elemento successivo. L’istruzione in esame è: LVWS (Load Vector With Stride).
I registri VLR e MVLR Supponiamo che il vettore da processare sia costituito da un numero di elementi molto inferiore ai 64 che
la CPU in esame mette a disposizione. Il caricamento del vettore avverrà in un unico registro vettoriale
senza nessun tipo di problema, ma con conseguenti elementi inutilizzati; si nota facilmente che processare
questo vettore significherebbe far lavorare la CPU anche su elementi che non hanno nessun significato. Per
evitare ciò la CPU vettoriale ha un registro particolare chiamato VLR (V ector Length Register): questo
registro contiene un numero che il compilatore va ad impostare, in maniera trasparente al programmatore,
quando deve operare sui registri vettoriali; questo numero equivale alla dimensione del vettore da
processare e al massimo può valere (in questo caso) 64.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 107
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Le varie operazioni sul vettore procederanno fino a quando si raggiungerà un numero di passi pari al
contenuto di VLR.
Il compilatore deve però conoscere a priori la dimensione dei registri vettoriali per poter impostare il valore
di VLR. Questo è possibile attraverso il registro MVLR (Max Vector Length Register): questo registro è
fondamentale per l’architettura vettoriale. Contiene la dimensione massima dei registri vettoriali della CPU;
per cui non è un registro impostato dal compilatore, ma impostato al momento della produzione del
firmware della CPU.
Prestazioni Una CPU vettoriale offre quindi ottime prestazioni, quando si processano dati che eseguono operazioni
vettoriali, giocando sui diversi fattori:
Riduzione drastica del collo di bottiglia provocato dalla memoria istruzioni.
A livello del codice, implicitamente, si eliminano i conflitti di dato.
Una Control Unit più semplice.
L’unico svantaggio è che non sempre si incontrano operazioni vettoriali comuni, ma operazioni che
richiedono una complessità diversa per il loro processo.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 108
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ANALISI REALE DELL’ARCHITETTURA DI UNA CPU VETTORIALE – CRAY-1 (1976) Il primo calcolatore basato su architettura vettoriale fu il CRAY-1
(pesante 5,5 tonnelate!) progettato da Seymour Cray nel 1976.
L’architettura di questo calcolatore prevedeva le unità scalari più una
estensione per operazioni vettoriali; per cui il Cray-1 presentava
alcune caratteristiche in più rispetto a precedenti calcolatori:
- Un’architettura per operazioni di load/store;
- Registri vettoriali;
- Istruzioni vettoriali;
- Un sistema di memoria INTERLEAVED che sostituisce a livello
dati le memorie cache;
SCHEMA LOGICO Di seguito è riportato lo schema logico dell’architettura della CPU vettoriale Cray-1.
Osserviamo alcune sue caratteristiche:
- 8 registri vettoriali da 64 elementi
l’uno [V0÷V7];
- 8 registri scalari di tipo S [S0÷S7];
- 8 registri scalari di tipo A [A0÷A7];
- Buffer da 4 istruzioni;
- 3 unità ad aritmentica floating
point;
- 4 unità ad aritmetica intera;
- 2 unità per le operazioni sugli
indirizzi;
- Registro V.Mask;
- Registro V.Lenght;
Si noti che in questa CPU non è presente il divisore: questo è sostituito dall’unità che effettua il reciproco;
tramite il moltiplicatore verrà eseguita poi l’operazione: 𝑥 ∙1
𝑦
Sono presenti inoltre due registri importanti per il corretto e efficiente funzionamento dell’architettura
vettoriale; questi registri sono:
Registro V.Mask: serve per operazioni condizionate oppure realtive a vettori o matrici sparse, cioè
quelli in cui la maggior parte dei loro dati sono degli zeri. La CPU impostando corretamente questo
registro evita di operare su valori uguali a zero, in modo tale da diventare più efficiente. Per cui nel
set istruzioni sono presenti particolari istruzioni con maschera che operano solo su dati significativi:
ad esempio utili per gestire situazioni di overflow provocati da divisione per zero.
Il registro V.MASK è un registro vettoriale, costituito da MVLR elementi.
Registro V.Lenght: equivale al registro VLR.
Cray-1 (1976)
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 109
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
IDEE ALLA BASE DELLA ORGANIZZAZIONE VETTORIALE REGISTRI:
16 registri scalari;
8 registri vettoriali da 64 elementi
l’uno;
VLR indica da quanti elementi è
costituito il vettore da processare.
OPERAZIONI ARITMETICHE:
Avere a disposizioni tante unità
funzionali per processare
parallelamente ogni elemento del
vettore.
OPERAZIONI LAOD/STORE:
Accesso (load/store) in memoria
tramite gli indici BASE e STRIDE,
permettendo così l’accesso
efficiente a vettori con elementi
non contigui, come ad esempio un
qualsiasi vettore colonna di una matrice memorizzata in memoria per righe.
CODICE VETTORIALE Di seguito è riportato un confronto fra il codice implementato per una cpu scalare e un codice
implementato per la cpu vettoriale. Si noti come risulta molto più breve e semplice utilizzare istruzioni
vettoriali.
L’esempio consiste nell’eseguire una somma fra due vettori.
CODICE SORGENTE, C CODICE CPU SCALARE CODICE CPU VETTORIALE
for (i=0; i<64; i++)
C[i] = A[i] + B[i];
LI R4, 64
loop: L.D F0, 0(R1)
L.D F2, 0(R2)
ADD.D F4, F2, F0
S.D F4, 0(R3)
DADDIU R1, 8
DADDIU R2, 8
DADDIU R3, 8
DSUBIU R4, 1
BNEZ R4, loop
LI VLR, 64
LV V1, R1
LV V2, R2
stallo
ADDV.D V3, V1, V2
SV V3, R3
I vantaggi nell’uso di un set con istruzioni vettoriali sono molteplici:
- Compattezza: poche istruzioni per eseguire diverse operazioni; - Indipendenza implicita dei dati, per cui assenza di conflitti di dati; - Uso delle stesse unità funzionali, per cui non sono necessarie particolari unità di calcolo; - Accesso a registri disgiunti, quindi come avviene per le non vettoriali; - Accesso a blocchi di memoria contigui (stride unitario), oppure saltando (stride noto a priori); - Riduzione drastica del collo di bottiglia con la memoria.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 110
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESECUZIONE ARITMETICA DELLE ISTRUZIONI L’unità funzionale che deve eseguire una certa operazione avrà una latenza, definita in fase di
progettazione, la quale permette di avere il risultato dopo un certo numero di colpi di clock. Organizzandola
in maniera tale che le sue unità logiche siano strutturate in pipeline, è possibile migliorare il throughput
(rendimento, cioè la frequenza con cui l’oggetto è in grado di processare i dati) dell’unità di calcolo.
Sulla base di queste considerazioni è chiaro che è possibile migliorare di molto le
prestazioni della singola unità funzionale e quindi dell’intero sistema; i dati saranno
disponibili molto più velocemente. La possibilità di utilizzare questa tecnica è garantita
perché gli elementi di un vettore sono indipendenti.
La figura affianco mostra come viene effettuato il prodotto fra due registri contenti dati
vettoriali, attraverso un moltiplicatore a 6 stadi di pipeline.
Supponendo una latenza di 6 colpi di clock il primo risultato lo si ottiene appunto dopo 6
cc. Il secondo risultato lo si otterrà al cc 7 e così via.
SISTEMA DI MEMORIZZAZIONE DI DATI VETTORIALI NEI REGISTRI VETTORIALI La CPU del Cray-1 disponeva di una memoria a 16 banchi, il cui schema logico è riportato di seguito:
L’accesso ai blocchi avviene in maniera
molto intuitiva; un sommatore genera
l’indirizzo del blocco operando sulla
base e sullo stride.
ESECUZIONE ISTRUZIONI VETTORIALI Si supponga di effettuare una operazione di somma fra due vettori:
ADDV C,A,B
Si possono distinguere due casi:
1°CASO
Una unità funzionale pipeline a 3 stadi
2°CASO
4 o più unità funzionale pipeline a 3 stadi
Aumenta il parallelismo, provocando un aumento
del throughput del sistema; la latenza della singola
unità rimane invariata. Si noti la disposizione con
cui gli elementi entrano nelle unità.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 111
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
STRUTTURA DELLE UNITA’ VETTORIALI La struttura delle unità si basa sulla
creazione di CORSIE le quali sono
organizzate in maniera tale da
ottimizzare al meglio l’operazione
vettoriale da eseguire. Ogni corsia
presenta due unità funzionali che
operano sui registri organizzati in
maniera logica, per ottenere i risultati
in modo consecutivo e il più
velocemente possibile.
Come già detto questa organizzazione
migliora il throughput del sistema.
Di seguito è riportata una immagine reale della struttura del T0 Vector Microprocessor del 1995; esso è
costituito da 16 unità funzionali.
DIFFERENZA FRA ARCHITETTURA MEMORIA-MEMORIA E ARCHITETTURA A REGISTRI VETTORIALI I sistemi basati su architettura memoria-memoria (VMMA – Vector Memory-Memory Architectures)
operano fondamentalmente considerando i vettori residenti in memoria centrale; quindi il prelievo e la
scrittura avviene direttamente in memoria centrale.
I primi sistemi che si basavano esclusivamente su architettura memoria-memoria sono ad esempio CDC
Star-100 (1973) e il TI ASC (1971); la scelta di questa tecnica era dovuta esclusivamente alla indisponibilità
di spazio fisico.
Per cui il codice di una macchina memoria-memoria è di questo tipo:
ADDV C, A, B ;si usano direttamente gli indirizzi
SUBV D, A, B
Cray-1 fu il primo sistema ad utilizzare registri vettoriali; questo implica necessariamente un codice diverso,
poiché bisogna effettuare le operazioni di load e store.
T0 Vector Microprocessor (1995)
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 112
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
È possibile quindi evidenziare le differenze fra queste due tipologie di macchine vettoriali:
I sistemi VMMA richiedono una banda maggiore di memoria, perché ogni operando deve essere
sempre letto dalla memoria anche se precedentemente utilizzato, problema non presente con
l’utilizzo di registri vettoriali.
Aumento del rischio di dipendenza fra dati nei sistemi VMMA.
I sistemi VMMA incorrono in una maggiore latenza di avvio.
VETTORIZZAZIONE AUTOMATICA DEL CODICE Si osservi adesso come un codice sorgente, per semplicità consideriamo la somma di due vettori, viene
processato da una macchina con istruzioni scalari e da una con istruzioni vettoriali, e quindi i tempi di
esecuzione delle singole iterazioni.
CODICE SORGENTE
for (i=0; i < N; i++)
C[i] = A[i] + B[i];
ISTRUZIONI SCALARI SEQUENZIALI Ipotizzando la
latenza pari a
un colpo di
clock per ogni
singola unità.
ISTRUZIONI VETTORIZZATE
La vettorizzazione permette un parallelismo
maggiore e quindi per lo stesso numero di colpi di
clock una cpu vettoriale riesce a processare più dati.
GESTIONE DI VETTORI CON DIMENSIONE SUPERIORE A MVLR – VECTOR STRIPMINING Vediamo ora come vengono gestiti i casi in cui il vettore da processare è costituito da un numero di
elementi maggiori del valore impostato in Max Vector Length Register.
Questo tipo di problema viene affrontato suddividendo il vettore in un certo numero di sottovettori;
ciascuno di questi sottovettori verrà considerato come un vettore di MVLR elementi o comunque di un
numero minore. Il vettore viene suddiviso quindi in N sottovettori: per rendere il più efficiente possibile il
sistema, N-1 sottovettori avranno la dimensione massima possibile, consentita dai registri vettoriali, quindi
MVLR, mentre un vettore sarà costituito dagli eventuali elementi residui.
È facile capire che se la dimensione del vettore è divisibile per MVLR non vi saranno sottovettori residui e
quindi la gestione si semplifica; se la dimensione del vettore non è divisibile per MVLR, allora bisognerà
gestire al meglio la presenza del vettore residuo.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 113
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Risulta opportuno che il primo sottovettore che deve essere processato sia il sottovettore residuo; in questo
modo al di fuori del loop viene processato il residuo e poi dopo aver modificato VLR si procede con i
restanti vettori.
Questa situazione viene implementata con le seguenti istruzioni:
for (i=0; i<N; i++)
C[i] = A[i]+B[i];
1 ANDI R1, N, 63 # N mod 64
2 MTC1 VLR, R1 # Do remainder
3 loop: LV V1, RA
4 DSLL R2, R1, 3 # Multiply by 8
5 DADDU RA, RA, R2 # Bump pointer
6 LV V2, RB
7 DADDU RB, RB, R2
8 ADDV.D V3, V1, V2
9 SV V3, RC
10 DADDU RC, RC, R2
11 DSUBU N, N, R1 # Subtract elements
12 LI R1, 64
13 MTC1 VLR, R1 # Reset full length
14 BGTZ N, loop # Any more to do?
Analizziamo ora alcune istruzioni, fondamentali per gestire la presenza del vettore Remainder.
ISTRUZIONE 1: il valore del residuo viene calcolato attraverso l’istruzione:
ANDI R1, N, 63
Un residuo di una divisione per un divisore che è potenza di 2, come 64, si fa semplicemente
andando a considerare gli ultimi n bit (2𝑛 ). Per cui essendo 64 = 26 si considerano gli ultimi 6 bit
della dimensione del vettore, per ottenere il resto della divisione.
Per esempio N = 187:
(187)10 = (10111011)2 - Bisogna considerare gli ultimi 6 bit, quindi in AND con 63;
𝐴𝑁𝐷 63 10 = 00111111 2
Per cui risulta: (00111011)2 = (59)10
Quindi se la dimensione del vettore da processare è di 187 elementi, ci sarà un vettore Remainder
da 59 elementi e 191
64≅ 2, quindi 2 vettori da 64 elementi.
ISTRUZIONE 2: l’impostazione di VLR, essendo un registro speciale, avviene tramite un’istruzione
speciale:
MTC1 VLR, R1
ISTRUZIONE 4: shift logico verso sinistra di 3 posti, moltiplicando così per 8 il contenuto di R1, ossia
il valore della dimensione del vettore al momento processato;
DSLL R2, R1, 3
In questo modo in R2 è contenuto il valore della dimensione in memoria del sottovettore che si sta
processando e di conseguenza R2 conterrà il valore del salto da effettuare per accedere al
sottovettore successivo. Le istruzioni 5 – 7 – 10 aggiorneranno i rispettivi indirizzi per accedere al
successivo sottovettore.
ISTRUZIONE 14: controlla se il valore di N è maggiore di zero: BGTZ N, loop
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 114
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
PARALLELISMO DELLE ISTRUZIONI VETTORIALI Si supponga una unità costituita 8 corsie e 32 elementi per ogni registro vettoriale, e si ipotizzi idealmente
che ogni unità abbia una latenza di 1 colpo di clock; è possibile sovrapporre l’esecuzione di più istruzioni
vettoriali in questo modo: (considerando l’esecuzione su un singolo vettore)
Essendo disponibili 8 corsie verranno caricate nel registro vettoriale i primi 8 elementi del vettore; inoltre
essendo le unità pipeline, al colpo di clock successivo (2) si potranno caricare altri 8 elementi e in parallelo
eseguire con il moltiplicatore, come in questo esempio, l’istruzione successiva che processerà i dati caricati
al colpo di clock 1:
Per cui al colpo di clock successivo (3) saranno caricati altri 8 elementi, e in parallelo oltre al moltiplicatore,
si potranno processare, con ad esempio un sommatore, i dati del colpo di clock precedente (2); per cui si
ottiene la seguente situazione:
In questo caso si sta eseguendo in parallelo, load-mul-add;
Essendo i registri costituiti da 32 elementi, e le corsie disponibili sono 8, la prima istruzione di load
terminerà al 4 colpo di clock; per cui al 5 cc l’unità che effettua operazioni di load/store sarà disponibile per
eventuali altre load/store; quindi è possibile in questo modo avere istruzioni parallele: la seguente figura
evidenzia il parallelismo che si ottiene.
In questo modo si completano 6 istruzioni in soli 10 colpi di clock. Ogni istruzione si completa in 4 colpi di
clock. Quindi nei casi in cui si ha il massimo parallelismo, cioè tutte le unità stanno operando, si eseguono
24 operazioni (8 load – 8 mul – 8 add). Per cui sono evidenti i vantaggi che porta questo tipo di soluzione.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 115
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
PENALITA’ DI AVVIO DELLE CPU VETTORIALI Le componenti che incidono sulla penalità di avvio nelle cpu vettoriali sono essenzialmente due:
1. Latenza delle unità funzionali, e quindi il tempo che trascorre per ottenere un risultato;
2. Tempo morto o tempo di recupero, ossia il tempo che trascorre prima che un altro vettore possa
utilizzare l’unità funzionale, se questa è unica e occupata.
Per chiarire il concetto di tempo morto si consideri la seguente figura:
Un’ipotetica unità funzionale è
occupata nel processore da un
certo vettore (e potrà essere
impegnata da un altro vettore solo
quando avrà terminato di
processato il primo vettore);
essendo questa unità organizzata in
pipeline solamente dopo un certo
numero di colpi di clock, pari alla
sua latenza, darà in uscita il primo
risultato e successivamente tutti gli
altri risultati, per ogni colpo di clock
successivo. Essendo questa unità
unica nel sistema, se un secondo
vettore deve essere processato, questo deve attendere che il primo vettore completi l’intera operazione e
che liberi quindi l’unità funzionale. Il tempo che intercorre si definisce tempo morto (Dead Time).
Per cui questo tempo morto dipende da due fattori:
1. La dimensione del vettore.
2. Il numero di unità funzionali presenti e quindi il numero di corsie.
GESTIONE DELLE CONDIZIONI – USO DEL REGISTRO V.MASK – ISTRUZIONI MASCHERATE L’obiettivo è quello di gestire, attraverso la vettorizzazione, situazioni in cui sono presenti condizioni sugli
elementi del vettore.
Consideriamo l’esempio:
for (i=0; i<N; i++)
if (A[i]>0) then
A[i] = B[i];
Si vuole sostituire tutti gli elementi del vettore A che sono maggiori di zero, con gli elementi di B.
Ad ogni elemento del registro vettoriale viene associato, tramite una particolare istruzione, un elemento
del registro V.MASK; gli elementi del registro V.MASK faranno da flag per gli elementi del vettore. Il flag
permette di identificare se quell’elemento è da processare oppure no.
Per fare questo bisogna impostare, come già detto, il registro V.MASK tramite l’istruzione SGTVS:
SGTVS.D V1, F0
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 116
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Questa istruzione confronta gli elementi del vettore V1 con uno scalare e, se la condizione è verificata,
imposta il relativo campo del V.MASK associato al relativo elemento del vettore. Quindi per tutti gli
elementi che verificano la condizione verrà impostato il flag a 1 per indicare che solo quelli saranno
processati successivamente.
Quindi per l’esempio considerato si ha il seguente codice:
CVM # Turn on all elements
LV V1,R1 # Load entire A vector
SGTVS.D V1, F0 # Set bits in mask register where A>0
LV V1, R2 # Load B vector into A under mask
SV R1,V1 # Store A back to memory under mask
Per cui con l’utilizzo delle istruzioni mascherate è possibile ulteriormente ottimizzare l’esecuzione, e quindi
ridurre i tempi; gli elementi verranno processati in questa maniera:
È evidente che la verifica del flag relativo ad ogni elemento deve
essere effettuata a monte dell’unità funzionale, in modo tale da
poter processare solo gli elementi con flag a 1.
L’operazione di mascheramento quindi richiede una fase di
“compressione” dei dati, cioè i soli dati processati vengono
temporaneamente memorizzati in un registro vettoriale,
seguita da un fase di “espansione” in cui i dati vengono
memorizzati nelle relative posizioni del registro destinazione.
Temporary Register
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 117
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
RIDUZIONE A OPERAZIONI SCALARI Ci sono operazioni con vettori che non sono definite operazioni vettoriali, poiché creano dipendenza tra i
dati e quindi conflitti nell’esecuzione.
È possibile ridurre queste operazioni ad operazioni di tipo vettoriale; questa tecnica permette dunque di
risolvere questo tipo di problema.
Consideriamo questa situazione:
sum = 0;
for (i=0; i<N; i++)
sum += A[i]; # Loop-carried dependence on sum
Questo codice somma gli elementi del vettore stesso creando però una dipendenza di dati.
Ridurre questa situazione a operazioni vettoriali significa dividere a metà il vettore e trattarlo come due
vettori distinti, per poter eseguire le operazioni vettoriali possibili.
Quindi si sommano i rispettivi elementi per ottenere un terzo vettore; a sua volta questo vettore viene
diviso a metà per operare ancora sui suoi elementi. Quando il numero degli elementi si riduce, diventa
molto piccolo o dispari, allora si trattano gli elementi del vettore come degli scalari.
Schematicamente la situazione è la seguente:
4
12
44
10
𝑉𝐿𝑅
2
48
22
48 𝑉𝐿𝑅
2
4
12
44
10
+ = +
22
= 70
VETTOREA
VETTORE A1
VETTORE A2
VETTORE B SCALARE A
SCALARE B
sum
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 118
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO Ottimizzare un loop che calcoli: Y=aX+bY (X e Y vettori, a e b scalari) per una CPU VETTORIALE, cercando di
ridurre al minimo il numero di stalli.
Essendo la dimensione dei registri vettoriali da 64 elementi, ogni vettore sarà spezzettato in un vettore
Remainder da 32 elementi e in un vettore da 64 elementi.
La situazione si può riassumere con la seguente figura:
Supponiamo:
R1, R2: registri contenenti gli indirizzi dei due vettori, A e B;
R3: registro contenente la dimensione (96) dei vettori;
R29, R30: registri contenenti rispettivamente gli scalari “a” e “b”.
Il codice non ottimizzato è il seguente:
1 ANDI R4, R3, 63
2 MTC1 VLR, R4
3 LOOP: LV.D V1, R1
4 DSLL R5, R4, 3
5 DADDU R1, R1, R5
6 LV.D V2, R2
7 DADDU R2, R2, R5
8 MULTSV.D V1, V1, R29
9 MULTSV.D V2, V2, R30
10 ADDV.D V2, V1, V2
11 SV.D V2, R2
12 DADD R3, R3, -R4
13 LI R4, 64
14 MTC1 VLR, R4
15 BGTZ R3, LOOP
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 119
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
OTTIMIZZAZIONE
Prima di tutto è possibile, sfruttando la forma base+spiazzamento, utilizzare un unico registro per
l’incremento dei registri R1 e R2 evitando così di utilizzare due istruzioni (5 e 7).
Il registro base conterrà l’indirizzo del primo elemento del vettore, quindi diverso per ogni vettore, mentre
lo spiazzamento, comune per tutti i vettori, conterrà il valore del salto per accedere al blocco di dati
successivo. Per cui è possibile riscrivere le load/store nella seguente maniera:
La sintassi da seguire è: LV.D dest, offset(base)
LV.D V1, R7(R1)
LV.D V2, R7(R2)
SV.D V2, R7(R2)
Dove R7 è il registro contenente lo spiazzamento; per cui basterà incrementarlo per accedere al blocco di
dati successivo; per cui R7 è l’unico indice che opera all’interno del loop. In questo modo è possibile anche
escludere il registro R3 che precedentemente faceva da contatore, ed usare R7 come registro su cui
effettuare il controllo.
Si ricordi che nel caso scalare, il problema veniva affrontato processando il vettore a partire dall’ultimo
elemento fino ad arrivare al primo, con un decremento dell’indice di 8 byte.
Nel caso del processore vettoriale, l’indice non punterà all’ultimo elemento, ma al primo elemento
dell’ultimo sottovettore, che, per una migliore implementazione, è il vettore remainder; per cui l’indice ad
ogni iterazione verrà decrementato di 64 elementi, ossia di 64 ∗ 8 = 512 byte. Il decremento, sottoforma
d’istruzione, è il seguente:
DADDI R7, R7, #-512
Per chiarire quando detto si consideri il seguente esempio:
Si supponga un vettore di 140 elementi; questo vettore sarà diviso in due sottovettori da 64 elementi e un
sottovettore da 12 elementi. Considerando il sottovettore remainder come ultimo blocco, l’indice punterà
al suo primo elemento, per cui attraverso il decremento di 512 byte si avrà accesso al primo elemento del
secondo sottoblocco e successivamente, con un ulteriore decremento al primo elemento del primo
sottoblocco.
Le seguenti figure chiariscono la scelta di porre per ultimo il sottovettore remainder.
Per posizionare R7 bisogna calcolare l’indirizzo del primo elemento del sottovettore remainder. Questo è possibile attraverso l’operazione: 𝑁 − 𝑟𝑒𝑚𝑎𝑖𝑛𝑑𝑒𝑟 ∗ 8.
L’indice punterà al primo elemento
dell’ultimo sottoblocco R7
L’indice punterà al primo elemento del
secondo sottoblocco R7
L’indice punterà al primo elemento del
primo sottoblocco
R7
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 120
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Fatte queste considerazioni il codice parzialmente ottimizzato è il seguente:
1 ANDI R4, R3, 63
2 MTC1 VLR, R4
3 DSUBI R7, R3, R4
4 DMULI R7, R7, #8
5 LOOP: LV.D V1, R7(R1)
6 MULTSV.D V1, V1, R29
7 LV.D V2, R7(R2)
8 MULTSV.D V2, V2, R30
9 ADDV.D V2, V1, V2
10 SV.D V2, R7(R2)
11 DADDI R7, R7, #-512
12 MTC1 VLR, #64
13 BGEZ R7, LOOP
Adesso vediamo come è possibile schedulare meglio il loop per eliminare gli eventuali stalli presenti. Dopo le due load ci sarà uno stallo con le successive operazioni di moltiplicazione che utilizzano come sorgenti i registri destinazione delle load.
L’istruzione BGEZ provoca uno stallo: sposto l’istruzione MTC1 VLR, #64 nel delay slot sotto alla BCEZ. Per concludere il codice ottimizzato è il seguente (considerando unitaria la latenza di ciascuna unità funzionale):
1 ANDI R4, R3, 63
2 DSUBI R7, R3, R4
3 MTC1 VLR, R4
4 DMULI R7, R7, #8
5 LOOP: LV.D V1, R7(R1)
6 LV.D V2, R7(R2)
7 MULTSV.D V1, V1, R29
8 MULTSV.D V2, V2, R30
9 ADDV.D V2, V1, V2
10 SV.D V2, R7(R2)
11 DADDI R7, R7, #-512
12 BCEZ R7, LOOP
13 MTC1 VLR, #64
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 121
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Analizziamo ora i diagrammi temporali delle istruzioni “fondamentali” per l’operazione da effettuare; si
consideri per semplicità che la cpu vettoriale sia ad una sola corsia e che la banda passante della memoria
dati sia di tre dati per colpo di clock, per cui è possibile effettuare tre accessi in memoria. Inoltre si
consideri la presenza di due moltiplicatori con una latenza di 4 colpi di clock, per cui dopo 4 cc il
moltiplicatore mette a disposizione il primo risultato; due sommatori con una latenza di 2 colpi di clock.
LEGENDA
Disponibilità 1° elemento:
Disponibilità 2° elemento:
Disponibilità elementi successivi:
Disponibilità ULTIMO elemento:
Per il seguente diagramma VLR è impostato al valore 64
COLPI DI CLOCK
ISTRUZIONI↓ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 .
6
7
6
8 .
7
2
7
3
7
4
7
5
7
6
LV.D V1, R7(R1) IF ID EX MEM WB
LV.D V2, R7(R2) IF ID EX MEM WB
MULTSV.D V1, V1, R29 IF ID EX MEM WB
MULTSV.D V2, V2, R30 IF ID EX MEM WB
ADDV.D V2, V1, V2 IF ID STALLO EX MEM WB
SV.D V2, R7(R2) IF ID EX STALLO MEM WB
Bisogna quindi aggiungere le ulteriori istruzioni di gestione; il procedimento da seguire è analogo a quanto
appena fatto. Per cui si completa l’intera operazione Y=aX+bY con vettori da 64 elementi dopo 76 colpi di
clock, senza contare le istruzioni di gestione fuori e dentro al loop.
Chiarito questo, si supponga di avere la stessa cpu vettoriale con la sola differenza che adesso consideriamo
8 corsie. Questo significa che per ogni colpo di clock verranno effettuate 8 operazioni, per ogni istruzione
vettoriale, per cui ad esempio una istruzione di load vettoriale caricherà in un solo colpo di clock 8
elementi.
Per cui si riducono i colpi di clock e ne risulta il seguente diagramma:
LEGENDA
Disponibilità 1° ÷ 8° elemento:
Disponibilità 9° ÷ 16° elemento:
Disponibilità 17° ÷ 56° elemento:
Disponibilità 57° ÷ 64° elemento:
Per il seguente diagramma VLR è impostato al valore 64 COLPI DI CLOCK
ISTRUZIONI↓ 1 2 3 4 5 6 7 8 9 10 11 12 13 14
1
5
1
6
1
7
1
8
1
9
2
0
LV.D V1, R7(R1) IF ID EX MEM WB
LV.D V2, R7(R2) IF ID EX MEM WB
MULTSV.D V1, V1, R29 IF ID EX MEM WB
MULTSV.D V2, V2, R30 IF ID EX MEM WB
ADDV.D V2, V1, V2 IF ID STALLO EX MEM WB
SV.D V2, R7(R2) IF ID EX STALLO MEM WB
Per cui si completa l’intera operazione Y=aX+bY con vettori da 64 elementi dopo 19 colpi di clock.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 122
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Il diagramma completo per l’esercizio assegnato è il seguente: si consideri una cpu a 8 corsie. LEGENDA
Disponibilità 1° ÷ 8° elemento del sottovettore:
Disponibilità 9° ÷ 16° elemento del sottovettore:
Disponibilità 17° ÷ 56° elemento del sottovettore:
Disponibilità 57° ÷ 64° elemento del sottovettore:
COLPI DI CLOCK
ISTRUZIONI↓ 1 2 3 4 5 6 7 8 9
1
0
1
1
1
2
1
3
1
4
1
5
1
6
1
7
1
8
1
9
2
0
2
1
2
2
2
3
2
4
2
5
2
6
2
7
2
8
2
9
3
0
3
1
3
2
ANDI R4, R3, 63 IF ID EX ME
M WB
ANDI R7, R3, R4 IF ID EX ME
M WB
MTC1 VLR, R4 VLR = 32 IF ID EX ME
M WB
DMULI R7, R7, #8 IF ID EX ME
M WB
LV.D V1, R7(R1) IF ID EX ME
M WB
LV.D V2, R7(R2) IF ID EX ME
M WB
MULTSV.D V1, V1, R29 IF ID EX ME
M WB
MULTSV.D V2, V2, R30 IF ID EX ME
M WB
ADDV.D V2, V1, V2 IF ID STALLO EX ME
M WB
SV.D V2, R7(R2) IF ID EX STALLO ME
M WB
DADDI R7, R7, #-512 IF ID EX ME
M WB
BCEZ R7, LOOP IF ID EX ME
M WB
MTC1 VLR, #64 VLR = 64 IF ID EX ME
M WB
LV.D V1, R7(R1) IF ID EX ST
AL
ME
M WB
LV.D V2, R7(R2) IF ID EX STALLO ME
M WB
MULTSV.D V1, V1, R29 IF ID EX ME
M WB
MULTSV.D V2, V2, R30 IF ID EX STALLO ME
M WB
ADDV.D V2, V1, V2 IF ID STALLO EX STALLO M
E
W
B
SV.D V2, R7(R2) ID ID EX STALLO M
E
W
B
DADDI R7, R7, #-512 IF ID EX ME
M WB
BCEZ R7, LOOP IF ID EX ME
M WB
MTC1 VLR, #64 IF ID EX ME
M WB
È possibile sovrapporre alcune fasi, poiché queste utilizzano unità funzionali diverse, o perché si è ipotizzato
che alcune unità, come la memoria, possiedono una banda di dati maggiore.
Essendo i vettori di 96 elementi il loop sarà eseguito due volte, prima con VLR = 32 e poi con VLR = 64; per
eseguire l’operazione richiesta ci vorranno 37 colpi di clock (la tabella non è completa per motivi di spazio).
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 123
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ARCHITETTURA MULTICORE Fino ad ora si è visto come potessero essere migliorate le prestazioni di un calcolatore puntando su
architetture ILP (Instruction Level Parallelism), cioè quelle architetture basate sul parallelismo delle
istruzioni che con una serie di accorgimenti, quali pipeline delle unità funzionali, riduzione dei conflitti,
predizione dei salti, ecc., hanno permesso di ottenere la miglior soluzione possibile per l’ottimizzazione
delle prestazioni; inoltre con l’utilizzo di hardware particolari (VLIW, Super Scalare, Vettoriale) si è
contribuito all’aumento delle prestazioni, il tutto utilizzando una sola cpu.
Quello che emerge è che l’aumento delle prestazioni che è possibile ottenere è fortemente legato
all’hardware di controllo, il quale deve gestire al meglio la contemporanea esecuzione delle istruzioni in
maniera da evitare conflitti; non sempre però questo porta ad un effettivo ed evidente miglioramento delle
prestazioni.
Infatti alcune valutazioni hanno evidenziato che insistere in queste direzioni non porta ad avere una
effettiva efficienza (generalmente: 𝐸𝐹𝐹𝐼𝐶𝐼𝐸𝑁𝑍𝐴 =𝑅𝐼𝑆𝑈𝐿𝑇𝐴𝑇𝐼
𝐶𝑂𝑆𝑇𝐼).
Inoltre queste valutazioni hanno evidenziato che è possibile mantenere alta l’efficienza con un numero di
processori maggiori. Seguendo queste valutazioni si è arrivati, grazie alla tecnologia a disposizione, a
realizzare in un singolo chip più di un processore.
Questa tecnologia risulta interessante, poiché ha costi relativamente bassi, in quanto si va replicare il
singolo processore e quindi non richiede una riprogettazione complessa. Quindi invece di rinforzare,
potenziare una singola caratteristica si va a replicare l’intera cpu; il potenziamento di una caratteristica
migliora le prestazioni di quella parte di esecuzione del programma che va ad usare quella componente, e
quindi non vi è un miglioramento globale del sistema.
La seguente figura mostra come l’aumento dei registri, non comporta una miglioramento proporzionale al
potenziamento eseguito.
Passando da 32 a 128 registri, quindi quadruplicandone il numero, non si nota un aumento proporzionale
delle istruzioni parallele, per cui non sempre il potenziamento si traduce in un effettivo miglioramento.
Questo significa che il punto critico è diventato un altro aspetto; analogo discorso si potrebbe avere
analizzando un miglioramento delle predizioni di salto.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 124
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
PARALLELISMO A LIVELLO DI THREAD, MULTI-THREAD Per thread si intende un processo indipendente da un altro processo; indipendente nel senso che può
appartenere allo stesso programma, ma che non è influenzato dagli esiti determinati dagli altri processi che
costituiscono il programma. Ogni thread ha i suoi dati, istruzioni, registri necessari alla sua esecuzione.
Fondamentalmente esistono tre tipi di multithread:
1. SIMULTANEOUS MULTI-THREADING: consideriamo una CPU che permette teoricamente di eseguire
in simultaneo 8 istruzioni, grazie alla presenza di più unità funzionali uguali. L’esecuzione di un
singolo thread potrebbe generare una situazione del genere:
In un colpo di clock dovrebbero essere prelevate 8 istruzioni, ma questo,
come si vede, non avviene, poiché evidentemente non vi sono istruzioni che
usano unità funzionali diverse. Quindi in un colpo di clock saranno
processate poche istruzioni, provocando anche eventuali stalli.
È possibile pensare di utilizzare le unità
funzionali inutilizzate usando istruzioni di un
altro thread; questo perché per definizione i
thread sono indipendenti fra loro, quindi lo
saranno anche i loro dati. Ciò significa che non
vi saranno conflitti di dati: la situazione in
presenza di un altro thread è rappresentata
dalla seguente figura.
Per cui i thread partono simultaneamente sfruttando le unità
funzionali non utilizzate da un altro thread.
2. FINE-GRAINED MULTI-THREADING: (a grana fina) questa tipologia di multithreading prevede che il
processore scambi il thread in esecuzione a ogni ciclo di clock. Questa tipologia di multithreading
dovrebbe rimuovere la dipendenza dai dati dei singoli thread e quindi dovrebbe azzerare o
comunque ridurre gli stalli della pipeline dovuta alla dipendenza dai dati. Dato che ogni thread
dovrebbe funzionare in modo indipendente i singoli thread eseguiranno programmi non correlati e
quindi vi saranno poche probabilità che le istruzioni di un thread necessitino dei risultati elaborati
da un'istruzione di un altro thread in esecuzione in quel momento.
3. COARSE-GRAINED MULTI-THREAD: (a grana grossa) questa tipologia di multithread prevede che il
processore esegua un singolo thread fino a quando questo non viene bloccato da un evento che
normalmente ha una elevata latenza (per esempio un cache miss), in questo caso il processore
provvede a eseguire un altro thread che era pronto per l'esecuzione. Il thread di rimpiazzo rimane
in esecuzione fino a quando termina o viene bloccato da un evento.
Per queste ultime due tipologie di multithread bisogna fare delle considerazioni: il multithreading parte dal
presupposto che il passaggio tra thread avvenga in modo rapido; queste due tecniche effettuano il
passaggio in un ciclo di clock. Al fine di ottenere questo il processore deve replicare alcune componenti per
i due thread come i registri interni, il program counter e alcuni registri di stato. Per cui un cambio di
contesto ottimizzato è fondamentale per avere tempi estremamente bassi.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 125
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Di seguito è riportato uno schema riassuntivo delle varie tecniche di parallelismo.
MEMORIA CONDIVISA E MEMORIA DISTRIBUITA IN SISTEMI MULTICORE
La categoria normalmente utilizzata nelle architetture
multicore è quella a memoria condivisa; N core, ognuno
comprendente una memoria cache, condividono
un’unica memoria centrale.
Un’altra categoria è caratterizzata da
memorie locali per ogni core, che sono
sincronizzate da una particolare
infrastruttura, anche complessa, per
mantenere una certa coerenza fra i dati.
Si utilizza una memoria condivisa quando non è possibile individuare delle aree dati distinte e indipendenti
per ogni singolo thread che ogni core deve eseguire. Per cui questa soluzione è ottimale dal punto di vista
della coerenza fra i dati. Il problema legato a questa categoria è dovuto al fatto che diversi core devono
accedervi contemporaneamente; ma questo non è possibile, o comunque non in elevate quantità, poiché
la memoria possiede una banda passante finita, che limita gli accessi ad essa stessa.
Per cui è evidente che una soluzione a memoria condivisa è effettivamente praticabile quando si utilizza un
numero di core basso. Per superare quindi questo limite è opportuno implementare la categoria a memoria
distribuita; l’implementazione richiede la realizzazione di una efficiente rete di interconnessione, in modo
da ridurre il tempo di comunicazione tra le memorie.
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 126
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
IInnddiiccee AAnnaalliittiiccoo
A
ALEE ISTRUZIONI ALU ........................ 31 ISTRUZIONI BRANCH ................. 35 ISTRUZIONI LOAD ...................... 34 RAW - WAW - WAR - RAR ......... 30
Amdahl, legge di ............................ 69 Associativa ........ Vedi Memorie Cache
B
Banchi interlacciati ........................ 78 Banchi paralleli .............................. 78
C
Clean Bit ........................................ 69 COARSE-GRAINED MULTI-THREAD
................................................ 123 Codifica
dell'istruzione ........................... 14 Completamente Associativa ....... Vedi
Memorie cache Componenti del processore No-
Pipeline ......... Vedi Processore No-Pipeline
Control Unit Microprogrammata, Cablata .... 14
Corsie ........................................... 110
D
Dead Time ................................... 114 Delay Slot ....................................... 37 Dirty Bit .......................................... 70 DRAM ............................................ 70
E
EX - Execution ................................ 17
F
FIFO, metodo ......... Vedi Sostituzione FINE-GRAINED MULTI-THREADING
................................................ 123 Finestra dei registri ........................ 62 Floating point
Scheduling istruzioni ................. 87
G
Gerarchia di memoria .................... 62
H
HIT RATE ........................................ 71 HIT TIME ........................................ 71
I
ID - Instruction Decode .................. 16 IF - Instruction Fetch ...................... 16 Indirizzamento diretto Vedi Memorie
cache Istruzioni .......................................... 7
di calcolo ................................... 10 di controllo ................................ 11 di tipo MOV ................................. 9 di trasferimento dei dati ............. 7 Formato delle ............................ 13 fuori ordine ............................... 84 LVWS ....................................... 105 Set, floating point...................... 86 Set, vettoriale .......................... 104 Superscalare ............................ 102 Vettoriali
Parallelismo ........................ 113 VLIW .......................................... 99
Istruzioni di tipo I . Vedi Formato delle istruzioni
Istruzioni di tipo Jump.. Vedi Formato delle istruzioni
Istruzioni di tipo R Vedi Formato delle istruzioni
L
LRU, metodo .......... Vedi Sostituzione
M
MEM - Memory Access .................. 18 Memorie cache .............................. 64
ad indirizzamento diretto ......... 65 Allocazione dei blocchi .............. 64 Completamnte associative ........ 65 Elettronica ................................. 70 Funzionamento logico delle ...... 74 Organizzazione .......................... 80 Prestazioni .......................... 71; 78 Problematiche ........................... 77 Scrittura .................................... 69
set associativa .......................... 65 Memorie Cache
Accesso alla memoria ............... 28 LOAD/STORE disallineata..... 29
MIPS64 Set istruzioni ............................. 12
MISS PENALITY .............................. 71 MISS RATE ..................................... 71 MOTOROLA 68000 ........................ 76 MVLR ..............................Vedi Registri
P
Pipeline ALEE .......................................... 27
Strutturali, di dato ............... 30 da programma .......................... 42 Microistruzioni ......................... 26 Struttura processore ................ 25 Tecnica ..................................... 22
PowerPC ........................................ 74 Prinicipi di località ......................... 63 Processore
Accumulatore ........................... 57 Floating point ........................... 84 Multicore ................................ 122 No-Pipeline ............................... 15 Pipeline ..................................... 25
Ottimizzato .......................... 36 Superscalare ........................... 102 Vettoriale ............................... 103
CRAY 1 ............................... 107 VLIW ......................................... 99
R
Random, metodo ... Vedi Sostituzione Registri ............................................ 9
V.LENGHT ............................... 107 V.MASK ................................... 107 Vettoriali................................. 109 VLR, MVLR .............................. 105
Ricerca e identificazione ............... 66
S
Salto Condizionato, Incondizionato ... 11
Scoreboard .................................... 86 Set, istruzioni................................. 11 Shift, istruzioni
Logico, Aritmetico .................... 11 SIMULTANEOUS MULTI-THREADING
............................................... 123 Sostituzione ................................... 67 SRAM ............................................. 70
Appunti di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 127
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Stazioni di prenotazione ............. Vedi Tomasulo, algoritmo
Strotolamento ............................... 40
T
Tecnica Speculativa ....................... 38 Tipi di dati ........................................ 7
Floating Point .............................. 7 Interi ........................................... 7
Vettoriali ................................. 103 Tomasulo, algoritmo ...................... 88 Trasparenza dei livelli .................... 62
V
V.LENGHT ....................... Vedi Registri V.MASK .......................... Vedi Registri
uso del registro ....................... 114 VECTOR STRIPMINING ................. 111
VLR .................................Vedi Registri
W
Write Back ..................................... 69 Write Through ............................... 69
BBIIBBLLIIOOGGRRAAFFIIAA
1. JOHN L. HENNESSY, DAVID A. PATTERSON, “Architettura degli elaboratori”, 4a edizione, APOGEO
2. PROF. ING. F. MARINO, G. MASTRONARDI “Supporto Multimediale di Ausilio al Corso di
CALCOLATORI ELETTRONICI”,
3. DAVID A. PATTERSON, “Slide” di alcune lezioni scaricabili dal link:
http://vlsi.cs.berkeley.edu/cs252-s06/index.php/Lectures”, 2006
4. WIKIPEDIA, “L’enciclopedia libera“
EESSEERRCCIIZZII DDII CCAALLCCOOLLAATTOORRII EELLEETTTTRROONNIICCII
A.A. 2009/2010
A cura di: Fabio Stroppa
Nicola Pietroleonardo
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 1
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
IINNDDIICCEE
MICROCODICE DELLE ISTRUZIONI FONDAMENTALI ............................... 2
ESERCIZI MICROCODICE ........................................................................ 3
ESERCIZIO 1 - ADDW R1 R2 R3 ....................................................................................................................... 4
ESERCIZIO 2 - ADDMEM R1 R2 R3 ................................................................................................................. 6
ESERCIZIO 3 – ADD3 R1 R2 R3 ....................................................................................................................... 8
ESERCIZIO 4 – MAC R1,(R2),R3 ...................................................................................................................... 9
ESERCIZIO 5 – SWP R1 R2 ............................................................................................................................ 11
ESERCIZIO 6 – SWX R2 R31 R1 ..................................................................................................................... 13
ESERCIZIO 7 – LL R6 (#100,R3) ..................................................................................................................... 14
ESERCIZIO 8 – SL (#100,R3) R6 ..................................................................................................................... 15
ESERCIZIO 9 – SWPM R1 R2 ......................................................................................................................... 16
ESERCIZI ASSEMBLY ............................................................................ 18
ESERCIZIO 1 – SOMMA DI DUE VETTORI ..................................................................................................... 19
ESERCIZIO 2 – MEDIA DI UN VETTORE ......................................................................................................... 23
ESERCIZIO 3 – MINIMO DI UN VETTORE ...................................................................................................... 25
ESERCIZIO 4 – LOAD DOUBLE NON ALLINEATA ........................................................................................... 28
ESERCIZIO 5 – STORE DOUBLE NON ALLINEATA .......................................................................................... 30
ESERCIZIO 6 – SOMMA DI VETTORI – PIPELINE DA PROGRAMMA .............................................................. 32
ALGORITMO DI TOMASULO ................................................................ 33
ESERCIZIO 1 .................................................................................................................................................. 34
ESERCIZIO 2 .................................................................................................................................................. 40
ESERCIZI ASSEMBLY – PROCESSORI SUPERSCALARI E VLIW .................. 48
ESERCIZIO 1 .................................................................................................................................................. 49
ESERCIZI ASSEMBLY DLXV ................................................................... 55
ESERCIZIO 1 – SOMMA VETTORI DA 64 ELEMENTI ...................................................................................... 56
ESERCIZIO 2 – SOMMA DI VETTORI > 64 ..................................................................................................... 57
ESERCIZIO 3 – SOMMA DI MATRICI CON MxN > 64 ..................................................................................... 59
ESERCIZIO 4 – OPERAZIONE Y = (aX + bY)/c ................................................................................................ 60
ESERCIZIO 5 – PRODOTTO SCALARE TRA VETTORI DI 64 ELEMENTI ............................................................ 62
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 2
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
MICROCODICE DELLE ISTRUZIONI FONDAMENTALI
IF IF/ID.IR Mem[PC]; IF/ID.NPC (if ((EX/MEM.opcode == branch)OR(EX/MEM.opcode == jump) & EX/MEM.cond) {(EX/MEM.ALUOutput)} else{PC+4}); ID ID/EX.A Regs[IF/ID.IR[rs]]; ID/EX.B Regs[IF/ID.IR[rt]]; ID/EX.Imm sign-extended(IF/ID.IR[immediate field]); ID/EX.IR IF/ID.IR; ID/EX.NPC IF/ID.NPC; ISTRUZIONE DI DIRAMAZIONE EX EX/MEM.ALUOutput ID/EX.NPC + (ID/EX.Imm << 2); EX/MEM.cond (ID/EX.A == 0); MEM WB ISTRUZIONE ALU R op R EX EX/MEM.IR ID/EX.IR; EX/MEM.ALUOutput ID/EX.A op ID/EX.B; MEM MEM/WB.IR EX/MEM.IR; MEM/WB.ALUOutput EX/MEM.ALUOutput; WB Regs[MEM/WB.IR[rd]] MEM/WB.ALUOutput; ISTRUZIONE ALU R op Imm EX EX/MEM.IR ID/EX.IR; EX/MEM.ALUOutput ID/EX.A op ID/EX.Imm; MEM MEM/WB.IR EX/MEM.IR; MEM/WB.ALUOutput EX/MEM.ALUOutput; WB Regs[MEM/WB.IR[rd]] MEM/WB.ALUOutput; ISTRUZIONE LOAD EX EX/MEM.IR ID/EX.IR; EX/MEM.ALUOutput ID/EX.A + ID/EX.Imm; MEM MEM/WB.IR EX/MEM.IR; MEM/WB.LMD Mem[EX/MEM.ALUOutput]; WB Regs[MEM/WB.IR[rt]] MEM/WB.LMD; ISTRUZIONE STORE EX EX/MEM.IR ID/EX.IR; EX/MEM.ALUOutput ID/EX.A + ID/EX.Imm; EX/MEM.B ID/EX.B; MEM MEM/WB.IR EX/MEM.IR; Mem[EX/MEM.ALUOutput] EX/MEM.B; WB
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 3
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZI MICROCODICE
ESERCIZI MICROCODICE
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 4
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 1 - ADDW R1 R2 R3 Scrivere un microprogramma per l'istruzione ADDW R1 R2 R3 che fa R1=M[R2]+M[R3] per un MIPS-pipeline, discutere i conflitti e possibili soluzioni architetturali. Equivale alla successione di queste operazioni assembly: LD R4, 0(R2) LD R5, 0(R3) DADD R1, R4, R5 Tale codice presenta uno stallo dopo l’istruzione di load per conflitto di dati, in quanto il registro operando della somma è il registro destinazione della load, la quale al momento della fase exe dell’istruzione di somma non ha ancora scritto in tale registro il valore prelevato dalla memoria. Conteggiamo quindi 4 istruzioni, che vengono eseguite in 5+(4-1) = 8 colpi di clock. IF IF/ID.IR Mem[PC]; IF/ID.NPC PC+4; ID ID/EX.IR IF/ID.IR; ID/EX.NPC IF/ID.NPC; ID/EX.A Regs[IF/ID.IR[rs]]; ID/EX.B Regs[IF/ID.IR[rt]]; ID/EX.Imm sign-extended(IF/ID.IR[immediate field]); In realtà l’indirizzo a cui fare riferimento in memoria è già presente nei registri R2 ed R3 caricati nei latch ID/EX.A ed ID/EX.B nella fase di ID, dunque non è necessario sommare un immediato nullo. L’ALU non svolge alcuna operazione di somma e la fase EX si limita a propagare il valore di A e B rispettivamente nel latch EX/MEM.ALUOutput e EX/MEM.B. EX1 EX/MEM.IR ID/EX.IR; EX/MEM.ALUOutput ID/EX.A; EX/MEM.B ID/EX.B; L’operazione di MEM prevede due accessi alla memoria: uno per prelevare il primo dato MEM1 (indirizzo salvato in R2, A) e un altro per prelevare il secondo dato MEM2 (indirizzo salvato in R3, B). Quindi avremo bisogno di due fasi di MEM. È utile che, contemporaneamente al salvataggio nei latch del primo operando dalla memoria, venga sostituito il valore di EX/MEM.ALUOutput con il valore di B per contenere il secondo operando, così da ripetere nel colpo di clock successivo la medesima operazione. In realtà, se si utilizza lo stesso latch EX/MEM.ALUOutput si rischia di incorrere in un problema di incoerenza dei dati: l’istruzione schedulata un colpo di clock dopo quella di interesse si troverà in fase EX mentre questa è in MEM1 e aggiornerà il valore di EX/MEM.ALUOutput con il risultato della sua operazione con l’ALU, dunque è necessario salvare B in un altro latch aggiuntivo che chiamiamo EX/MEM.ALUOutput2. MEM1 MEM/WB.IR EX/MEM.IR; MEM/WB.LMD Mem[EX/MEM.ALUOutput]; EX/MEM.ALUOutput2 EX/MEM.B;
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 5
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Avendo ora disponibile B in EX/MEM.ALUOutput2 si può pensare al prelievo dalla memoria di un’altra istruzione, la quale scriverà nuovamente in MEM/WB.LMD per contenere il secondo operando. È dunque importante salvare il valore del primo operando in MEM/WB.ALUOutput così da non perdere il dato. Attenzione, stesso problema precedente: nel caso l’istruzione schedulata nel colpo di clock successivo a quella di interesse sia un’operazione di ALU, la sua fase MEM verrà eseguita in contemporanea con la fase MEM2 in quanto tale operazione non farà effettivamente uso della memoria e quindi non crea conflitti o stalli; viene però modificato il valore di MEM/WB.ALUOutput al termine della fase di MEM, quindi è saggio salvare il primo operando (A) in un altro latch che chiamiamo MEM/WB.ALUOutput2, senza scomodare minimamente MEM/WB.ALUOutupt che sarà impegnato (probabilmente) dall’istruzione successiva. Il prelievo del dato salvato in memoria nell’indirizzo contenuto in EX/MEM.ALUOutput2 (B) viene ora salvato in MEM/WB.LMD, ma l’operazione di lettura da memoria e scrittura nel registro può essere pensata come divisa in due fasi, ciascuna lunga un semiciclo di clock: nel primo semiciclo viene letto il dato in memoria all’indirizzo EX/MEM.ALUOutput2 e nel secondo semiciclo viene scritto tale valore nel latch MEM/WB.LMD: non vi è alcuna sovrascrittura, in quanto abbiamo già salvato MEM/WB.LMD in MEMWB.ALUOutput2 durante il primo semiciclo. È importante inoltre che l’IR dell’istruzione continui a propagarsi nella pipeline, e quindi tale valore dovrà essere spostato da MEM/WB.IR in quanto tale latch ora ospiterà l’IR dell’istruzione schedulata successivamente quella di interesse. Dunque, salviamo l’IR in un nuovo latch che chiamiamo MEM/WB.IR2. MEM2 MEM/WB.IR2 MEM/WB.IR; MEM/WB.ALUOutput2 MEM/WB.LMD; MEM/WB.LMD Mem[EX/MEM.ALUOutput2]; Avendo ora a disposizione entrambi gli operandi, è possibile compiere l’operazione di somma. Si pensa di aggiungere un sommatore esterno all’ALU in modo da non creare conflitti con istruzioni schedulate 3 colpi di clock dopo quella di interesse. EX2 MEM/WB.ALUOutput2 MEM/WB.LMD + MEM/WB.ALUOutput2; WB Regs[MEM/WB.IR2[rd]] MEM/WB.ALUOutput2; L’istruzione viene eseguita in 7 colpi di clock, risparmiandone 1 rispetto alla sua scissione in 3 istruzioni. Ci saranno stalli obbligatori se l’istruzione che segue la nostra ADDW è una load o store, che fa uso effettivo nella memoria (che sarà occupata in quel momento) oppure se la seconda istruzione schedulata dopo la ADDW è un’istruzione ALU oppure una LOAD, che scrive nei registri durante la fase di write back.
Al progetto del processore pipeline abbiamo aggiunto tre latch ed un sommatore.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 6
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 2 - ADDMEM R1 R2 R3 Scrivere un microprogramma per l'istruzione ADDMEM R1 R2 R3 che fa Mem[R1]=Mem[R2]+Mem[R3] per un MIPS-pipeline, discutere i conflitti e possibili soluzioni architetturali. Equivale alla successione di queste operazioni assembly: LD R4, 0(R2) LD R5, 0(R3) DADD R6, R4, R5 SD 0(R1), R6 Tale codice presenta uno stallo dopo l’istruzione di load per conflitto di dati, in quanto il registro operando della somma è il registro destinazione della load, la quale al momento della fase exe dell’istruzione di somma non ha ancora scritto in tale registro il valore prelevato dalla memoria. Non vi sono stalli dopo l’istruzione di somma, nonostante il suo registro destinazione sia il registro operando dell’istruzione di store successiva se si pensa a cortocircuitare l’ALU del processore in modo tale da evitare questi conflitti di dati. Conteggiamo quindi 5 istruzioni, che vengono eseguite in 5+(5-1) = 9 colpi di clock. L’istruzione da codificare è essenzialmente simile all’esercizio precedente, con l’unica differenza che il risultato della somma non deve essere salvato in un registro ma in memoria, dunque si rende necessaria l’operazione finale di store. Le modifiche apportate al processore per l’operazione dell’esercizio precedente rimangono inalterate. IF IF/ID.IR Mem[PC]; IF/ID.NPC PC+4; ID ID/EX.IR IF/ID.IR; ID/EX.NPC IF/ID.NPC; ID/EX.A Regs[IF/ID.IR[rs]]; ID/EX.B Regs[IF/ID.IR[rt]]; ID/EX.Imm sign-extended(IF/ID.IR[immediate field]); EX1 EX/MEM.IR ID/EX.IR; EX/MEM.ALUOutput ID/EX.A; EX/MEM.B ID/EX.B; MEM1 MEM/WB.IR EX/MEM.IR; MEM/WB.LMD Mem[EX/MEM.ALUOutput]; EX/MEM.ALUOutput2 EX/MEM.B; MEM2 MEM/WB.IR2 MEM/WB.IR; MEM/WB.ALUOutput2 MEM/WB.LMD; MEM/WB.LMD Mem[EX/MEM.ALUOutput2]; Dovendo salvare il risultato in memoria, si rende necessaria la lettura dell’indirizzo a cui fare riferimento dal registro in cui è contenuto. Si nota una cosa fondamentale: durante la seconda fase di EX si scrive nel
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 7
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
registro EX/MEM.B: tale operazione può portare a dei conflitti di dati se l’istruzione schedulata tre colpi di clock dopo la ADDMEM è un’operazione di store:
Nella sua fase di EXE, la store scriverà il valore di ID/EX.B in EX/MEM.B per propagare il valore di B, utilizzando quindi il latch EX/MEM.B. Dunque, per evitare problemi di questo tipo, sarebbe consigliabile propagare ulteriormente il valore di B della istruzione di ADDMEM da EX/MEM.B a MEM/WB.B aggiungendo un nuovo registro al latch del processore. In realtà, successivamente scopriremo che l’aggiunta di questo registro nel latch è inutile. EX2 MEM/WB.ALUOutput2 MEM/WB.LMD + MEM/WB.ALUOutput2; MEM/WB.B Regs[M/WB.IR2[rd]; } da svolgere nel secondo semiciclo di clock, lettura da registro MEM3 Mem[MEM/WB.B] MEM/WB.ALUOutput2; L’istruzione viene eseguita in 7 colpi di clock, risparmiandone 2 rispetto alla sua scissione in 4 istruzioni. Ci saranno stalli obbligatori se l’istruzione che segue la nostra ADDMEM è una load o store, che fa uso effettivo nella memoria (che sarà occupata in quel momento). Stesso discorso per l’istruzione schedulata tre colpi di clock dopo la ADDMEM, che cadrà in fase MEM quando la ADDMEM è in MEM3.
In base a quanto detto, la terza operazione dopo la ADDMEM, se è una store, provocherà uno stallo: tornando al discorso in cui si consigliava la presenza del latch MEM/WB.B si nota ora che è possibile utilizzare per tale funzione lo stesso registro EX/MEM.B; spostando infatti lo stallo che si trova dopo la fase EX della store prima della EX stessa, non si avranno problemi di sovrascrittura e di conflitti di memoria.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 8
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 3 – ADD3 R1 R2 R3 Scrivere un microprogramma per l'istruzione ADD3 R1 R2 R3 che fa R1=R1+R2+R3 per un MIPS-pipeline, discutere i conflitti e possibili soluzioni architetturali. Equivale alla successione di queste operazioni assembly: DADD R1, R1, R2 DADD R1, R1, R3 Tale codice non presenta stalli se si considera la corto circuitazione dell’ALU. Conteggiamo quindi 2 istruzioni, che vengono eseguite in 5+(2-1) = 6 colpi di clock. IF IF/ID.IR Mem[PC]; IF/ID.NPC PC+4; ID ID/EX.IR IF/ID.IR; ID/EX.NPC IF/ID.NPC; ID/EX.A Regs[IF/ID.IR[rs]]; ID/EX.B Regs[IF/ID.IR[rt]]; ID/EX.Imm sign-extended(IF/ID.IR[immediate field]); La fase di EX1 dovrà sommare I registri R2 ed R3 e nel frattempo caricare R1 affinché l’operazione di somma sia completata al colpo di clock successivo. Possiamo pensare di leggere R1 nella fase di ID aggiungendo un nuovo registro nel latch ID/EX chiamato C e propagarlo anche nel latch EX/MEM, quindi aggiungendo due registri; oppure si può pensare di potenziare l’accesso alla memoria registri in modo tale da poter effettuare più letture in parallelo, in questo caso inserendo un’ulteriore fase di ID nella fase EX1 questa non andrà in conflitto con la fase ID processata contemporaneamente dal processore per l’istruzione schedulata un colpo di clock dopo. Si utilizza quindi il già presente registro EX/MEM.B. EX1 EX/MEM.IR ID/EX.IR; EX/MEM.ALUOutput ID/EX.A + ID/EX.B; EX/MEM.B Regs[ID/EX.IR[rd]]; EX2 MEM/WB.IR EX/MEM.IR; MEM/WB.ALUOutput EX/MEM.ALUOutput + EX/MEM.B; WB Regs[MEM/WB.IR[rd]] MEM/WB.ALUOutput; Inserendo un sommatore aggiuntivo nella fase di MEM, nominata EX2 per questa istruzione, non si hanno conflitti con l’istruzione schedulata al colpo di clock successivo. L’istruzione viene eseguita in 5 colpi di clock, risparmiandone 1 rispetto alla sua scissione in 2 istruzioni. Non ci sono stalli o conflitti con istruzioni successive.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 9
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 4 – MAC R1,(R2),R3 Scrivere un microprogramma per l'istruzione MAC R1,(R2),R3 che in RTL significa R1<-R1+M[R2]*R3 per un MIPS-pipeline, discutere i conflitti e possibili soluzioni architetturali (non si prevede un’architettura tale da avere una ALU che svolge l’istruzione MADD). Equivale alla successione di queste operazioni assembly: LD R4, 0(R2) DMUL R4, R4, R3 DADD R1, R1, R4 Tale codice presenta uno stallo dopo l’istruzione di load per conflitto di dati, in quanto il registro operando della moltiplicazione è il registro destinazione della load, la quale al momento della fase exe dell’istruzione di moltiplicazione non ha ancora scritto in tale registro il valore prelevato dalla memoria. Non vi sono stalli tra la mul e la add se si considera la corto circuitazione dell’ALU. Conteggiamo quindi 4 istruzioni, che vengono eseguite in 5+(4-1) = 8 colpi di clock. IF IF/ID.IR Mem[PC]; IF/ID.NPC PC+4; ID ID/EX.IR IF/ID.IR; ID/EX.NPC IF/ID.NPC; ID/EX.A Regs[IF/ID.IR[rs]]; ID/EX.B Regs[IF/ID.IR[rt]]; ID/EX.Imm sign-extended(IF/ID.IR[immediate field]); La prima cosa da fare è accedere a memoria per caricare il dato dall’indirizzo contenuto in R2 (a cui non va sommato alcun immediato). Contemporaneamente, propaghiamo il valore di R3 (contenuto in B) nel latch EX/MEM ma utilizzando un altro registro chiamato B2: questo perché se l’istruzione schedulata un colpo di clock dopo questa è un’istruzione di store al termine della sua fase di EX (ovvero nel colpo di clock in cui la MAC è in fase di MEM) sovrascriverà il valore di EX/MEM.B con il suo rt ed il valore che poi verrà successivamente letto dalla MAC per l’operazione di moltiplicazione non sarà il valore di rt della MAC ma della store che le succede. EX1 EX/MEM.IR ID/EX.IR; EX/MEM.ALUOutput ID/EX.A; EX/MEM.B2 ID/EX.B; MEM MEM/WB.IR EX/MEM.IR; MEM/WB.LMD Mem[EX/MEM.ALUOutput]; Contemporaneamente all’operazione di moltiplicazione si preleva il terzo operando contenuto in R1. Questo porta ad avere in contemporanea con la fase di EX2 un’ulteriore fase di ID che creerebbe conflitti con l’istruzione schedulata tre colpi di clock dopo la MAC: a tal proposito è possibile potenziare l’accesso alla memoria registri in modo da avere più letture parallele.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 10
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
È importante inoltre che l’IR dell’istruzione continui a propagarsi nella pipeline, e quindi tale valore dovrà essere spostato da MEM/WB.IR in quanto tale latch ora ospiterà l’IR dell’istruzione schedulata successivamente quella di interesse. Dunque, salviamo l’IR in un nuovo latch che chiamiamo MEM/WB.IR2. EX2 MEM/WB.IR2 MEM/WB.IR; MEM/WB.ALUOutput2 MEM/WB.LMD * EX/MEM.B2; EX/MEM.B2 Regs[MEM/WB.IR[rd]]; } svolta nel secondo semiciclo Si aggiunge un MEM/WB.ALUOutput2. Erroneamente si può pensare che questo registro non serva poiché questo registro viene scritto dalle normali istruzioni solo nella fase di MEM e solo da istruzioni ALU; per creare conflitto esse devono avvenire contemporaneamente con la fase EX3 della MAC e quindi con le istruzioni schedulate 2 colpi di clock dopo la MAC. Queste però si troveranno in una situazione di stallo poiché cercheranno di usare la ALU nella loro fase EX che è già utilizzata per la moltiplicazione della MAC in EX2; quindi non si presenta la necessità di aggiungere un MEM/WB.ALUOutput2, sbagliando. Tale registro serve perché l’istruzione schedulata un colpo di clock dopo la MAC scriverà in EX/MEM.ALUOutput dopo la sua fase di EX, e quindi se si usa tale registro per contenere il prodotto e poi la somma al momento della fase EX2 si processerà un dato sbagliato. In sostanza, se non avete capito niente di ciò che è scritto qua, pensate solo che c’è una sovrascrittura su EX/MEM.ALUOutput se utilizziamo tale registro per fare il prodotto! EX3 MEM/WB.ALUOutput2 MEM/WB.ALUOutput2+ EX/MEM.B2; WB Regs[MEM/WB.IR2[rd]] MEM/WB.ALUOutput; L’istruzione viene eseguita in 7 colpi di clock, risparmiandone 1 rispetto alla sua scissione in 2 istruzioni. Ci sarà inevitabilmente uno stallo con l’istruzione schedulata due colpi di clock dopo la MAC a meno che non si inserisca nel progetto un moltiplicatore aggiuntivo, ma è uno spreco decisamente evitabile considerando la frequenza di utilizzo di un’istruzione di questo tipo. Inserendo un sommatore aggiuntivo nella fase EX3 si non si hanno conflitti con l’istruzione schedulata tre colpi di clock dopo.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 11
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 5 – SWP R1 R2 Scrivere un microprogramma per l'istruzione SWP R1 R2 che fa Mem[R1] = Mem[R2] per un MIPS-pipeline, discutere i conflitti e possibili soluzioni architetturali. Equivale alla successione di queste operazioni assembly: LD R3, 0(R2) SD 0(R1), R3 Tale listato presenta uno stallo, evitabile se si apporta una piccola modifica: si cortocircuita l’uscita della memoria MEM/WB.LMD in ingresso alla memoria stessa per avere nella fase di MEM della store un Mem[MEM/WB.ALUOutput] MEM/WB.LMD. Conteggiamo quindi 3 istruzioni, che vengono eseguite in 5+(2-1) = 6 colpi di clock. IF IF/ID.IR Mem[PC]; IF/ID.NPC PC+4; ID ID/EX.IR IF/ID.IR; ID/EX.NPC IF/ID.NPC; ID/EX.A Regs[IF/ID.IR[rs]]; ID/EX.B Regs[IF/ID.IR[rt]]; ID/EX.Imm sign-extended(IF/ID.IR[immediate field]); In realtà l’indirizzo a cui fare riferimento in memoria è già presente nei registri R2 ed R3 caricati nei latch ID/EX.A ed ID/EX.B nella fase di ID, dunque non è necessario sommare un immediato nullo. L’ALU non svolge alcuna operazione di somma e la fase EX si limita a propagare il valore di A e B rispettivamente nel latch EX/MEM.ALUOutput e EX/MEM.B. EX EX/MEM.IR ID/EX.IR; EX/MEM.ALUOutput ID/EX.A; EX/MEM.B ID/EX.B; Il registro B che contiene l’indirizzo in memoria in cui salvare il dato contenuto ora in ALUOutput dev’essere propagato anche in questa fase di MEM1, quindi è necessario aggiungere un altro registro B al latch MEM/WB. MEM1 MEM/WB.IR EX/MEM.IR; MEM/WB.LMD Mem[EX/MEM.ALUOutput]; MEM/WB.B EX/MEM.B; Nella seconda fase di MEM verrà eseguita la store del dato contenuto in LMD. Non è necessario propagare l’IR in quanto non si richiedono altre informazioni sugli operandi dell’istruzione. Supponendo che l’istruzione successiva alla SWP sia una load, questa scriverà nel registro MEM/WB.LMD durante la sua fase di MEM che verrà eseguita in contemporanea con questa fase di MEM2 che anch’essa usa MEM/WB.LMD: tale registro non sarà sovrascritto perché la SWP legge il suo contenuto nel primo semiciclo di clock mentre la LOAD scrive nel registro il valore che preleva in memoria nel secondo semiciclo di clock.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 12
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
MEM2 Mem[MEM/WB.B] MEM/WB.LMD; L’istruzione viene eseguita in 5 colpi di clock, risparmiandone 1 rispetto alla sua scissione in 2 istruzioni. Ci sarà inevitabilmente uno stallo con l’istruzione schedulata un colpo di clock dopo se questa istruzione è una load o una store che fa uso effettivo della memoria.
In alternativa, si poteva utilizzare al posto del nuovo registro MEM/WB.B lo stesso registro MEM/WB.ALUOutput: quando SWP è in fase MEM2 leggerà il contenuto di questo registro all’inizio del primo semiciclo e salverà in memoria LMD (a quell’indirizzo) per tutto il resto del ciclo di clock; se l’operazione successiva alla SWP fosse una ALU starebbe eseguendo la sua fase di MEM in cui ALUOutput viene propagato dai latch EX/MEM e MEM/WB, però MEM/WB.ALUOutput viene scritto solo nel secondo semiciclo. Quindi non c’è problema di sovrascrittura.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 13
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 6 – SWX R2 R31 R1 Scrivere un microprogramma per l'istruzione SWX R2 R31 R1 che fa Mem[R1+R31] = R2 per un MIPS-pipeline, discutere i conflitti e possibili soluzioni architetturali. Equivale alla successione di queste operazioni assembly: DADD R1, R1, R31 SD 0(R1), R2 Tale codice presenta non presenta stalli se si va a considerare la corto circuitazione dell’ALU. Conteggiamo quindi 2 istruzioni, che vengono eseguite in 5+(2-1) = 6 colpi di clock. IF IF/ID.IR Mem[PC]; IF/ID.NPC PC+4; ID ID/EX.IR IF/ID.IR; ID/EX.NPC IF/ID.NPC; ID/EX.A Regs[IF/ID.IR[rs]]; ID/EX.B Regs[IF/ID.IR[rt]]; ID/EX.Imm sign-extended(IF/ID.IR[immediate field]); Si può pensare di potenziare l’accesso alla memoria registri in modo tale da poter effettuare più letture in parallelo, in questo caso inserendo un’ulteriore fase di ID nella fase EX questa non andrà in conflitto con la fase ID processata contemporaneamente dal processore per l’istruzione schedulata un colpo di clock dopo. Si utilizza quindi il già presente registro EX/MEM.B. EX EX/MEM.IR ID/EX.IR; EX/MEM.ALUOutput ID/EX.A + ID/EX.Imm; EX/MEM.B Regs[IF/ID.IR[rd]]; MEM MEM/WB.IR EX/MEM.IR; Mem[EX/MEM.ALUOutput] EX/MEM.B; L’istruzione viene eseguita in 4 colpi di clock, risparmiandone 2 rispetto alla sua scissione in 2 istruzioni. Non vi sono stalli con istruzioni successive.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 14
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 7 – LL R6 (#100,R3) Scrivere un microprogramma per l'istruzione LL R6 (#100,R3) significa R6 Mem[Mem[100+R3]] per un MIPS-pipeline, discutere i conflitti e possibili soluzioni architetturali. Equivale alla successione di queste operazioni assembly: LD R1, 100(R3) LD R6 , 0(R1) Tale listato presenta uno stallo, evitabile se si apporta una piccola modifica: si cortocircuita l’uscita della memoria MEM/WB.LMD in ingresso alla memoria stessa per avere nella fase di MEM della seconda load un MEM/WB.LMD Mem[MEM/WB.LMD]. Conteggiamo quindi 2 istruzioni, che vengono eseguite in 5+(2-1) = 6 colpi di clock. IF IF/ID.IR Mem[PC]; IF/ID.NPC PC+4; ID ID/EX.IR IF/ID.IR; ID/EX.NPC IF/ID.NPC; ID/EX.A Regs[IF/ID.IR[rs]]; ID/EX.B Regs[IF/ID.IR[rt]]; ID/EX.Imm sign-extended(IF/ID.IR[immediate field]); EX EX/MEM.IR ID/EX.IR; EX/MEM.ALUOutput ID/EX.A + ID/EX.Imm; MEM1 MEM/WB.IR EX/MEM.IR; MEM/WB.LMD Mem[EX/MEM.ALUOutput]; MEM2 MEM/WB.LMD Mem[MEM/WB.LMD]; WB Regs[MEM/WB.IR2[rt]] MEM/WB.LMD; L’istruzione viene eseguita in 6 colpi di clock, senza alcun risparmio rispetto alla sua scissione in 2 istruzioni. Ci sarà uno stallo con l’istruzione successiva qualsiasi essa sia (tranne i salti) perché verranno contemporaneamente eseguite le fasi MEM e WB delle due istruzioni, e questo ci permette di non utilizzare registri aggiuntivi quali IR2 o LMD2. Mi sa tanto che conviene usare due operazioni al posto di una!!
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 15
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 8 – SL (#100,R3) R6 Scrivere un microprogramma per l'istruzione SL (#100,R3) R6 significa Mem[Mem[100+R3]] R6 per un MIPS-pipeline, discutere i conflitti e possibili soluzioni architetturali. Equivale alla successione di queste operazioni assembly: LD R1, 100(R3) SD 0(R1), R6 Tale listato presenta uno stallo, evitabile se si apporta una piccola modifica: si cortocircuita l’uscita della memoria MEM/WB.LMD in ingresso alla memoria stessa per avere nella fase di MEM della store un Mem[MEM/WB.LMD] MEM/WB.B. Conteggiamo quindi 2 istruzioni, che vengono eseguite in 5+(2-1) = 6 colpi di clock. IF IF/ID.IR Mem[PC]; IF/ID.NPC PC+4; ID ID/EX.IR IF/ID.IR; ID/EX.NPC IF/ID.NPC; ID/EX.A Regs[IF/ID.IR[rs]]; ID/EX.B Regs[IF/ID.IR[rt]]; ID/EX.Imm sign-extended(IF/ID.IR[immediate field]); EX EX/MEM.IR ID/EX.IR; EX/MEM.ALUOutput ID/EX.A + ID/EX.Imm; EX/MEM.B ID/EX.B MEM1 MEM/WB.IR EX/MEM.IR; MEM/WB.LMD Mem[EX/MEM.ALUOutput]; MEM/WB. ALUOutput EX/MEM.B; MEM2 Mem[MEM/WB.LMD] MEM/WB.ALUOutput; L’istruzione viene eseguita in 5 colpi di clock, risparmiandone 1 rispetto alla sua scissione in 2 istruzioni. Ci sarà uno stallo se l’istruzione che la segue è una load/store che fa uso effettivo della memoria; dunque l’utilizzo del registro MEM/WB .LMD nella fase MEM2 non crea problemi poiché l’unica istruzione che ne fa uso è la load, che in questo caso verrà stallata.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 16
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 9 – SWPM R1 R2 Scrivere un microprogramma per l'istruzione SWPM R1 R2 significa Mem[R1]Mem[R2] per un MIPS-pipeline, discutere i conflitti e possibili soluzioni architetturali. Equivale alla successione di queste operazioni assembly: LD R3, 0(R1) LD R4, 0(R2) SD 0(R2), R3 SD 0(R1), R4 Non ci sono stalli. Conteggiamo quindi 4 istruzioni, che vengono eseguite in 5+(4-1) = 8 colpi di clock. IF IF/ID.IR Mem[PC]; IF/ID.NPC PC+4; ID ID/EX.IR IF/ID.IR; ID/EX.NPC IF/ID.NPC; ID/EX.A Regs[IF/ID.IR[rs]]; ID/EX.B Regs[IF/ID.IR[rt]]; ID/EX.Imm sign-extended(IF/ID.IR[immediate field]); Propaghiamo il valore di A e B aggiungendo il registro A al latch EX/MEM. Non utilizziamo EX/MEM.ALUOutput perché poi il valore di A servirà nelle fasi successive. EX EX/MEM.IR ID/EX.IR; EX/MEM.A ID/EX.A; EX/MEM.B ID/EX.B; Usiamo un altro registro chiamato MEM/WB.ALUOutput2 per non avere problemi di sovrascrittura con istruzioni ALU successive che faranno uso di questo registro. MEM/WB.LMD invece è liberamente utilizzabile, perché l’unica operazione che lo usa è la LOAD e questa si stallerà se segue la nostra istruzione in quanto verranno eseguite contemporaneamente due fasi MEM. MEM1 MEM/WB.IR EX/MEM.IR; MEM/WB.LMD Mem[EX/MEM.A]; MEM/WB. ALUOutput2 EX/MEM.B; MEM/WB.A EX/MEM.A; Si sarebbe anche potuto cortocircuitare lo stesso EX/MEM.A, ma tralasciamo ed aggiungiamo il registro anche a MEM/WB. Non è più necessario propagare l’IR perché non dovremo più fare accessi alla memoria registri, visto che abbiamo propagato i valori di rs ed rt rispettivamente in MEM/WB.A e MEM/WB.ALUOutput2. Aggiungiamo il registro LMD2 al latch MEM/WB per salvare il contenuto della cella di memoria indirizzata al valore di rs.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 17
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
MEM2 MEM/WB.LMD Mem[MEM/WB.ALUOutput]; MEM/WB. LMD2 EX/MEM.LMD; Non vi è sovrascrittura perché la fase di mem dura tutto il colpo di clock, all’inizio viene letto il valore di LMD e al secondo semiciclo del clock viene scritto tale valore in LMD2; nel frattempo, LMD potrà tranquillamente essere sovrascritto da ciò che troviamo in memoria all’indirizzo rt. Ricapitolando, ora abbiamo in MEM/WB.LMD ciò che si trova in memoria all’indirizzo rt ed in MEM/WB.LMD2 ciò che si trova in memoria all’indirizzo rs. Il valore di rs è salvato in MEM/WB.A ed il valore di rt è salvato in MEM/WB.ALUOutput. MEM3 Mem[MEM/WB.A]MEM/WB.LMD; MEM4 Mem[EX/MEM.ALUOutput] MEM/WB. LMD2; L’istruzione viene eseguita in 7 colpi di clock, risparmiandone 1 rispetto alla sua scissione in 4 istruzioni. Ci saranno stalli con le prossime tre istruzioni solo se queste sono istruzioni LOAD/STORE, ovvero che fanno uso effettivo della memoria.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 18
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZI ASSEMBLY
ESERCIZI ASSEMBLY
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 19
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 1 – SOMMA DI DUE VETTORI Somma di due vettori in un terzo vettore con processore scalare pipeline MIPS. Si vuole scrivere un programma assembly per un processore MIPS scalare pipeline che sommi due vettori di dati double contenuti in memoria e salvi il risultato in un terzo vettore. Siano A, B e C vettori di N elementi, l’operazione da svolgere è: for(i=0; i<N; i++) { C[i] = A[i] + B[i]; } Il primo risparmio lo si può pensare sui registri: l’utilizzo di un unico registro come indice che scorre all’interno del vettore man mano che vengono svolte le somme riduce il numero di registri in gioco. Si ipotizza dunque di conoscere le locazioni in memoria dei tre vettori, cioè le locazioni in memoria dei primi elementi dei tre vettori: supponiamo A*0+ all’indirizzo 1000, B*0+ all’indirizzo 2000 e C*0+ all’indirizzo 3000.
Utilizziamo il registro R1 come indice, il quale dovrà essere incrementato di 8 (operiamo su vettori double) ad ogni iterazione. In realtà, se si pensa di inizializzare R1 al valore dell’ultimo elemento del vettore, è possibile usare una BGEZ su R1 come condizione per il loop, così che se è verificata (se R1 è maggiore o uguale a 0) si salta all’inizio del loop. In questo modo R1 dovrà essere decrementato di 8 ad ogni iterazione. R1 dovrà dunque essere inizializzato al valore (N-1)*8, essendo questo il valore occupato in memoria da ciascuno dei tre vettori. Dunque le prime tre istruzioni serviranno ad inizializzare il valore di R1 e saranno operazioni esterne al loop.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 20
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
DADDI R1, R0, N DADDI R1, R1, #-1 DMULI R1, R1, #8 Successivamente, scriviamo il loop. All’inizio del loop mettiamo l’etichetta loop per identificare la prima operazioni ove si dovrà saltare se verificata la condizione di salto. Le prime due operazioni saranno due load per caricare gli elementi dei vettori dalla memoria nei registri: supponiamo R2 sia destinato a contenere A ed R3 sia destinato a contenere B. loop: LD R2, R1(1000) LD R3, R1(2000) Procediamo con la somma dei due elementi. Potremmo utilizzare il registro R4 per contenere C, ma risulterebbe un’inutile spreco di registri in quanto sia R2 che R3 non saranno più utilizzati nel corso dell’iterazione. Scegliamo dunque di salvare C in R2. DADDI R2, R2, R3 Salviamo C in memoria. SD R1(3000), R2 Procediamo con il decremento dell’indice di 8 e con la condizione di salto. DADDI R1, R1, #-8 BGEZ R1, loop Il programma in assembly risulta essere:
DADDI R1, R0, N DADDI R1, R1, #-1 DMULI R1, R1, #8
loop: LD R2, R1(1000) LD R3, R1(2000) DADDI R2, R2, R3 SD R1(3000), R2 DADDI R1, R1, #-8 BGEZ R1, loop
Tale listato è decisamente inaccettabile, in quanto ci saranno numerosi stalli. Supponendo che il nostro processore abbia già le modifiche necessarie alla cortocircuitazione dell’ALU, e un sommatore aggiuntivo per effettuare il calcolo del PC dove saltare dopo un’istruzione di brench/jump perdendo solo un colpo di clock, la situazione è la seguente:
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 21
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Calcoliamo in quanti colpi di clock viene eseguito questo programma in pipeline. Le istruzioni all’interno del loop sono 6 più 3 stalli, cioè 9 istruzioni. L’esecuzione impiegherà: Numero di colpi di clock per eseguire 1 istruzione + (numero di istruzioni -1) = 5 + (9-1) = 13 colpi di clock. Questi 13 colpi di clock valgono per’un'unica istruzione. Considerando il loop, le 9 istruzioni dovranno essere moltiplicate per il numero di iterazioni, cioè N. Quindi ((9*N)-1)+5. A questi, andranno sommati i colpi di clock necessari per eseguire le tre istruzioni precedenti il loop: Numero di colpi di clock per eseguire 1 istruzione + (Numero di istruzioni precedenti il loop – 1) + 1 istruzione (la prima del loop) - Numero di colpi di clock per eseguire 1 istruzione = = 5 + (3-1) – 5 + 1 = 3 Supponendo vettori di 10 elementi, il programma impiega 3 + 5 + (9*10)-1) = 97 colpi di clock per essere eseguito.
Per ottimizzare il programma è quindi necessario spostare alcune istruzioni utilizzando la tecnica del delay slot. Spostiamo il decremento dell’indice dopo la seconda load, in questo modo anche lo stallo che segue quest’istruzione viene eliminato. Spostiamo inoltre la store dopo la bnez, con l’accortezza di cambiare l’indirizzo da sommare all’indice R1, in quanto R1 è già stato decrementato di 8: dunque, per ottenere lo stesso indirizzo di memoria, si incrementa di 8 l'indirizzo nella store
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 22
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
DADDI R1, R0, N DADDI R1, R1, #-1 DMULI R1, R1, #8
loop: LD R2, R1(1000) LD R3, R1(2000) DADDI R1, R1, #-8 DADDI R2, R2, R3 BGEZ R1, loop SD R1(3008), R2
Il loop viene eseguito in 5 + (6 -1) = 10 colpi di clock, quindi supponendo vettori di 10 elementi, il programma viene eseguito in 3 + 5 + ((6*10)-1) = 67 colpi di clock, 30 in meno rispetto a quelli utilizzati per processare il listato con gli stalli.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 23
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 2 – MEDIA DI UN VETTORE Scrivere la procedura che calcoli la media di un vettore di dimensione N. Suppongo che il vettore A sia contenuto in memoria a partire dall’indirizzo 1000 e alla procedura viene passato questo indirizzo e la dimensione N del vettore che viene considerato come un immediato nel listato. Utilizzo il registro R1 come indice, per contenere la dimensione del vettore in byte e poter scorrere ogni elemento. Utilizzo R2 come registro per contenere la somma degli elementi del vettore, valore che poi verrà restituito dalla procedura (non si richiede una store in memoria). Utilizzo R3 come registro temporaneo per caricare da memoria ogni elemento del vettore A.
DADDI R1, R0, #N DADDI R1, R1, #-1 DMULI R1, R1, #8 DADDI R2, R0, #0
loop: LD R3, R1(1000) DADD R2, R2, R3 DADDI R1, R1, #-8 BGEZ R1, loop DDIVI R2, R2, #N // NB: la DDIVI mi sa che non esiste Analizziamo gli stalli (ipotizzando che il processore abbia già le modifiche per la corto circuitazione dell’ALU).
DADDI R1, R0, #N DADDI R1, R1, #-1 DMULI R1, R1, #8 DADDI R2, R0, #0
loop: LD R3, R1(1000) stallo DADD R2, R2, R3 DADDI R1, R1, #-8 stallo BGEZ R1, loop stallo DDIVI R2, R2, #N Il primo stallo si ha perché uno degli operandi della DADD (R3) è registro di destinazione dell’operazione di load precedente. Il corretto valore di R3 lo si avrà solo quando questo sarà stato salvato in MEM/WB.LMD, quindi dopo la fase di MEM, mentre la somma successiva viene eseguita nella fase di EXE, che non avrà ancora il valore di R3. Il secondo stallo si ha perché il registro su cui verificare la condizione di branch è destinazione dell’operazione precedente, che sarà disponibile in EX/MEM.ALUOutput solo dopo la fase di EX; contemporaneamente la branch starà eseguendo la ID, fase in cui si verifica la condizione e si calcola il nuovo PC ove saltare. Il terzo stallo si verifica in quanto è possibile scoprire dove saltare solo dopo la fase di ID della branch, quindi al secondo colpo di clock; intanto sarà partita l’istruzione successiva che, se il salto si verifica, dovrà essere abortita. Quindi c’è uno stallo.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 24
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Supponendo un vettore di 10 elementi il programma viene eseguito in: loop (5+(7*10)-1)) = 74 colpi di clock 74 + 5 istuzioni fuori dal loop = 79 colpi di clock Per ottimizzare il programma è quindi necessario spostare alcune istruzioni utilizzando la tecnica del delay slot.
DADDI R1, R0, #N DADDI R1, R1, #-1 DMULI R1, R1, #8 DADDI R2, R0, #0 LD R3, R1(1000)
loop: DADDI R1, R1, #-8 DADD R2, R2, R3 BGEZ R1, loop LD R3, R1(1000) DDIVI R2, R2, #N
Supponendo un vettore di 10 elementi il programma viene eseguito in: loop (5+(4*10)-1)) = 44 colpi di clock 44 + 6 istuzioni fuori dal loop = 50 colpi di clock Si noti che dopo l’ultima iterazione, l’operazione di LOAD verrà comunque eseguita e verrà caricato in R3 un valore di memoria non interessante ai fini del programma. Questo, in ogni caso, non comporta gravi errori. Altrimenti, si può abortire l’operazione di load se il salto non si verifica.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 25
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 3 – MINIMO DI UN VETTORE Scrivere la procedura che calcoli l’elemento minimo di un vettore di dimensione N. Suppongo che il vettore A sia contenuto in memoria a partire dall’indirizzo 1000 e alla procedura viene passato questo indirizzo e la dimensione N del vettore che viene considerato come un immediato nel listato. Utilizzo il registro R1 come indice, per contenere la dimensione del vettore in byte e poter scorrere ogni elemento. Utilizzo R2 come registro per contenere l’elemento più piccolo del vettore, valore che poi verrà restituito dalla procedura (non si richiede una store in memoria). Utilizzo R3 come registro temporaneo per caricare da memoria ogni elemento del vettore A. Utilizzo R4 come registro temporaneo per la sottrazione tra l’elemento i-esimo del vettore A con il minimo memorizzato nel registro R2. Tale operazione è utile al fine di verificare se l’elemento i-esimo è più piccolo dell’elemento finora considerato minimo.
DADDI R1, R0, #N DADDI R1, R1, #-1 DMULI R1, R1, #8
LD R2, R1(1000) loop: LD R3, R1(1000) DSUB R4, R3, R2
DADDI R1, R1, #-8 BGEZ R4, if DADDI R2, R3, #0
if: BGEZ R1, loop Analizziamo gli stalli (ipotizzando che il processore abbia già le modifiche per la corto circuitazione dell’ALU).
DADDI R1, R0, #N DADDI R1, R1, #-1 DMULI R1, R1, #8
LD R2, R1(1000) loop: LD R3, R1(1000) stallo DSUB R4, R3, R2
DADDI R1, R1, #-8 BGEZ R4, if stallo DADDI R2, R3, #0
if: BGEZ R1, loop stallo Il primo stallo si ha perché uno degli operandi della DSUB (R3) è registro di destinazione dell’operazione di load precedente. Il corretto valore di R3 lo si avrà solo quando questo sarà stato salvato in MEM/WB.LMD, quindi dopo la fase di MEM, mentre la somma successiva viene eseguita nella fase di EXE, che non avrà ancora il valore di R3. Il secondo ed il terzo stallo si verificano in quanto è possibile scoprire dove saltare solo dopo la fase di ID della branch, quindi al secondo colpo di clock; intanto sarà partita l’istruzione successiva che, se il salto si verifica, dovrà essere abortita.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 26
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Supponendo un vettore di 10 elementi, possiamo scindere il calcolo dei colpi di clock in due casi:
best case quando il valore minimo del vettore è l’ultimo elemento (e quindi viene schedulato per primo) e i restanti elementi sono tutti maggiori o uguali al primo: in questo caso si risparmia un’istruzione in quanto il branch BGEZ R4, if sarà sempre verificato;
worste case quando il valore minimo del vettore è il primo elemento (e quindi viene schedulato per ultimo) e i restanti elementi sono posizionati nel vettore in ordine decrescente, cosicché ad ogni iterazione l’i-esimo elemento verrà sempre considerato come elemento minimo ed il branch BGEZ R4, if non sarà mai verificato, eseguendo anche l’istruzione DADDI R2, R3, #0 di scambio dei registri.
BEST CASE 8 istruzioni per ogni loop. 5 + (8*10) -1 = 84 colpi di clock + 4 istruzioni fuori dal loop = 88 colpi di clock. WORSTE CASE 8 istruzioni alla prima iterazione (l’ultimo elemento di A è già caricato in R2 prima del loop) e 9 istruzioni per il resto delle iterazioni. 5 + 8 + (9*9)-1 = 93 colpi di clock + 4 istruzioni fuori dal loop = 97 colpi di clock. Per ottimizzare il programma è quindi necessario spostare alcune istruzioni utilizzando la tecnica del delay slot.
DADDI R1, R0, #N DADDI R1, R1, #-1 DMULI R1, R1, #8
LD R2, R1(1000) stallo DADDI R3, R2, #0 loop: DSUB R4, R3, R2
DADDI R1, R1, #-8 BGEZ R4, if DADDI R2, R3, #0
if: BGEZ R1, loop LD R3, R1(1000)
Nello spostare la load nel delay slot dopo l’ultima branch e duplicandola prima del loop, si è preferito utilizzare una DADDI per copiare il valore di R2 in R3 in quanto l’elemento è già stato caricato in memoria. Non è possibile riempire il delay slot dopo la LD R2, R1(1000), ma essendo uno stallo fuori dal loop non la si ritiene una grave perdita di prestazioni. È importante ricordarsi che:
spostando la DADDI R2, R3, #0 nel delay slot dopo la BGEZ R4, if tale istruzione dev’essere abortita nel caso il salto si verifichi;
spostando la LD R3, R1(1000) nel delay slot dopo la BGEZ R1, loop tale istruzione dev’essere abortita nel caso il salto non si verifichi.
Supponendo un vettore di 10 elementi il programma viene eseguito in: BEST CASE = WORSTE CASE i due casi si riducono ad un unico caso in quanto le istruzioni verranno sempre e comunque eseguite tutte, ma alcune verranno abortite nei casi precedentemente illustrati. 6 istruzioni per ogni loop. 5 + (6*10) – 1 = 64 colpi di clock + 6 istruzioni fuori dal loop = 70 colpi di clock.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 27
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Alternativamente, si può procedere in questo modo. Invece di settare R2 (valore massimo) pari al primo elemento schedulato, prima di entrare nel loop, lo si pone uguale al massimo numero rappresentabile con un registro a 64 bit. Considerando la notazione del complemento a due per i numeri negativi, c’è da scartare il primo bit che è il bit di segno. Dunque, con 64 bit a disposizione, il numero maggiore rappresentabile è: 264-1-1= 9223372036854775807. Assumiamo MAX=264-1-1 come un valore immediato.
DADDI R1, R0, #N DADDI R1, R1, #-1 DMULI R1, R1, #8
LD R3, R1(1000) DADDI R2, R0, #MAX loop: DSUB R4, R3, R2
DADDI R1, R1, #-8 BGEZ R4, if DADDI R2, R3, #0
if: BGEZ R1, loop LD R3, R1(1000) Con questa soluzione, il programma viene eseguito in: 6 istruzioni per ogni loop. 5 + (6*10) – 1 = 64 colpi di clock + 5 istruzioni fuori dal loop = 69 colpi di clock.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 28
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 4 – LOAD DOUBLE NON ALLINEATA Scrivere la procedura che esegua una LOAD double non allineata. Si vuole scrivere una procedura che carichi da memoria un dato double da 64 bit il cui indirizzo non è multiplo di 8. Il caricamento dei dati da memoria a registro o da registro a memoria avviene a blocchi di 64 bit (8 byte) a partire da indirizzi che sono sempre divisibili per 8. In questo caso, si vuole caricare un dato che è contenuto in due blocchi di memoria, allineandolo successivamente poi in un unico registro. Supponiamo che il dato si trovi all’indirizzo di partenza IND passato come parametro alla routine. La prima cosa da fare è verificare effettivamente se questo indirizzo non è il primo di un blocco da 64 che può essere caricato in un registro con una semplice LOAD. Questa caratteristica imporrà all’indirizzo, nel caso sia il primo di un blocco allineato, di essere divisibile per 8. Se non lo è, ovviamente, procediamo con la routine. Tale verifica è eseguibile semplicemente osservando gli ultimi tre bit dell’indirizzo. Se questi sono uguali a zero allora il numero sarà divisibile per 8. Dunque, sarà sufficiente mettere l’indirizzo in AND con il numero binario 7 (111) e verificare se tale risultato è uguale a zero: se lo è, si esce dalla routine e si passa al processo principale; altrimenti, si esegue la load non allineata. Dopo la and bisognerà fare la condizione su R1 per vedere se è uguale a zero. Se lo è, la routine termina. Quindi, prima di far terminare la routine, è necessario aver fatto la load del double nel caso il dato sia allineato. L’indirizzo di partenza non dovrà essere IND, ma IND – R1 essendo R1 lo scostamento dall’indirizzo XXX000 che è il primo del blocco da 64 bit che vogliamo caricare. ANDI R1, IND, #7 DSUB IND, IND, R1 LD R2, #0(IND) BEQZ R1, end Continuando la routine, carichiamo l’altro blocco da 8 byte (8 byte = 64 bit!). LD R3, #8(IND) Caricati I due dati da 8 byte in due registri diversi, bisognerà ora fare lo shift di questi dati rispettivamente verso sinistra per il primo registro R2 e verso destra per il secondo registro R3 per poi infine fare la OR tra i due registri.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 29
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
R2 lo shifteremo di tanti posti quanto è lo scostamento R1 moltiplicato per 8 bit (quindi R1 byte per 8 bit). R3 lo shifteremo di tanti posti quanto è lo scostamento 8 byte – R1 moltiplicato per 8 bit (quindi R1 byte per 8 bit). Infine, si procede con l’OR tra i due registri.
DMULT R4, R1, #8 DSLLV R2, R2, R4 DADDI R4, R0, #8 DSUB R1, R4, R1 DMULT R4, R1, #8 DSRLV R3, R3, R1 OR R2, R2, R3 end Il listato completo è: ANDI R1, IND, #7 DSUB IND, IND, R1 LD R2, #0(IND) BEQZ R1, end LD R3, #8(IND) DMULT R4, R1, #8 DSLLV R2, R2, R4 DADDI R4, R0, #8 DSUB R1, R4, R1 DMULT R4, R1, #8 DSRLV R3, R3, R1 OR R2, R2, R3 End L’unico stallo è quello solito presente dopo la BEQZ, eliminabile spostando la LD R3, #8(IND) nel delay slot. Ovviamente, se la condizione si verifica tale operazione dev’essere abortita. Il programma viene eseguito (considerando il caso in cui la load non sia allineata) in: 12 istruzioni. 5 + (12 – 1) = 16 colpi di clock.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 30
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 5 – STORE DOUBLE NON ALLINEATA Scrivere la procedura che esegua una STORE double non allineata. Si vuole scrivere una procedura che salvi un dato double da 64 in memoria ad un indirizzo che non è multiplo di 8.
Supponiamo il che il dato da voler scrivere in memoria si trovi nel registro R10 e che la locazione in memoria ove scriverlo, all’indirizzo IND, sia passata come parametro alla routine. ANDI R1, IND, #7 DSUB IND, IND, R1 BEQZ R1, end SD #0(IND), R11 Lo stallo dovuto alla BEQZ viene riempito con la store. Nel caso la BEQZ sia verificata, e l’indirizzo IND sia già allineato in memoria, allora questa store deve essere eseguita; nel caso in cui invece la BEQZ non è verificata e l’indirizzo IND non è un multiplo di 8, questa store deve essere abortita con la perdita di un colpo di clock. Non volendo sovrascrivere il contenuto degli altri indirizzi non interessati alla store, ma che comunque fanno parte dei due blocchi da 64 bit in cui la store dovrà operare, è necessario andare a caricare nei registri tali valori e porli infine in OR con il dato da voler salvare, opportunamente shiftato. Avremo dunque bisogno, oltre che del registro R10 che contiene il dato, la sua copia nel registro R11, in modo tale da shiftare R10 verso destra (parte alta del dato) ed R11 verso sinistra (parte bassa del dato). Saranno questi i registri da porre in OR con R2 ed R3. LD R2, #0(IND) LD R3, #8(IND) Copiamo R10 in R11. DADD R11, R10, R0
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 31
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Shift di R10 verso destra. DMULT R4, R1, #8 DSRLV R10, R0, R4 Shift di R11 verso sinistra. DADDI R4, R0, #8 DSUB R1, R4, R1 DMULT R4, R1, #8 DSLLV R11, R11, R1 OR logico. OR R2, R2, R10 OR R3, R3, R10 Store dei dati. SD #0(IND), R2 SD #8(IND), R3 end Il listato completo è: ANDI R1, IND, #7 DSUB IND, IND, R1 BEQZ R1, end SD #0(IND), R11 LD R2, #0(IND) LD R3, #8(IND) DADD R11, R10, R0 DMULT R4, R1, #8 DSRLV R10, R0, R4 DADDI R4, R0, #8 DSUB R1, R4, R1 DMULT R4, R1, #8 DSLLV R11, R11, R1 OR R2, R2, R10 OR R3, R3, R10 SD #0(IND), R2 SD #8(IND), R3 end Il programma viene eseguito (considerando il caso in cui la store non sia allineata) in: 17 istruzioni. 5 + (17 – 1) = 21 colpi di clock.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 32
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 6 – SOMMA DI VETTORI – PIPELINE DA PROGRAMMA Somma di vettori con il metodo della pipeline da programma. Suppongo che l'indirizzo del primo elemento del vettore A sia 1000, l'indirizzo del primo elemento del vettore B sia 2000, l'indirizzo del primo elemento del vettore C sia 3000. Suppongo che in R1 mi venga passato come parametro alla procedura la dimensione del vettore che userò come indice (dal fondo verso la testa del vettore). Uso R2 ed R3 per salvare gli i-esimi elementi del vettore. Uso R4 ed R5 per salvare gli i-esimi – 1 elementi del vettore (partiamo dalla coda). Uso R6 per salvare gli i-esimi elementi della somma tra i vettori. Uso R7 per salvare gli i-esimi – 1 elementi della somma tra i vettori. Uso R8 come condizione sul branch ponendolo uguale a 8. Quando l’indice arriva a 8 devo uscire dal loop.
DADDI R8,R0, #8 // pongo R8 = 8 DADDI R1, R1, #-1 // mi posiziono all’ultimo elemento (N-1)x8byte DMULI R1, R1, #8 LD R2, R1(1000) // riempimento LD R3, R1(2000) LD R4, R1(992) LD R5, R1(1992) DADD R6, R2, R3
loop: LD R2, R1(984) LD R3, R1(1984) DADD R7,R4,R5 DADDI R4, R2, #0 // scambio dei registri DADDI R5, R3, #0 SD R1(3000), R6 DADDI R6, R7, #0 DADDI R1, R1, #-8 // decremento l'indice BNE R1, R8, loop DADD R7, R4, R5 // svuotamento SD 0(3008), R6 SD 0(3000), R7
Come è facile notare, e come era prevedibile dalla pipeline da programma, non ci sono stalli per via di conflitti di dato. Si considera sempre la corto circuitazione dell’ALU per DADDI R1, R1, #-1 DMULI R1, R1, #8
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 33
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ALGORITMO DI TOMASULO
ESERCIZI ALGORITMO TOMASULO
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 34
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 1 Si consideri una CPU con le seguenti unità funzionali:
- 3 Sommatori con latenza di 2 colpi di clock; - 2 Moltiplicatori con latenza di 4 colpi di clock sia per la moltiplicazione che per la divisione; - 3 Accessi a memoria con latenza di 2 colpi di clock.
Eseguire colpo di clock dopo colpo di clock l’algoritmo di Tomasulo per il seguente programma:
LD F6 0+ R1
LD F8 2+ R2
MULTD F4 F8 F2
DIVD F8 F8 F0
ADDD F10 F10 F4
SUBD F2 F8 F0
CLOCK 1
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address
LD F6 0+ R1 1 Load1 Yes 0+R1
LD F8 2+ R2 Load2 No
MULTD F4 F8 F2 Load3 No
DIVD F8 F8 F0
ADDD F10 F10 F4
SUBD F2 F8 F0
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
Add1 No
Add2 No
Add3 No
Mult1 No
Mult2 No
Register result status:
Clock F0 F2 F4 F6 F8 F10 F12 ...1 FU Load1
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 35
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CLOCK 2
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address
LD F6 0+ R1 1 Load1 Yes 0+R1
LD F8 2+ R2 2 Load2 Yes 2+R2
MULTD F4 F8 F2 Load3 No
DIVD F8 F8 F0
ADDD F10 F10 F4
SUBD F2 F8 F0
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
Add1 No
Add2 No
Add3 No
Mult1 No
Mult2 No
Register result status:
Clock F0 F2 F4 F6 F8 F10 F12 ...2 FU Load1 Load2
CLOCK 3
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address
LD F6 0+ R1 1 3 Load1 Yes 0+R1
LD F8 2+ R2 2 Load2 Yes 2+R2
MULTD F4 F8 F2 3 Load3 No
DIVD F8 F8 F0
ADDD F10 F10 F4
SUBD F2 F8 F0
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
Add1 No
Add2 No
Add3 No
Mult1 Yes MULTD R(F2) Load2
Mult2 No
Register result status:
Clock F0 F2 F4 F6 F8 F10 F12 ...3 FU Load1 Load2
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 36
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address
LD F6 0+ R1 1 3 4 Load1 No
LD F8 2+ R2 2 4 Load2 Yes 2+R2
MULTD F4 F8 F2 3 Load3 No
DIVD F8 F8 F0 4
ADDD F10 F10 F4
SUBD F2 F8 F0
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
Add1 No
Add2 No
Add3 No
Mult1 Yes MULTD R(F2) Load2
Mult2 Yes DIVD R(F0) Load2
Register result status:
Clock F0 F2 F4 F6 F8 F10 F12 ...4 FU Mult1 M(A1) Load2
CLOCK 4: Al monitor dei registri rimane sempre Load2 su F8, perché effettivamente F8 non è ancora
disponibile; al colpo di clock successivo F8 sarà disponibile, e dal CDB va direttamente alle unità funzionali per far si che possono essere eseguite sia la MULTD che la DIVD; quindi queste due operazioni partiranno CONTEMPORANEAMENTE. Per cui il monitor dei registri viene aggiornato al cc successivo con F8: MULTD
CLOCK 5:
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address
LD F6 0+ R1 1 3 4 Load1 No
LD F8 2+ R2 2 4 5 Load2 No
MULTD F4 F8 F2 3 Load3 No
DIVD F8 F8 F0 4
ADDD F10 F10 F4 5
SUBD F2 F8 F0
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
Add1 Yes ADDD R(F10) Mult1
Add2 No
Add3 No
4 Mult1 Yes MULTD F8 dal CDB R(F2)
4 Mult2 Yes DIVD F8 dal CDB R(F0)
Register result status:
Clock F0 F2 F4 F6 F8 F10 F125 FU Mult1 M(A1) Mult2 Add1
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 37
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CLOCK 6:
CLOCK 7-8: situazione invariata, decrementati i valori della colonna time
CLOCK 9:
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address
LD F6 0+ R1 1 3 4 Load1 No
LD F8 2+ R2 2 4 5 Load2 No
MULTD F4 F8 F2 3 Load3 No
DIVD F8 F8 F0 4
ADDD F10 F10 F4 5
SUBD F2 F8 F0 6
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
Add1 Yes ADDD R(F10) Mult1
Add2 Yes SUBD R(F0) Mult2
Add3 No
3 Mult1 Yes MULTD F8 dal CDB R(F2)
3 Mult2 Yes DIVD F8 dal CDB R(F0)
Register result status:
Clock F0 F2 F4 F6 F8 F10 F126 FU Add2 Mult1 M(A1) Mult2 Add1
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address
LD F6 0+ R1 1 3 4 Load1 No
LD F8 2+ R2 2 4 5 Load2 No
MULTD F4 F8 F2 3 9 Load3 No
DIVD F8 F8 F0 4 9
ADDD F10 F10 F4 5
SUBD F2 F8 F0 6
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
Add1 Yes ADDD R(F10) Mult1
Add2 Yes SUBD R(F0) Mult2
Add3 No
0 Mult1 Yes MULTD F8 dal CDB R(F2)
0 Mult2 Yes DIVD F8 dal CDB R(F0)
Register result status:
Clock F0 F2 F4 F6 F8 F10 F129 FU Add2 Mult1 M(A1) Mult2 Add1
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 38
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CLOCK 10:
CLOCK 11: situazione invariata, decrementati i valori della colonna time
CLOCK 12:
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address
LD F6 0+ R1 1 3 4 Load1 No
LD F8 2+ R2 2 4 5 Load2 No
MULTD F4 F8 F2 3 9 10 Load3 No
DIVD F8 F8 F0 4 9 10
ADDD F10 F10 F4 5
SUBD F2 F8 F0 6
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
2 Add1 Yes ADDD R(F10) M(A3)
2 Add2 Yes SUBD M(A4) R(F0)
Add3 No
Mult1 No
Mult2 No
Register result status:
Clock F0 F2 F4 F6 F8 F10 F1210 FU Add2 M(A3) M(A1) M(A4) Add1
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address
LD F6 0+ R1 1 3 4 Load1 No
LD F8 2+ R2 2 4 5 Load2 No
MULTD F4 F8 F2 3 9 10 Load3 No
DIVD F8 F8 F0 4 9 10
ADDD F10 F10 F4 5 12
SUBD F2 F8 F0 6 12
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
0 Add1 Yes ADDD R(F10) M(A3)
0 Add2 Yes SUBD M(A4) R(F0)
Add3 No
Mult1 No
Mult2 No
Register result status:
Clock F0 F2 F4 F6 F8 F10 F1212 FU Add2 M(A3) M(A1) M(A4) Add1
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 39
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CLOCK 13:
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address
LD F6 0+ R1 1 3 4 Load1 No
LD F8 2+ R2 2 4 5 Load2 No
MULTD F4 F8 F2 3 9 10 Load3 No
DIVD F8 F8 F0 4 9 10
ADDD F10 F10 F4 5 12 13
SUBD F2 F8 F0 6 12 13
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
Add1 No
Add2 No
Add3 No
Mult1 No
Mult2 No
Register result status:
Clock F0 F2 F4 F6 F8 F10 F1213 FU M(A5) M(A3) M(A1) M(A4) M(A6)
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 40
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 2
Si consideri una CPU con le seguenti unità funzionali:
- 3 Sommatori con latenza di 2 colpi di clock;
- 2 Moltiplicatori con latenza di 4 colpi di clock per la moltiplicazione e 10 colpi di clock per la
divisione;
- 3 Accessi a memoria con latenza di 2 colpi di clock.
-
Eseguire colpo di clock dopo colpo di clock l’algoritmo di Tomasulo per il seguente programma:
DIVD F0 F2 F4
ADDD F6 F0 F4
SD F6 0+ R1
SUBD F8 F10 F14
MULTD F6 F10 F14
CLOCK 1
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address Val
DIVD F0 F2 F4 1 Store1 No
ADDD F6 F0 F4 Store2 No
SD F6 0+ R1 Store3 No
SUBD F8 F10 F14
MULTD F6 F10 F14
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
Add1 No
Add2 No
Add3 No
10 Mult1 Yes DIVD F2 F4
Mult2 No
Register result status:
Clock F0 F2 F4 F6 F8 F10 F12 ...1 FU Mult1
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 41
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CLOCK 2
CLOCK 3
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address Val
DIVD F0 F2 F4 1 Store1 No
ADDD F6 F0 F4 2 Store2 No
SD F6 0+ R1 Store3 No
SUBD F8 F10 F14
MULTD F6 F10 F14
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
Add1 Yes ADDD R(F4) Mult1
Add2 No
Add3 No
9 Mult1 Yes DIVD R(F2) R(F4)
Mult2 No
Register result status:
Clock F0 F2 F4 F6 F8 F10 F12 ...2 FU Mult1 Add1
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address Val
DIVD F0 F2 F4 1 Store1 Yes 0+R1 Add1
ADDD F6 F0 F4 2 Store2 No
SD F6 0+ R1 3 Store3 No
SUBD F8 F10 F14
MULTD F6 F10 F14
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
Add1 Yes ADDD R(F4) Mult1
Add2 No
Add3 No
8 Mult1 Yes DIVD R(F2) R(F4)
Mult2 No
Register result status:
Clock F0 F2 F4 F6 F8 F10 F12 ...3 FU Mult1 Add1
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 42
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CLOCK 4
CLOCK 5: l’istruzione MULTD può partire senza problemi, anche se il destinazione F6 effettivamente non è
stato ancora calcolato dalla precedente istruzione ADDD, la quale attende il termine della DIVD. Questo è possibile perché la Store1 attenderà il valore non dal registro F6 ma direttamente dal sommatore Add1 (attraverso il CDB); quindi non vi è la necessità di scrivere il risultato prima in F6 e poi di effettuare la store. Detto questo l’istruzione MULTD può tranquillamente effettuare la sua operazione e scrivere il risultato in F6, senza provocare incoerenza di dati. Per cui nel monitor dei registri è possibile indicare Mult2 ad F6.
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address Val
DIVD F0 F2 F4 1 Store1 Yes 0+R1 Add1
ADDD F6 F0 F4 2 Store2 No
SD F6 0+ R1 3 Sotre3 No
SUBD F8 F10 F14 4
MULTD F6 F10 F14
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
Add1 Yes ADDD R(F4) Mult1
2 Add2 Yes SUBD R(F10) R(F14)
Add3 No
7 Mult1 Yes DIVD R(F2) R(F4)
Mult2 No
Register result status:
Clock F0 F2 F4 F6 F8 F10 F12 ...4 FU Mult1 Add1 Add2
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address Val
DIVD F0 F2 F4 1 Store1 Yes 0+R1 Add1
ADDD F6 F0 F4 2 Store2 No
SD F6 0+ R1 3 Store3 No
SUBD F8 F10 F14 4
MULTD F6 F10 F14 5
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
Add1 Yes ADDD R(F4) Mult1
1 Add2 Yes SUBD R(F10) R(F14)
Add3 No
6 Mult1 Yes DIVD R(F2) R(F4)
4 Mult2 Yes MULTDR(F10) R(F14)
Register result status:
Clock F0 F2 F4 F6 F8 F10 F12 ...5 FU Mult1 Mult2 Add2
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 43
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CLOCK 6
CLOCK 7
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address Val
DIVD F0 F2 F4 1 Store1 Yes 0+R1 Add1
ADDD F6 F0 F4 2 Store2 No
SD F6 0+ R1 3 Store3 No
SUBD F8 F10 F14 4 6
MULTD F6 F10 F14 5
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
Add1 Yes ADDD R(F4) Mult1
0 Add2 Yes SUBD R(F10) R(F14)
Add3 No
5 Mult1 Yes DIVD R(F2) R(F4)
3 Mult2 Yes MULTDR(F10) R(F14)
Register result status:
Clock F0 F2 F4 F6 F8 F10 F12 ...6 FU Mult1 Mult2 Add2
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address Val
DIVD F0 F2 F4 1 Store1 Yes 0+R1 Add1
ADDD F6 F0 F4 2 Store2 No
SD F6 0+ R1 3 Store3 No
SUBD F8 F10 F14 4 6 7
MULTD F6 F10 F14 5
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
Add1 Yes ADDD R(F4) Mult1
Add2 No
Add3 No
4 Mult1 Yes DIVD R(F2) R(F4)
2 Mult2 Yes MULTDR(F10) R(F14)
Register result status:
Clock F0 F2 F4 F6 F8 F10 F12 ...7 FU Mult1 Mult2 M(A1)
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 44
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CLOCK 8: situazione invariata, decremento colonna timer CLOCK 9
CLOCK 10
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address Val
DIVD F0 F2 F4 1 Store1 Yes 0+R1 Add1
ADDD F6 F0 F4 2 Store2 No
SD F6 0+ R1 3 Store3 No
SUBD F8 F10 F14 4 6 7
MULTD F6 F10 F14 5 9
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
Add1 Yes ADDD R(F4) Mult1
Add2 No
Add3 No
2 Mult1 Yes DIVD R(F2) R(F4)
0 Mult2 Yes MULTDR(F10) R(F14)
Register result status:
Clock F0 F2 F4 F6 F8 F10 F12 ...9 FU Mult1 Mult2 M(A1)
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address Val
DIVD F0 F2 F4 1 Store1 Yes 0+R1 Add1
ADDD F6 F0 F4 2 Store2 No
SD F6 0+ R1 3 Store3 No
SUBD F8 F10 F14 4 6 7
MULTD F6 F10 F14 5 9 10
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
Add1 Yes ADDD R(F4) Mult1
Add2 No
Add3 No
1 Mult1 Yes DIVD R(F2) R(F4)
Mult2 No
Register result status:
Clock F0 F2 F4 F6 F8 F10 F12 ...10 FU Mult1 M(A2) M(A1)
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 45
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CLOCK 11
CLOCK 12
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address Val
DIVD F0 F2 F4 1 11 Store1 Yes 0+R1 Add1
ADDD F6 F0 F4 2 Store3 No
SD F6 0+ R1 3 Store3 No
SUBD F8 F10 F14 4 6 7
MULTD F6 F10 F14 5 9 10
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
Add1 Yes ADDD R(F4) Mult1
Add2 No
Add3 No
0 Mult1 Yes DIVD R(F2) R(F4)
Mult2 No
Register result status:
Clock F0 F2 F4 F6 F8 F10 F12 ...11 FU Mult1 M(A2) M(A1)
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address Val
DIVD F0 F2 F4 1 11 12 Store1 Yes 0+R1 Add1
ADDD F6 F0 F4 2 Store2 No
SD F6 0+ R1 3 Store3 No
SUBD F8 F10 F14 4 6 7
MULTD F6 F10 F14 5 9 10
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
2 Add1 Yes ADDD M(A3) R(F4)
Add2 No
Add3 No
Mult1 No
Mult2 No
Register result status:
Clock F0 F2 F4 F6 F8 F10 F12 ...12 FU M(A3) M(A2) M(A1)
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 46
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CLOCK 13: situazione invariata, decremento colonna timer
CLOCK 14
CLOCK 15
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address Val
DIVD F0 F2 F4 1 11 12 Store1 Yes 0+R1 Add1
ADDD F6 F0 F4 2 14 Store2 No
SD F6 0+ R1 3 Store3 No
SUBD F8 F10 F14 4 6 7
MULTD F6 F10 F14 5 9 10
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
0 Add1 Yes ADDD M(A3) R(F4)
Add2 No
Add3 No
Mult1 No
Mult2 No
Register result status:
Clock F0 F2 F4 F6 F8 F10 F12 ...14 FU M(A3) M(A2) M(A1)
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address Val
DIVD F0 F2 F4 1 11 12 2 Store1 Yes 0+R1
Add1
dal
CDB
ADDD F6 F0 F4 2 14 15 Store2 No
SD F6 0+ R1 3 Store3 No
SUBD F8 F10 F14 4 6 7
MULTD F6 F10 F14 5 9 10
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
Add1 No
Add2 No
Add3 No
Mult1 No
Mult2 No
Register result status:
Clock F0 F2 F4 F6 F8 F10 F12 ...15 FU M(A3) M(A2) M(A1)
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 47
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CLOCK 16: situazione invariata, decremento del timer della Store1
CLOCK 17: la store si completa, non bisogna attendere nessun risultato; il buffer Store1 viene liberato al
colpo di clock successivo per poter essere eventualmente utilizzato.
Instruction status: Exec Write
Instruction j k Issue Comp Result Busy Address Val
DIVD F0 F2 F4 1 11 12 0 Store1 Yes 0+R1
Add1
dal
CDB
ADDD F6 F0 F4 2 14 15 Store2 No
SD F6 0+ R1 3 17 Store3 No
SUBD F8 F10 F14 4 6 7
MULTD F6 F10 F14 5 9 10
Reservation Stations: S1 S2 RS RS
Time Name Busy Op Vj Vk Qj Qk
Add1 No
Add2 No
Add3 No
Mult1 No
Mult2 No
Register result status:
Clock F0 F2 F4 F6 F8 F10 F12 ...17 FU M(A3) M(A2) M(A1)
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 48
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZI ASSEMBLY – PROCESSORI SUPERSCALARI E VLIW
ESERCIZI ASSEMBLY PROCESSORI SUPERSCALARI E VLIW
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 49
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 1 Scrivere il codice srotolato di un programma che faccia il prodotto tra due vettori. Scrivere il codice per una CPU SCALARE, per una CPU VLIW e per una CPU SUPERSCALARE limitandosi prima a 20 registri e poi a 32 registri, riportando in quale caso si ha un miglioramento delle prestazioni (in percentuali). Si consideri un processore con registri a 32 bit e bus a 32 bit. Ogni CPU ha le seguenti caratteristiche: UNITA’ FUNZIONALI:
2 unità di accesso a memoria;
2 moltiplicatori/divisori;
1 sommatore/sottrattore;
LATENZA UNITA’:
LOAD: 2 colpi di clock
MOLTIPLICATORE: 10 colpi di clock
DIVISORE: 20 colpi di clock
SOMMATORE: 5 colpi di clock
Per la CPU VLIW si consideri il seguente formato istruzioni:
2 accessi a memoria;
2 operazioni FP;
1 operazione intera/branch
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 50
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
Si ipotizzi A*0+ all’indirizzo 1000, B*0+ all’indirizzo 2000, C*0+ all’indirizzo 3000.
Si posiziona R1, l’indice, all’ultimo elemento del vettore ((N-1)x8).
CPU SCALARE CON 20 REGISTRI FP
1 LOOP: L.D F0,R1(1000)
2 L.D F2,R1(2000)
3 L.D F4,R1(992) ;1000 – 8 byte = 992
4 L.D F6,R1(1992) ;2000 – 8 byte = 1992
5 L.D F8,R1(984) ;1000 – 16 byte = 984
6 L.D F10,R1(1984) ;2000 – 16 byte = 1984
7 L.D F12,R1(976) ;1000 – 24 byte = 976
8 L.D F14,R1(1976) ;2000 – 24 byte = 1976
9 L.D F16,R1(968) ;1000 – 32 byte = 968
10 L.D F18,R1(1968) ;2000 – 32 byte = 1968
11 MUL.D F0,F0,F2
12 MUL.D F4,F4,F6
13 MUL.D F8,F8,F10
14 MUL.D F12,F12,F14
16 MUL.D F16,F16,F18
17 DADDI R1,R1,#-40
18 STALLO
19 STALLO
20 STALLO
21 STALLO
22 S.D R1(3040),F0
23 S.D R1(3032),F4
24 S.D R1(3024),F8
25 S.D R1(3016),F12
26 BGEZ R1,LOOP
28 S.D R1(2968),F16
5 risultati in 28 colpi di clock, oppure 5.6 colpi di clock per iterazione.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 51
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CPU VLIW CON 20 REGISTRI FP
Mem Reference1 Mem Reference2 FP op1 FP op2 Int/branch
1 LOOP: L.D F0,R1(1000) L.D F2,R1(2000) noop noop noop
2 L.D F4,R1(992) L.D F6,R1(1992) noop noop noop
3 L.D F8,R1(984) L.D F10,R1(1984) MUL.D F0,F0,F2 noop noop
4 L.D F12,R1(976) L.D F4,R1(1976) MUL.D F4,F4,F6 noop noop
5 L.D F16,R1(968) L.D F18,R1(1968) MUL.D F8,F8,F10 noop noop
6 noop noop MUL.D F12,F12,F14 noop DADDI R1,R1,#-40
7 noop noop MUL.D F16,F16,F18 noop noop
8 STALLO
9 STALLO
10 STALLO
11 STALLO
12 STALLO
13 S.D R1(3040),F0 noop noop noop noop
14 S.D R1(3032),F4 noop noop noop noop
16 S.D R1(3024),F8 noop noop noop noop
17 S.D R1(3016),F12 noop noop noop BGEZ R1,LOOP
18 S.D R1(2968),F16 noop noop noop noop
5 risultati in 18 colpi di clock, oppure 3.6 colpi di clock per iterazione.
CPU SUPERSCALARE CON 20 REGISTRI FP
1 LOOP: L.D F0,R1(1000) noop
2 L.D F2,R1(2000) noop
3 L.D F4,R1(992) noop
4 L.D F6,R1(1992) MUL.D F0,F0,F2
5 L.D F8,R1(984) noop
6 L.D F10,R1(1984) MUL.D F4,F4,F6
7 L.D F12,R1(976) noop
8 L.D F14,R1(1976) MUL.D F8,F8,F10
9 L.D F16,R1(968) noop
10 L.D F18,R1(1968) MUL.D F12,F12,F14
11 DADDI R1,R1,#-40 noop
12 noop MUL.D F16,F16,F18
13 STALLO
14 S.D R1(3040),F0 noop
16 S.D R1(3032),F4 noop
17 S.D R1(3024),F8 noop
18 S.D R1(3016),F12 noop
19 BGEZ R1,LOOP noop
20 S.D R1(2968),F16 noop
5 operazioni in 20 colpi di clock, oppure 4 colpi di clock per iterazione.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 52
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CPU SCALARE CON 32 REGISTRI FP
1 LOOP: L.D F0,R1(1000)
2 L.D F2,R1(2000)
3 L.D F4,R1(992) ;1000 – 8 byte = 992
4 L.D F6,R1(1992) ;2000 – 8 byte = 1992
5 L.D F8,R1(984) ;1000 – 16 byte = 984
6 L.D F10,R1(1984) ;2000 – 16 byte = 1984
7 L.D F12,R1(976) ;1000 – 24 byte = 976
8 L.D F14,R1(1976) ;2000 – 24 byte = 1976
9 L.D F16,R1(968) ;1000 – 32 byte = 968
10 L.D F18,R1(1968) ;2000 – 32 byte = 1968
11 L.D F20,R1(960) ;1000 – 40 byte = 960
12 L.D F22,R1(1960) ;2000 – 40 byte = 1960
13 L.D F24,R1(952) ;1000 – 48 byte = 952
14 L.D F26,R1(1952) ;2000 – 48 byte = 1952
15 L.D F28,R1(944) ;1000 – 56 byte = 944
16 L.D F30,R1(1944) ;2000 – 56 byte = 944
17 MUL.D F0,F0,F2
18 MUL.D F4,F4,F6
19 MUL.D F8,F8,F10
20 MUL.D F12,F12,F14
21 MUL.D F16,F16,F18
22 MUL.D F20,F20,F22
23 MUL.D F24,F24,F26
24 MUL.D F28,F28,F30
25 DADDI R1,R1,#-64
26 STALLO
27 S.D R1(3064),F0
28 S.D R1(3056),F4
29 S.D R1(3048),F8
30 S.D R1(3040),F12
31 S.D R1(3032),F16
32 S.D R1(3024),F20
33 S.D R1(3016),F24
34 BGEZ R1,LOOP
35 S.D R1(2944),F24
8 risultati in 35 colpi di clock, oppure 4.3 colpi di clock per iterazione.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 53
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CPU VLIW CON 32 REGISTRI FP
Mem Reference1 Mem Reference2 FP op1 FP op2 Int/branch
1 LOOP: L.D F0,R1(1000) L.D F2,R1(2000) noop noop noop
2 L.D F4,R1(992) L.D F6,R1(1992) noop noop noop
3 L.D F8,R1(984) L.D F10,R1(1984) MUL.D F0,F0,F2 noop noop
4 L.D F12,R1(976) L.D F14,R1(1976) MUL.D F8,F8,F10 noop noop
5 L.D F16,R1(968) L.D F18,R1(1968) MUL.D F12,F12,F14 noop noop
6 L.D F20,R1(960) L.D F22,R1(1960) MUL.D F16,F16,F18 noop noop
7 L.D F24,R1(952) L.D F26,R1(1952) MUL.D F20,F20,F22 noop noop
8 L.D F28,R1(944) L.D F30,R1(1944) MUL.D F24,F24,F26 noop noop
9 noop noop MUL.D F28,F28,F30 noop DADDIR1,R1,#-64
10 STALLO
11 STALLO
12 STALLO
13 S.D R1(3064),F0 noop noop noop noop
14 S.D R1(3056),F4 noop noop noop noop
15 S.D R1(3048),F8 noop noop noop noop
16 S.D R1(3040),F12 noop noop noop noop
17 S.D R1(3032),F16 noop noop noop noop
18 S.D R1(3024),F20 noop noop noop noop
19 S.D R1(3016),F24 noop noop noop BGEZ R1,LOOP
20 S.D R1(2944),F24 noop noop noop noop
8 risultati in 20 colpi di clock, oppure 2.5 colpi di clock per iterazione.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 54
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
CPU SUPERSCALARE CON 32 REGISTRI FP
1 LOOP: L.D F0,R1(1000) noop
2 L.D F2,R1(2000) noop
3 L.D F4,R1(992) noop
4 L.D F6,R1(1992) MUL.D F0,F0,F2
5 L.D F8,R1(984) noop
6 L.D F10,R1(1984) MUL.D F4,F4,F6
7 L.D F12,R1(976) noop
8 L.D F14,R1(1976) MUL.D F8,F8,F10
9 L.D F16,R1(968) noop
10 L.D F18,R1(1968) MUL.D F12,F12,F14
11 L.D F20,R1(960) noop
12 L.D F22,R1(1960) MUL.D F16,F16,F18
13 L.D F24,R1(952) noop
14 L.D F26,R1(1952) MUL.D F20,F20,F22
15 L.D F28,R1(944) noop
16 L.D F30,R1(1944) MUL.D F24,F24,F26
17 DADDI R1,R1,#-64 noop
18 S.D R1(3064),F0 MUL.D F28,F28,F30
19 S.D R1(3056),F4 noop
20 S.D R1(3048),F8 noop
21 S.D R1(3040),F12 noop
22 S.D R1(3032),F16 noop
23 S.D R1(3024),F20 noop
24 S.D R1(3016),F24 noop
25 BGEZ R1,LOOP noop
26 S.D R1(2944),F24 noop
8 operazioni in 26 colpi di clock, oppure 3.25 colpi di clock per iterazione.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 55
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZI ASSEMBLY DLXV
ESERCIZI ASSEMBLY DLXV
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 56
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 1 – SOMMA VETTORI DA 64 ELEMENTI Somma di due vettori da 64 elementi per un DLXV con MVLR = 64. Si vuole realizzare una procedura che esegua C[64] = A[64] + B[64]. Utilizziamo R1 per contenere la dimensione del vettore. Utilizziamo R2 per contenere l’indirizzo in memoria del primo elemento del vettore A. Utilizziamo R3 per contenere l’indirizzo in memoria del primo elemento del vettore B. Utilizziamo R4 per contenere l’indirizzo in memoria del primo elemento del vettore C. DADDI R1, R0, #64 MTC1 VLR, R1 LV V1, 0(R2) LV V2, 0(R3) ADDV.D V1, V1, V2 SV 0(R4), V1 L’utilizzo di V1 come registro destinazione per contenere il vettore C è solo una forma di risparmio in registri. In alternativa all’istruzione DADDI R1, R0, #64 si può utilizzare l’istruzione LI R1, #64. Il programma presenterà uno stallo dopo l’ultima load perché la sua destinazione è operando della add che le succede: la prima delle 64 fasi di EX della ADDV processerà gli elementi V1[0] e V2[0], ma in V2[0] non sarà ancora stato ospitato l’effettivo valore B*0+ presente in memoria in quanto questo viene posto nel registro LDM solo dopo la fase di mem di LV, e successivamente nel registro vettoriale V2. DADDI R1, R0, #64 MTC1 VLR, R1 LV V1, 0(R2) LV V2, 0(R3) stallo ADDV.D V1, V1, V2 SV 0(R4), V1
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 57
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 2 – SOMMA DI VETTORI > 64 Somma di due vettori con un numero di elementi >64 per un DLXV con MVLR = 64. Si vuole realizzare una procedura che esegua C[>64] = A[>64] + B[>64]. Utilizziamo R1 per contenere la dimensione del vettore. Utilizziamo R10 come indice per scorrere tra i vari sottovettori. Utilizziamo R2 per contenere l’indirizzo in memoria del primo elemento del vettore A. Utilizziamo R3 per contenere l’indirizzo in memoria del primo elemento del vettore B. Utilizziamo R4 per contenere l’indirizzo in memoria del primo elemento del vettore C. I due vettori avranno dimensioni superiori a MVLR. Si può dunque pensare di suddividere i due vettori in tanti sottovettori da 64 elementi l’uno. Il problema principale è però che non sappiamo a priori se queste dimensioni sono divisibili per MVLR.
Nel caso lo fossero, bisognerà semplicemente incrementare l’indice di un valore pari a 8 byte x 64 elementi = 512 byte ad ogni iterazione per passare al sottovettore successivo senza modificare mai VLR.
Nel caso non lo fossero, e questo è il caso generale da usare per risolvere questo tipo di problema, bisognerà considerare un vettore residuo. Quindi scomporre il vettore principale in tanti sottovettori da 64 più un altro con dimensione minore di 64.
È logico schedulare come primo sottovettore il vettore residuo, in modo tale da non dover verificare ad ogni iterazione se si è giunti al penultimo sottovettore e quindi cambiare alla fine il VLR. Si pone quindi VLR uguale al residuo e lo si cambia alla fine di ogni loop ponendolo uguale a 64. Per ottenere la dimensione di questo residuo, si può utilizzare questa operazione: ANDI R10, R1, #63 Infatti, gli ultimi 6 bit di un numero binario qualsiasi corrispondono proprio al suo residuo se divisi per 64, ed essendo 26=64, ponendo 6 bit a 1 si ottiene il numero decimale 63 che posto in AND con la dimensione del vettore mette a zero tutti i bit più significativi del sesto. Ipotizzando un vettore di 187 elementi si ha: 187 / 64 = 2,921 64 x 2 = 128 187 – 128 = 59 (187)10 (10111011)2 (63)10 (111111)2 10111011 AND 111111 = 00111011 (00111011)2 (59)10
Poniamo il valore 64 in un registro qualsiasi (R5) in modo tale da poterlo poi spostare in VLR con l’istruzione MTC1 quando richiesto. DADDI R5, R0, #64 Considerando l’esempio della somma dei vettori per un processore scalare, abbiamo verificato che è più conveniente tenere un indice partendo dal fondo del vettore per arrivare fino in cima. Quindi volendo andare in coda al vettore, l’indice da utilizzare non dovrà partire da 0 ma da (dimensione del vettore – residuo) x 8 byte. Ricordiamoci di settare VLR pari al residuo prima di porre l’indice in coda al vettore.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 58
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
MTC1 VLR, R10 DSUB R10, R1, R10 DMUL R10, R10, #8 Ora si può iniziare il loop. loop: LV V1, R10(R2)
LV V2, R10(R3) ADDV.D V1, V1, V2 SV R10(R4), V1
Alla fine del loop, si decrementa il valore dell’indice di una quantità pari ad un sottovettore, quindi di 64 elementi, ognuno da 8 byte, quindi 512 byte.
DADDI R10, R10, #-512
Imposto VLR pari a 64, dato che da ora in poi, i sottovettori saranno sempre di dimensioni pari a MVLR.
MTC1 VLR, R5 Impongo la condizione che fino a ché l’indice è maggiore o uguale a zero, l’iterazione deve essere eseguita.
BGEZ R10, loop
Il listato completo è: ANDI R10, R1, #63
DADDI R5, R0, #64 MTC1 VLR, R10 DSUB R10, R1, R10 DMUL R10, R10, #8
loop: LV V1, R10(R2) LV V2, R10(R3) stallo ADDV.D V1, V1, V2 SV R10(R4), V1 DADDI R10, R10, #-512 MTC1 VLR, R5 BGEZ R10, loop stallo
L’istruzione di salto provoca i soliti stalli.
Spostiamo la MTC1 nel delay slot sotto BGEZ per non perdere il colpo di clock.
Lo stallo sotto la LV non potrà essere evitato.
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 59
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 3 – SOMMA DI MATRICI CON MxN > 64 Somma di due matrici con un numero di elementi MxN >64 per un DLXV con MVLR = 64. Si vuole realizzare una procedura che esegua C[>64][>64] = A[>64] [>64] + B[>64] [>64]. Prima di pensare a somme matriciali con due for, uno per riga e uno per colonna, ragioniamo un attimo su come vengono salvate le matrici in memoria per giungere ad una gradevole soluzione. In memoria, le matrici vengono salvate per righe. Questo significa che due blocchi contigui in memoria conterranno elementi successivi della stessa riga.
A[0][0] A[0][1] A[0][2] A[0][3] A[0][4] A[0][5] A*0+*…+ Una volta terminata la riga 0, successivamente, in memoria sarà allocata tutta la riga 1. Dunque, le matrici in memoria non sono altro che vettori di dimensione MxN. Il programma in assembly è identico a quello della somma di due vettori di dimensione >64, con l’unica differenza che la dimensione questa volta non sarà immediatamente passata come parametro alla routine ma bisognerà ricavarsela con una semplice moltiplicazione. Utilizziamo R1 per contenere la M ed R6 per contenere N. DMUL R1, R1, R6
ANDI R10, R1, #63 DADDI R5, R0, #64 MTC1 VLR, R10 DSUB R10, R1, R10 DMUL R10, R10, #8
loop: LV V1, R10(R2) LV V2, R10(R3) ADDV.D V1, V1, V2 SV R10(R4), V1 DADDI R10, R10, #-512 BGEZ R10, loop MTC1 VLR, R5
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 60
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 4 – OPERAZIONE Y = (aX + bY)/c Y= (aX + bY)/c con X e Y vettori di dimensione >64 e a, b e c scalari per un DLXV con MVLR = 64. Si vuole realizzare una procedura che esegua Y[>64] = (aX[>64] + bY[>64])/c. Utilizziamo R1 per contenere la dimensione del vettore. Utilizziamo R5 per contenere l’immediato costante 64. Utilizziamo R10 come indice per scorrere tra i vari sottovettori. Utilizziamo R2 per contenere l’indirizzo in memoria del primo elemento del vettore A. Utilizziamo R3 per contenere l’indirizzo in memoria del primo elemento del vettore B. Utilizziamo F0 per contenere lo scalare c. Utilizziamo F2 per contenere lo scalare a. Utilizziamo F4 per contenere lo scalare b.
ANDI R10, R1, #63 DADDI R5, R0, #64 MTC1 VLR, R10 DSUB R10, R1, R10 DMUL R10, R10, #8
loop: LV V1, R10(R2) stallo MULVS.D V1, V1, F2
LV V2, R10(R3) stallo MULVS.D V2, V2, F4 ADDV.D V2, V1, V2 DIVVS.D V2, V2, F0 SV R10(R3), V2 DADDI R10, R10, #-512 MTC1 VLR, R5 BGEZ R10, loop
stallo L’operazione MULVS.D V1, V1, F1 e MULVS.D V2, V2, F2 moltiplicano un vettore per uno scalare. L’operazione DIVVS.D V2, V2, F2 divide un vettore per uno scalare. Riordiniamo il programma per eliminare eventuali stalli. Non si sono considerati gli stalli dovuti alla fase EX delle unità floating point, quale moltiplicatore e divisore: il loro output sarà ottenuto solo dopo un numero di colpi di clock che varia in base alla latenza di tali unità, ed è quindi incalcolabile ad occhio quando questi provocheranno uno stallo.
ANDI R10, R1, #63 DADDI R5, R0, #64 MTC1 VLR, R10 DSUB R10, R1, R10 DMUL R10, R10, #8
loop: LV V1, R10(R2) LV V2, R10(R3)
MULVS.D V1, V1, F2 MULVS.D V2, V2, F4 ADDV.D V2, V1, V2
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 61
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
DIVVS.D V2, V2, F0 SV R10(R3), V2 DADDI R10, R10, #-512 BGEZ R10, loop MTC1 VLR, R5
Un metodo alternativo per risolvere l’algoritmo con, probabilmente, meno colpi di clock è quello di dividere prima del loop sia a che b per c. Questo porterebbe essere vantaggioso se le latenze delle unità funzionali non sono unitarie, in quanto supponiamo sia 10 la latenza del divisore e 4 quella del moltiplicatore, l’operazione di divisione che dura 10 colpi di clock la si fa una volta all’inizio, e non la si ripete 64 volte nel loop per ogni elemento (considerando una sola corsia e una sola unità funzionale per corsia). Se fosse a latenza unitaria, sprecheremmo solo un colpo di clock nel loop contro i due fuori dal loop (perché contemporaneamente a queste 64 divisioni venivano svolte 63 moltiplicazioni – la prima moltiplicazione era svolta prima della prima divisione così come l’ultima divisione è svolta dopo l’ultima moltiplicazione – aggiungendo solo un colpo di clock alla fine), ma ripeterlo 64 volte per 10 colpi di clock dopo le 64 moltiplicazioni per 4 colpi di clock significa un aumento notevole dei colpi di clock per eseguire il programma!
ANDI R10, R1, #63 DADDI R5, R0, #64 MTC1 VLR, R10 DSUB R10, R1, R10 DMUL R10, R10, #8 DIV.D F2, F2, F0 DIV.D F4, F4, F0
loop: LV V1, R10(R2) LV V2, R10(R3)
MULVS.D V1, V1, F2 MULVS.D V2, V2, F4 ADDV.D V2, V1, V2 SV R10(R3), V2 DADDI R10, R10, #-512 BGEZ R10, loop MTC1 VLR, R5
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 62
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
ESERCIZIO 5 – PRODOTTO SCALARE TRA VETTORI DI 64 ELEMENTI Prodotto scalare tra due vettori di 64 elementi con il metodo della riduzione a scalare. Si vuole realizzare una procedura che esegua c = A[64] x B[64]. Il prodotto scalare tra due vettori si realizza sommando i vari prodotti risultanti dalla moltiplicazione elemento per elemento: c = (A[0] x B[0]) + (A[1] x B[1]) + (A[2] x B[2]) + (A[3] x B[3]) + (A*4+ x B*4+) + (A*5+ x B*5+) + … Quindi per ottenere il risultato bisognerà innanzitutto moltiplicare i due vettori con l’operazione vettoriale MULV.D, successivamente dividere il vettore risultante in due sottovettori e sommarli. Tale divisione e somma dev’essere ripetuta fino a che non si giunge ad un unico elemento scalare che sarà poi il risultato finale (riduzione a scalare). Essendo i due vettori di dimensione 64 non vi sono problemi per quanto riguarda la moltiplicazione iniziale, e non vi è bisogno di alcun loop. Utilizziamo R1 per contenere la dimensione del vettore. Utilizziamo R2 per contenere l’indirizzo in memoria del primo elemento del vettore A. Utilizziamo R3 per contenere l’indirizzo in memoria del primo elemento del vettore B. Utilizziamo R4 per contenere l’immediato costante 1, per poi utilizzarlo come condizione di disuguaglianza nel branch. Utilizziamo R5 per contenere l’immediato costante 2, per poi fare la divisione a metà del vettore risultato della moltiplicazione (l’operazione DDIVI non esiste!). Utilizziamo R6 come indice per puntare alla seconda metà del sottovettore. DADDI R1, R0, #64 MTC1 VLR, R1 LV V1, 0(R2) LV V2, 0(R3) MULV.D V1, V1, V2 SV 0(R2), V1 Impostiamo le costanti 1 e 2: DADDI R4, R0, #1 DADDI R5, R0, #2 Iniziamo il loop. Nel loop dovremo inizialmente dividere il vettore per due, e poi impostare un indice che punti al secondo sottovettore moltiplicando la dimensione dei due sottovettori (nella prima iterazione 64/2=32) per 8 byte. Poi si caricano i vettori, si sommano ed infine store. Ultima istruzione, branch, se il risultato della divisione è diverso da 1, allora ripeti il loop, se non lo è, hai finito. loop: DDIV R1, R1, R5 MTC1 VLR, R1 DMULI R6, R1, #8 LV V1, 0(R2) LV V2, R6(R2) ADDV.D V1, V1, V2
Esercizi di Calcolatori Elettronici A.A. 2009/2010
CALCOLATORI ELETTRONICI Pagina 63
Pietroleonardo Nicola A.A. 2009/2010 Stroppa Fabio
SV 0(R2), V1 BNE R1, R4, loop Lo scalare c sarà salvato all’indirizzo di memoria R2, che inizialmente conteneva il primo elemento del vettore. Il listato completo è:
DADDI R1, R0, #64 MTC1 VLR, R1 LV V1, 0(R2) LV V2, 0(R3) stallo MULV.D V1, V1, V2 SV 0(R2), V1 DADDI R4, R0, #1 DADDI R5, R0, #2
loop: DDIV R1, R1, R5 MTC1 VLR, R1 DMULI R6, R1, #8 LV V1, 0(R2) LV V2, R6(R2) stallo ADDV.D V1, V1, V2 SV 0(R2), V1 BNE R1, R4, loop stallo Riordiniamo il programma per eliminare eventuali stalli. Non si sono considerati gli stalli dovuti alla fase EX delle unità floating point, quale moltiplicatore e sommatore: il loro output sarà ottenuto solo dopo un numero di colpi di clock che varia in base alla latenza di tali unità, ed è quindi incalcolabile ad occhio quando questi provocheranno uno stallo.
DADDI R1, R0, #64 MTC1 VLR, R1 LV V1, 0(R2) LV V2, 0(R3) DADDI R4, R0, #1 MULV.D V1, V1, V2 SV 0(R2), V1 DADDI R5, R0, #2
loop: DDIV R1, R1, R5 MTC1 VLR, R1 DMULI R6, R1, #8 LV V1, 0(R2) LV V2, R6(R2) stallo non eliminabile ADDV.D V1, V1, V2 BNE R1, R4, loop SV 0(R2), V1