Sei sulla pagina 1di 95

S.

Furber

ARM
System-on-chip
architecture

(traduzione curata da
E. Pediconi)

1
1 Introduzione alla
progettazione di un
processore

Contenuti del capitolo

Il progetto di un processore general-purpose


richiede in genere molti sforzi dal punto di
vista ingegneristico, giungendo spesso a
compromessi. In questo capitolo guarderemo
i principi alla base di un set distruzioni per i
processori, alla progettazione di logiche e alle
tecniche utilizzate dai progettisti.
Lastrazione fondamentale per capire la
complessit dei computer. Questo capitolo
introduce il concetto di astrazione utilizzato
dai progettisti hardware, con particolare
attenzione alle porte logiche.
Le idee che stanno dietro ai Reduced
Instruction Set Computer (RISC) furono
sviluppate nel programma di ricerca sui
2
processori alle universit di Stanford e
Berkeley intorno agli anni 80, anche se alcuni
dei temi centrali erano stati gi messi in
risalto da macchine precedenti. Guarderemo
alle idee che hanno condotto ai RISC e in
seguito influenzato la progettazione del
processore ARM, che sar oggetto dei
prossimi capitoli.
Con la rapida ascesa del mercato degli
apparecchi portatili, il consumo di potenza dei
circuiti assunse unimportanza crescente. Alla
fine del capitolo descriveremo i principi della
progettazione per ottenere alte prestazioni
con bassi consumi.

1.1 Architettura e organizzazione


di un processore

Tutti i moderni computer general-purpose


utilizzano i principi degli stored-program
digital computer. Questi furono sviluppati a
Princeton negli anni 40 e implementati nella
3
macchina Baby nel 1948 alluniversit di
Manchester. Cinquantanni di progressi hanno
permesso una grande crescita nelle
prestazioni di questi processori e una
diminuzione altrettanto grande del loro costo.
Durante questo periodo di continuo progresso
come detto, su costi e prestazioni dei
computer, i principi di funzionamento sono
cambiati ben poco. La maggior parte dei
miglioramenti sono stati ottenuti grazie a
sviluppi tecnologici, passando dalle valvole
(tubi a vuoto), ai transistor fino ai circuiti
integrati (IC) i quali incorporano vari
transistor bipolari e dopo alcune generazioni
di IC siamo oggi alla VLSI, dove sono presenti
milioni di transistor a effetto di campo su un
singolo chip. I transistor oltre a diventare pi
piccoli, hanno anche costi inferiori, sono pi
veloci e consumano meno potenza. Questo
scenario molto promettente ha fatto
sviluppare lindustria informatica negli ultimi
tre decenni, e continuer a farlo, almeno per i
prossimi anni.

4
Tuttavia non tutti i progressi degli ultimi 50
anni sono dovuti agli sviluppi della tecnologia
elettronica. Ci sono stati anche casi in cui una
comprensione maggiore del modo in cui
viene impiegata la tecnologia ha dato un
contributo significativo. Questi concetti vanno
sotto il nome di architettura dei computer e
organizzazione dei computer, a cui
attribuiamo il seguente significato:

Architettura dei computer

Descrive le parti visibili allutilizzatore. Il


set delle istruzioni, registri visibili,
struttura delle tabelle per la gestione
della memoria e le eccezioni fanno tutti
parte dellarchitettura.

Organizzazione del computer

Descrive ci che non risulta visibile


allutilizzatore. Come ad esempio la
struttura della pipeline, la cache
trasparente, ecc fanno tutti parte
5
dellorganizzazione.

Tra i progressi nella progettazione di


computer, lintroduzione di memorie virtuali
nel 1960, di cache trasparenti e di pipeline,
sono stati fondamentali per la sua evoluzione.
Lidea dei RISC fa parte di questi progressi,
offrendo un significativo spostamento di forze
che determinano il rapporto costo-efficienza
nella tecnologia informatica.

Cos un processore?

Un processore general-purpose una


macchina a stati finiti che esegue delle
operazioni contenute in memoria. Lo stato del
sistema definito dai valori contenuti nelle
locazioni di memoria insieme ai valori
contenuti in alcuni registri interni (Fig. 1.1, la
notazione esadecimale sar spiegata nella
sezione 6.2). Ogni istruzione definisce come
lo stato finale deve cambiare e quale
istruzione va eseguita in seguito.

6
Lo stored-program computer

Lo stored-program computer mantiene le


istruzioni e i dati nello stesso sistema di
memoria, permettendo di trattare le istruzioni
come fossero dati se necessario. Questo
permette al processore stesso di generare
istruzioni che verranno eseguite
7
successivamente. Anche se i programmi che
operano in questo modo (self-modifyng code)
non sono considerati molto utili poich risulta
assai difficile effettuarne il debug, quindi per
lo pi i computer non operano in questo
modo. Ogni volta che un computer carica un
programma dal disco (sovrascrive un vecchio
programma) e poi lo esegue, sta sfruttando
questabilit di cambiare un suo stesso
programma.

Applicazioni dei computer

Grazie alla sua programmabilit, uno


stored-program computer risulta universale,
nel senso che in grado di svolgere qualsiasi
compito che possa essere descritto
attraverso un algoritmo opportuno. A volte
questo si vede dalla sua configurazione come
computer desktop con il quale lutente lancia
programmi differenti in momenti diversi, ma
in altri casi lo stesso processore a essere
utilizzato in una vasta gamma di applicazioni

8
diverse, ognuna con un programma definito.
Tali applicazioni sono tipicamente incorporate
in prodotti come telefoni cellulari, sistemi per
la gestione del motore, e cos via.

1.2 Lastrazione nel progetto


hardware

I computer sono parti molto complesse di


apparecchiature che lavorano ad altissima
velocit. Un microprocessore moderno pu
essere costituito da vari milioni di transistor
ognuno dei quali pu cambiare di stato
centinaia di milioni di volte al secondo.
Guardate un documento, fate scorrere lo
schermo sul PC e provate a immaginare come
centinaia di milioni di transistor stanno
commutando ogni secondo. Ora considerate
che ciascuna di queste commutazioni , in un
certo senso, la conseguenza di una precisa
progettazione. Niente avviene casualmente,
in modo incontrollato; infatti, un singolo
9
errore tra queste transizioni sufficiente a far
collassare il sistema in uno stato indefinito.
Come possono essere progettati sistemi cos
complessi che possano operare in modo
affidabile?

I Transistor

Un indizio per la risposta pu essere trovato


nella domanda stessa. Abbiamo descritto il
funzionamento di un computer parlando di
transistor ma cos un transistor? una
struttura particolare composta di sostanze
chimiche scelte con cura che presenta delle
propriet elettriche che possono essere
comprese solamente facendo uso della
meccanica quantistica, dove strane particelle
subatomiche alle volte si comportano come
onde e possono quindi essere descritte
esclusivamente in termini probabilistici.
Tuttavia si pu descrivere il comportamento
di un transistor senza riferirsi alla meccanica
quantistica, ma utilizzando delle equazioni

10
che mettono in relazione la tensione ai suoi
capi e la corrente che vi scorre. Queste
equazioni sono unastrazione del
comportamento essenziale del dispositivo e
della fisica alla base.

Porte logiche

Le equazioni che descrivono il


comportamento di un transistor sono ancora
abbastanza complesse. Quando un gruppo di
transistor collegato insieme in una
configurazione particolare, come una porta
NAND in tecnologia CMOS (Complementary
Metal Oxide Semiconductor) (Fig. 1.2), il
comportamento nellinsieme ha una
descrizione particolarmente semplice. Se
ognuno degli ingressi (A e B) mantenuto a
una tensione vicino a Vdd o vicino a Vss,
luscita sar anchessa vicina a V dd o Vss
secondo le seguenti regole:

11
Se A e B sono entrambi vicini a V dd,
luscita sar prossima a Vss.
Se invece A o B (o entrambi) sono
vicini a Vss, luscita sar prossima a Vdd.

Con un po di attenzione si pu definire cosa


sintende con vicino a in queste regole, e
poi associare lo stato true se il valore
vicino a Vdd e false per valori vicini a Vss. Il
12
circuito quindi unimplementazione della
funzione logica Booleana NAND:

output = (A B) Eq. 1

Anche se ci sono molti modi di gestire quattro


transistor per implementare in modo
efficiente questa equazione, il progettista pu
far uso con sufficiente affidabilit solamente
delle porte logiche. I concetti utilizzati sono
rappresentati nella Fig. 1.3 ed esprimono:

Simboli logici

Simbolo che rappresenta la porta NAND in


un circuito; simile a altre porte logiche
(per esempio levando il pallino sulluscita
si ottiene una AND che genera una
funzione esattamente opposta alla NAND;
altri esempi sono dati nellAppendice:
Computer Logic).

13
Tavola di verit

Questa descrive la funzione logica della


porta, e fornisce tutto ci che si deve
sapere su di essa, per la maggior parte
delle applicazioni. Risulta quindi molto pi
semplice lavorare con queste piuttosto
che avere quattro equazioni dei transistor.

(In questa tavola di verit abbiamo espresso


true con 1 e false con 0, com
consuetudine lavorando con variabili
booleane.)

Lastrazione della porta logica

Sfruttare lastrazione delle porte logiche non


solo semplifica di molto il processo di
progettazione di circuiti con un gran numero
di transistor, ma permette di non considerare
proprio che le porte logiche siano costituite
da transistor.

14
Un circuito logico deve avere lo stesso
comportamento sia che le porte siano
implementate con dei FET, o dei transistor
bipolari, dei rel o qualunque altra forma di
logica. La tecnologia utilizzata influenzer le
performance del circuito, ma non dovrebbe
avere effetto sulla funzionalit. compito del
progettista circuitale che lavora al livello di
transistor far si che le porte logiche
15
funzionino perfettamente e che il progettista
che lavora a pi alto livello (porte logiche)
non debba pensare alle equazioni dei
transistor.

Livelli di astrazione

Pu sembrare che questo punto sia stato un


po faticoso, in particolare per quei lettori che
hanno lavorato con le porte logiche per molti
anni. Tuttavia, il principio che stato
illustrato si ripete molte volte a differenti
livelli nellinformatica ed assolutamente
fondamentale per il processo che abbiamo
iniziato a considerare, cio la gestione di
sistemi complessi.
Il processo di unire insieme alcuni
componenti di un certo livello ed estrarne la
funzione complessiva nascondendo i dettagli
irrilevanti per il livello pi alto, ci permette di
scalare ordini di complessit in pochi
passaggi. Per esempio, se a ogni livello
uniamo quattro componenti per ottenerne

16
uno del livello pi alto, come nel caso delle
porte logiche, saremo in grado di passare dai
transistor al microprocessore, che ne
comprende milioni, in soli dieci passaggi. In
molti casi lavoreremo con pi di quattro
componenti, in questo modo il numero di
passaggi si riduce notevolmente.
Una tipica gerarchia di astrazione a livello
hardware potrebbe essere:

1. Transistor;
2. Porte logiche, celle di memoria, circuiti
speciali;
3. Single-bit adders, multiplexers, decoders,
flip-flops;
4. Word-wide adders, multiplexers,
decoders, registri, buses;
5. ALU (Arithmetic-Logic Unit), barrel
shifters, banchi di registri, blocchi di
memoria;
6. Processori, organizzazione e gestione di
cache e memorie;
7. Processori, celle periferiche, memorie
cache, unit di gestione della memoria;
17
8. Chip di sistemi integrati;
9. Circuiti stampati;
10.Cellulari, PC, controlli automatici.

Il processo di comprensione del progetto in


termini di livello di astrazione
ragionevolmente concreto quando si parla di
hardware. Ma tale processo non limitato
allhardware; semmai, ancora pi
importante per la parte software della quale
parleremo a tempo debito.

Progettazione a livello di porte logiche

Il passo successivo per avere un circuito


logico creare una libreria di funzioni utili,
ognuna eseguita da varie porte logiche.
Funzioni tipiche sono, come detto in
precedenza, sommatori, multiplexer, decoder
e flip-flop, ciascuno da 1-bit. Questo testo non
vuole essere unintroduzione generale alla
progettazione di sistemi logici, ma alla
progettazione e utilizzo di processori e il

18
lettore dovrebbe avere gi familiarit con
sistemi logici basilari.
Per questo chi non dovesse avere familiarit
con la progettazione utilizzando porte logiche
o chi avesse bisogno di rinfrescare le sue
conoscenze pu vedere lAppendice:
Computer Logic, dove si descrivono gli
elementi essenziali che si assumeranno noti
nel seguito. Inclusi cenni su:

Algebra booleana e notazioni;


Numeri binari;
Addizione in sistema binario;
Multiplexer;
Clock;
Circuiti sequenziali;
Latch e flip-flop;
Registri.

Se qualcuno di questi argomenti risultasse


poco familiare, una rapida lettura
dellAppendice potrebbe essere sufficiente
per fornire le informazioni necessarie alla
comprensione del seguito. Si noti che
19
sebbene lappendice descriva questi circuiti
in termini di semplici porte logiche, ci sono
spesso implementazioni CMOS pi efficienti
basate su circuiti alternativi. Ci sono molti
modi per soddisfare le richieste basilari della
progettazione logica utilizzando i transistor
disponibili su un chip CMOS, e nuovi circuiti
vengono implementati regolarmente. Per
ulteriori informazioni consultare il testo sulla
progettazione logica; un riferimento adeguato
suggerito nella Bibliografia.

1.3 MU0 un semplice processore

Una forma semplificata di processore pu


essere costruita con pochi componenti base:

Un registro chiamato program counter


(PC) usato per conservare lindirizzo
dellistruzione corrente;

20
Un registro singolo chiamato
accumulatore (ACC) che mantiene il
valore del dato mentre questo utilizzato;
Una ALU in grado di eseguire delle
operazioni tra numeri binari, come
somma, sottrazione, incremento e cos
via;
Un istruction register (IR) che mantiene
listruzione corrente mentre viene
eseguita;
Un decodificatore per le istruzioni e una
logica di controllo che utilizza i
componenti descritti sopra per ottenere i
risultati desiderati dalle varie istruzioni.
Questo insieme ristretto di componenti
permette di implementare un ridotto numero
distruzioni. Tale progetto stato utilizzato
per molti anni nellUniversit di Manchester al
fine di illustrare i principi della progettazione
dei processori. Le macchine progettate a
Manchester sono spesso indicate con il nome
MUn con 1<n<6, per cui questa semplice
macchina nota come MU0. Si tratta di un
progetto sviluppato solo per linsegnamento e
21
non era una delle macchine costruite su
grande scala come veicolo di ricerca
nelluniversit, molto simile alla prima
macchina che fu implementata in varie forme
dagli studenti dellUniversit di Manchester.

Set distruzioni per il MU0

Il MU0 una macchina a 16-bit con 12-bit di


spazio per gli indirizzi, quindi in grado di
indirizzare fino a 8 Kb di memoria, disposti
come 4096 indirizzabili individualmente verso
i 16-bit di locazione. Le istruzioni hanno una
lunghezza di 16-bit, con 4-bit di codice
operazione (opcode) e 12-bit di campo
indirizzo (S) come mostrato in Fig. 1.4. Il pi
semplice set distruzioni usa solo otto dei
sedici opcode disponibili ed riassunto nella
Tabella 1.1.
Unistruzione come 'ACC := ACC + mem16[S]'
significa aggiungi il contenuto della locazione
di memoria (16-bit) che ha come indirizzo S
allaccumulatore. Listruzione caricata da

22
indirizzi di memoria consecutivi, partendo
dallindirizzo zero, fino a che unistruzione
che modifichi PC non viene eseguita, dopo di
che il fetch riparte dal nuovo indirizzo fornito
dallistruzione di branch.

23
Progetto della logica del MU0

Per capire come potrebbe essere


implementato il set distruzioni,
attraverseremo il processo di progettazione
con ordine. Lapproccio seguito qui sar
quello di dividere la progettazione in due
componenti:

Il datapath
Tutti i componenti che trasportano,
immagazzinano o elaborano pi bit in
parallelo saranno considerati parte del
datapath, includendo laccumulatore, il
program counter, lALU e il registro
istruzioni. Per questi componenti

24
useremo dei register transfer level (RTL)
basati su registri, multiplexer, e cos via.

Logica di controllo
Tutto ci che non compreso nel
datapath sar considerato parte della
logica di controllo e sar progettato
utilizzando lapproccio delle macchine a
stati finiti (FSM).

Progetto del datapath

Ci sono molti modi di connettere i


componenti base utili per implementare il set
distruzioni del MU0. Quando ci sono scelte da
fare abbiamo bisogno di linee guida che ci
aiutino ad andare nella direzione corretta. Qui
seguiremo il principio che la memoria il
fattore limitante del nostro progetto, e che
laccesso alla memoria richiede sempre un
ciclo di clock. Quindi punteremo a
unimplementazione in cui:

25
Ogni istruzione impiegher esattamente il
numero di cicli di clock uguale al numero
di accessi alla memoria necessari.

Riferendoci alla Tabella 1.1 possiamo vedere


che le prime quattro istruzioni richiedono
ciascuna due accessi alla memoria (uno per
effettuare il fetch dellistruzione stessa e un
altro per caricare o immagazzinare
loperando) mentre le ultime quattro
istruzioni possono essere eseguite in un solo
ciclo di clock, poich non richiedono alcun
operando. (In pratica probabilmente non ci
preoccuperemo dellefficienza dellistruzione
STP poich arresta il processore per sempre).
Quindi avremo bisogno di progettare un
datapath che sia in grado di completare
queste istruzioni in due, o in un ciclo di clock.
Un datapath adeguato mostrato in Fig. 1.5.

26
(Il lettore che si aspettasse di vedere un
incrementatore dedicato per il PC in questo
datapath, dovrebbe notare che tutte le
istruzioni che non modificano PC richiedono
due cicli, quindi la ALU disponibile durante
uno di questi cicli per incrementare PC).

27
Operazioni del datapath

Il progetto che svilupperemo parte dal


concetto che listruzione inizia quando arriva
al registro istruzione. Dopo tutto, finche non
nel registro istruzioni non possiamo sapere
con che istruzione abbiamo a che fare. Quindi
unistruzione viene eseguita in due fasi,
possibilmente omettendo la prima di queste:

1. Accedere alloperando in memoria ed


eseguire loperazione desiderata.
Viene rilasciato lindirizzo nel registro
istruzioni e un operando viene letto dalla
memoria, poi combinato con
laccumulatore nella ALU e riscritto
nellaccumulatore, o laccumulatore viene
immagazzinato in memoria.

2. Fetch dellistruzione successiva da


eseguire.
O il PC o lindirizzo nel registro istruzioni
viene rilasciato per eseguire il fetch della
prossima istruzione, in entrambi i casi
28
lindirizzo viene incrementato nella ALU e
salvato in PC.

Inizializzazione

Il processore deve partire da uno stato noto.


Spesso per ottenere ci richiesto un
ingresso di reset, in modo da iniziare
lesecuzione di unistruzione da un indirizzo
noto. Noi progetteremo il MU0 in modo che
inizi lesecuzione dallindirizzo 000 16. Ci sono
vari modi per arrivare a questo, uno dei quali
di usare il segnale di reset per portare a
zero luscita della ALU e dopo un clock
portarla nel PC.

Progetto a livello di trasferimenti tra


registri (register transfer level)

Il passo successivo quello di determinare


esattamente i segnali di controllo necessari
per permettere al datapath di eseguire
29
lintero set distruzioni. Supponiamo che tutti
i registri cambino stato sul fronte di discesa
del segnale di clock, e dove necessario si
abbia un controllo che pu prevenire un
cambio di stato a un particolare fronte del
clock. Il PC, per esempio, cambier alla fine
del ciclo di clock se PCce 1 ma non
cambier quando PCce 0.
Unapposita organizzazione dei registri
mostrata in Fig. 1.6. Questa mostra i segnali
di enable su tutti i registri, le linee di
selezione della funzione per la ALU (il numero
preciso e linterpretazione verranno
determinati in seguito), le linee di controllo
per la selezione di due multiplexer, il controllo
per un driver tri-state che manda il valore di
ACC alla memoria, la richiesta per la memoria
(MEMrq) e la linea di controllo read/write
(RnW). Gli altri segnali mostrati sono le uscite
che vanno dal datapath alla logica di
controllo, inclusi i bit dellopcode e i segnali
che indicano se ACC zero o negativo e che
controllano le rispettive istruzioni di branch
condizionato.
30
31
Logica di controllo

La logica di controllo deve semplicemente


decodificare listruzione corrente e portare il
segnale di controllo per il datapath al livello
appropriato, usando gli ingressi di controllo
dal datapath se necessario. Sebbene la
logica di controllo una macchina a stati
finiti, e quindi in linea di massima il progetto
dovrebbe iniziare dal diagramma delle
transizioni di stato, in questo caso la FSM
semplice e non vale la pena fare il
diagramma. Limplementazione richiede solo
due stati, fetch e execute, e un bit di
stato (Ex/ft) sar quindi sufficiente.
La logica di controllo pu essere
rappresentata in forma di tabella come
mostrato nella Tab. 1.2. In questa tabella la
x indica la condizione indifferente. Una
volta che i codici di selezione per la ALU sono
assegnati la tabella pu essere implementata
come un PLA (programmable logic array) o
tradotta in logica combinatoria e realizzata
con porte logiche standard. Uno sguardo
32
veloce alla Tab. 1.2 ci suggerisce alcune
semplificazioni immediate. I segnali di
abilitazione per il program counter e il
registro istruzioni (PCce e IRce) sono sempre
gli stessi.
Questo ha senso, dal momento che ogni volta
che una nuova istruzione viene caricata la
ALU sta calcolando il valore successivo del
program counter, e anche questo dovrebbe
essere memorizzato. Pertanto questi segnali
di controllo possono essere unificati.
Analogamente, ogni volta che laccumulatore
controlla il bus dati (ACCoe a livello logico
alto) la memoria dovrebbe eseguire
unoperazione di scrittura (RnW a livello
logico basso), quindi uno di questi due
segnali pu essere generato dallaltro
facendolo passare per un inverter.
Dopo queste semplificazioni il progetto della
logica di controllo quasi completo. Restano
solo da determinare le codifiche per le
funzioni dellALU.

33
34
Progettazione della ALU

La maggior parte delle funzioni del register


transfer level di Fig. 1.6 hanno una chiara
implementazione logica (il lettore che ha dei
dubbi pu consultare lAppendice: Computer
Logic). La ALU del MU0 un po pi
complicata del semplice sommatore mostrato
nellappendice.
Le funzioni della ALU necessarie sono
elencate nella Tab. 1.2. Cinque di queste
sono: (A+B, A-B, B, B+1, 0), lultima delle
quali utilizzata solo mentre attivo il reset.
Quindi il segnale di reset pu controllare
questa funzione direttamente, e la logica di
controllo ha bisogno di soli 2-bit per la
selezione della funzione tra le quattro
rimanenti. Se gli ingressi principali dellALU
sono gli operandi A e B, tutte le funzioni
possono essere prodotte sviluppando un
semplice sommatore binario:

35
A+B luscita di un normale
sommatore (assumendo il resto nullo).
A-B pu essere implementato come
A+B'+1, prendendo lingresso B
invertito e forzando il resto a 1.
B si ottiene forzando lingresso A e il
resto a 0.
B+1 si ottiene forzando lingresso A a 0
e il resto a 1.

Il livello logico della porta per la ALU


mostrato in Fig. 1.7. Aen abilita loperando A
o lo pone uguale a zero; Binv controlla se
loperando B invertito o meno. Il carry-out
(Cout) di un bit collegato con il carry-in
(Cin) del successivo; il carry-in del primo bit
controllato dal selettore di funzione dellALU
(come Aen e Binv), il carry-out dellultimo bit
inutilizzato. Insieme con i multiplexer, i
registri, le logiche di controllo e un bus buffer
(che viene utilizzato per inserire il valore
dellaccumulatore sul bus dati), il processore
completo. Aggiungendo una memoria
standard si ha un computer funzionante.
36
Estensioni al MU0

Sebbene il MU0 sia un processore molto


semplice e non sarebbe un buon target per
un compilatore che lavora su linguaggi ad
alto livello, serve a illustrare i principi basilari
per la progettazione di un processore. Il
processo di progettazione utilizzato per
sviluppare i primi processori ARM differisce
principalmente in complessit non sul
principio. Sono stati sviluppati anche progetti
37
di MU0 basati su logiche di controllo con
microcodice, che permettono delle estensioni
per incorporare indirizzi indicizzati. Come
ogni buon processore, il MU0 ha spazi liberi
nel campo istruzione, il che permette future
espansioni del set di istruzioni.
Trasformare il MU0 in un processore utile
richiede un bel po di lavoro. Le seguenti
estensioni sembrano le pi importanti:

Espandere lo spazio indirizzi.


Aggiungere ulteriori modalit di
indirizzamento.
Consentire il salvataggio del PC al
fine di permettere il meccanismo di
subroutine.
Aggiungere altri registri, supportare
gli interrupt, e cos via

Ad ogni modo, questa non la strada giusta


da intraprendere se lobiettivo quello di
progettare un processore di alte prestazioni
che sia il giusto target di un buon
compilatore.
38
1.4 Progettazione del set di
istruzioni

Se, come detto, il set di istruzioni del MU0


non una scelta appropriata per un
processore di alte prestazioni, quali altre
possibilit ci sono?
Partendo dal principio, consideriamo
un'operazione basilare per questa macchina,
come un'istruzione che permetta di sommare
due numeri e produrre un risultato.

Istruzione a 4-indirizzi

Nel caso pi generale, questa istruzione


richiede alcuni bit che permettano di
distinguerla da altre, alcuni bit per specificare
gli indirizzi degli operandi, e altri ancora per
specificare dove va inserito il risultato (la
destinazione) e infine dei bit per specificare
lindirizzo dellistruzione da eseguire in
seguito. Il linguaggio nel formato assembly
per questa istruzione potrebbe essere:
39
ADD d, s1, s2, next_i ; d := s1 + s2

Tale istruzione pu essere rappresentata in


memoria nel formato binario come mostrato
in Fig. 1.8. Questo formato richiede 4n+f bit
per istruzione dove ogni operando necessita
di n bit e lopcode che in questo caso esprime
la funzione ADD richiede ulteriori f bit.

Istruzione a 3-indirizzi

Il primo modo per ridurre il numero di bit


richiesti da ogni istruzione di rendere
implicito lindirizzo dellistruzione successiva
(tranne che per le istruzioni di branch, il cui
ruolo di modificare la sequenza delle
istruzioni in modo esplicito). Se assumiamo di

40
default che listruzione successiva pu essere
trovata aggiungendo la dimensione
dellistruzione al PC, avremo un'istruzione a
3-indirizzi che si pu esprimere in linguaggio
assembly nella forma:

ADD d, s1, s2 ; d := s1 + s2

Una rappresentazione binaria di questa


istruzione mostrata in Fig. 1.9.

Istruzione a 2-indirizzi

Un ulteriore risparmio nel numero di bit


richiede di poter salvare il risultato in uno dei

41
registri degli operandi. Il linguaggio assembly
per questoperazione :

ADD d, s1 ; d := d + s1

Di cui una rappresentazione binaria si vede in


Fig. 1.10.

Istruzione a 1-indirizzo

Se il registro di destinazione reso implicito,


viene spesso chiamato accumulatore
(vedere come esempio il MU0 nella sezione
precedente); l'istruzione necessita di
specificare solo un operando:

42
ADD s1 ; accumulator := accumulator + s1

Con rappresentazione binaria in Fig. 1.11.

Istruzione con 0-indirizzi

Infine, un'architettura potrebbe prevedere


tutti i riferimenti agli indirizzi impliciti
svolgendo una valutazione sequenziale. Il
linguaggio assembly sar:

ADD ; top_of_stack := top_of_stack


+ next_on_stack

e in Fig. 1.12 la rappresentazione binaria.

43
Esempi di utilizzo per istruzioni con
n-indirizzi

Tutti questi tipi di istruzione sono stati


utilizzati nei set di istruzioni presenti nei
processori tranne quello a 4-indirizzi, sebbene
venga utilizzato interamente per alcuni
progetti di microcodice, inutilmente pesante
per un set istruzioni a livello-macchina. Per
esempio:

LInmos transputer utilizza un'architettura


a 0-indirizzi.
Il MU0 presentato nella sezione
precedente presenta una semplice
architettura a 1-indirizzo.
44
Il set di istruzioni Thumb usate per
programmare con alta densit di codice
su alcuni processori ARM utilizzano
prevalentemente architetture con
2-indirizzi (vedere Capitolo 7).
Il normale set di istruzioni per ARM
utilizza un'architettura a 3-indirizzi.

Indirizzi

Nellarchitettura del MU0 un indirizzo il


riferimento diretto alla locazione di memoria
che contiene loperando richiesto. Anche se, i
tre indirizzi per le istruzioni ARM sono dei
riferimenti ai registri, non a locazioni di
memoria. In generale, con il termine
architettura a 3-indirizzi ci si riferisce a un
set di istruzioni nel quale possibile
specificare indipendentemente i due operandi
e la destinazione, ma spesso con un insieme
ristretto di valori consentiti.

45
Istruzioni ortogonali

Un set di istruzioni si dice ortogonale se


ogni decisione nella costruzione
dellistruzione indipendente dalle altre
scelte operate. Dato che laddizione e la
sottrazione sono operazioni simili, ci si
attende di poterle utilizzare in contesti simili.
Se per laddizione si usa un formato a
3-indirizzi con indirizzamento verso i registri,
cos dovrebbe essere per la sottrazione, e in
nessun caso dovrebbero esserci particolari
restrizioni sui registri che possono essere
usati.
Un insieme di istruzioni ortogonali pi facile
da imparare per chi programma in assembly
e pi semplice da eseguire per il compilatore.
Anche limplementazione hardware risulta
spesso pi efficiente.

46
Modi di indirizzamento

Quando si accede a un operando per il


processamento di un dato o lo spostamento
di un'istruzione, ci sono alcune tecniche
standard che si usano per specificare la
locazione desiderata. La maggior parte dei
processori supportano pi metodi di
idirizzamento (anche se alcuni li supportano
tutti):

1. Indirizzamento immediato: il valore


desiderato dato come numero binario
nellistruzione.
2. Indirizzamento assoluto: listruzione
contiene in binario lindirizzo di memoria
dove si trova il valore.
3. Indirizzamento indiretto: listruzione
contiene lindirizzo binario della locazione
di memoria dove si trova lindirizzo del
valore desiderato.
4. Indirizzamento a registro: il valore
cercato in un registro, e nellistruzione
contenuto il suo riferimento.
47
5. Indirizzamento indiretto a registro:
listruzione contiene il numero di un
registro il quale a sua volta contiene
lindirizzo del valore nella memoria.
6. Indirizzamento con base pi offset:
listruzione specifica un registro (la base)
e un offset binario che va aggiunto alla
base per formare lindirizzo di memoria.
7. Indirizzamento base pi indice:
listruzione specifica un registro base e
un altro registro (lindice) che va aggiunto
alla base per formare lindirizzo di
memoria.
8. Indirizzamento base pi indice scalato:
come sopra, ma lindice viene
moltiplicato per una costante (spesso una
potenza di due) prima di essere aggiunto
alla base.
9. Indirizzamento a stack: un registro
implicito o specificato (lo stack pointer)
punta un'area di memoria (lo stack) dove
il dato viene scritto (pushed) o letto
(popped) con un funzionamento, ultimo
a entrare-primo a uscire.
48
Si noti che i nomi utilizzati per i diversi
metodi dai produttori di processori non sono
necessariamente uguali a quelli scritti sopra.
La lista pu essere espansa praticamente
allinfinito rendendo sempre pi indiretto
lindirizzamento, aggiungendo ad esempio
base pi indice pi offset, e cos via.
Comunque, la maggior parte dei comuni
metodi di indirizzamento sono riportati nella
lista di sopra.

Istruzioni per il controllo del flusso

Quando un programma deve modificare la


normale sequenza delle istruzioni, viene
utilizzata un'istruzione che modifica
esplicitamente il program counter (PC) per
gestire il flusso. La pi semplice di queste
istruzioni generalmente chiamata branch
o salto. Visto che la maggior parte dei
branch richiesti sono relativamente brevi, la
forma pi comune il PC-relative branch.

49
Un tipico formato assembly per questa
istruzione :

B LABEL


LABEL

Qui il compilatore elabora la distanza che va


aggiunta al valore di PC quando viene
eseguito il branch al fine di forzare PC a
puntare il LABEL. La distanza massima del
branch determinata dal numero di bit
dedicati allo spostamento; il compilatore
dovrebbe riportare un errore se il branch
richiesto va oltre i limiti.

Branch condizionati

Un programma di Digital Signal Processing


(DSP) pu eseguire una sequenza fissata di
istruzioni, per sempre, ma a un comune
processore solitamente richiesto di variare i

50
programmi in funzione dei dati ricevuti.
Alcuni processori (tra cui il MU0) permettono
ai valori situati nei registri generali di
controllare la presenza o meno di un branch
attraverso istruzioni del tipo:

Salta se un particolare registro zero


(o non zero, o negativo, e cos
via).
Salta se due registri specifici sono
uguali (o se sono diversi).

Registri dei codici delle condizioni

Comunque, il meccanismo usato pi di


frequente si basa sui registri dei codici delle
condizioni, che sono dei registri speciali nel
processore. Ogni volta che viene eseguita
un'istruzione per lelaborazione di un dato (o
possibilmente solo per istruzioni speciali, o
istruzioni che abilitano esplicitamente i
registri in questione), i registri dei codici delle
condizioni salvano se il risultato era zero,
51
negativo oltre i limiti, producendo un riporto
in uscita. Le istruzioni di branch condizionato
sono controllate da questi registri.

Chiamate a subroutine

Alle volte un branch viene eseguito per


chiamare un sottoprogramma che una volta
terminato dovrebbe far tornare il sistema
dove si era interrotto. Visto che il
sottoprogramma pu essere invocato da
molti posti differenti, bisogna conservare
lindirizzo della chiamata. Ci sono vari modi
per fare questo:

La routine che esegue la chiamata


potrebbe calcolare, prima di eseguire il
branch, lindirizzo di ritorno corretto e
metterlo in una locazione di memoria
standard utilizzabile dal
sottoprogramma per tornare al
programma principale.

52
Lindirizzo di ritorno pu essere scritto
in uno stack.
Lindirizzo di ritorno pu essere salvato
in un registro.

Lutilizzo di sottoprogrammi
sufficientemente comune da far si che la
maggior parte delle architetture includa
specifiche istruzioni per renderli pi efficienti.
Spesso richiedono di eseguire salti pi lunghi
dei semplici branch, quindi ha senso che
vengano trattati separatamente. Sono spesso
non condizionati.

Ritorno dal sottoprogramma

Questa istruzione riporta lindirizzo di ritorno


nel PC da dovunque fosse stato salvato (in
memoria, in un registro, o possibilmente nello
stack).

Chiamate di sistema

53
Un'altra categoria di istruzioni per il controllo
dei flussi sono le chiamate di sistema. Queste
sono dei branch a una routine del sistema
operativo, spesso associato con un passaggio
al livello privilegiato del programma in
esecuzione. Alcune funzioni nel processore,
possibilmente includendo tutte le periferiche
di input e output, hanno accesso protetto da
un codice utilizzatore. Quindi un programma
che necessita di accedere a queste funzioni
deve fare una chiamata di sistema.
Le chiamate di sistema superano le barriere
di protezione in modo controllato. Un
processore ben progettato assicurer di poter
scrivere un sistema operativo multi-user nel
quale il programma di un utente sar protetto
dagli attacchi degli altri user, potenzialmente
maligni.
Questo richiede che gli utenti maligni non
possano modificare il codice del sistema, e
quando si tenta di accedere a funzioni
protette bisogna avere le autorizzazioni.
Questa una parte complessa nella
progettazione di hardware e software. Molti
54
sistemi embedded (e alcuni sistemi desktop)
non sfruttano tutte le possibili protezioni a
livello hardware, ma un processore che non
supportasse la modalit protetta sarebbe
escluso da queste considerazioni che
richiedono tale modalit, quindi ormai quasi
tutti i microprocessori includono questo
supporto. Mentre non necessario conoscere
a fondo tutte le implicazioni dovute a un
sistema operativo sicuro, per apprezzare il
progetto base di un set di istruzioni, anche il
lettore meno informato dovrebbe essere
consapevole di tali problemi, dal momento
che alcune architetture dei processori
commerciali danno poca importanza alla
sicurezza.

Eccezioni

Lultima categoria delle istruzioni per il


controllo dei flussi comprende quei casi nei
quali un cambiamento nel flusso di controllo
non lintento principale del programmatore

55
ma una conseguenza inaspettata (e
possibilmente involontaria) di un effetto
secondario del programma. Il tentativo di
accedere alla memoria potrebbe fallire, per
esempio, a causa di un errore rilevato nel
sottosistema della memoria. Il programma
deve quindi deviare dal percorso pianificato
al fine di rimediare al problema.
Questo cambiamento non pianificato nel
flusso di controllo detto eccezione.

1.5 Scelte e compromessi nella


progettazione dei processori

Larte del progettare i processori risiede nel


definire un insieme di istruzioni che
supportino le funzioni utili al programmatore
in modo da permettere una implementazione
pi efficiente possibile. Preferibilmente, lo
stesso set di istruzioni dovrebbe anche
permettere implementazioni successive e pi
complesse con la stessa efficienza.
56
Il programmatore vorrebbe scrivere il suo
codice nel modo pi astratto possibile,
usando linguaggio di alto livello che permetta
di esprimere i concetti pi adatti al singolo
problema.
Le tendenze attuali vanno dal linguaggio
funzionale a quello orientato agli oggetti che
alzano il livello di astrazione rispetto ad altri
linguaggi come il C. Anche i pi vecchi
linguaggi di programmazione sono ormai
lontani dal linguaggio macchina.
Il gap semantico tra un linguaggio ad alto
livello e listruzione per la macchina
colmato dal compilatore, che un
programma per computer (spesso complesso)
il quale traduce il linguaggio di alto livello in
una sequenza di istruzioni macchina. Quindi
chi progetta il processore dovrebbe definire il
set di istruzioni riferendosi al compilatore
piuttosto che al programmatore. Quindi
opportuno chiedersi quali siano le istruzioni
utili per un compilatore?

57
Complex Instruction Set Computer (CISC)

Prima del 1980, landamento era quello di


rendere sempre pi complesse le istruzioni
per diminuire il gap che il compilatore doveva
colmare. Furono introdotte istruzioni che
eseguivano complesse sequenze, e
impiegavano vari cicli di clock. Furono
venduti processori con sempre pi metodi di
indirizzamento, tipi di dati, e cos via.
Lorigine di questo trend dovuto allo
sviluppo dei microcomputer negli anni '70.
Questi computer avevano una memoria
principale relativamente lenta unita al
processore costruito con circuiti integrati. Il
processore era controllato da un
microcodice situato nella ROM (Read Only
Memory) che era pi veloce della memoria
principale, quindi aveva senso implementare
funzioni che usavano sequenze di
microcodice piuttosto che fare vari accessi
alla memoria.
Con il finire degli anni '70 i microprocessori
vennero migliorati molto. Questi processori su
58
singolo chip dipendevano dallo stato dellarte
nel campo della tecnologia dei
semiconduttori per riuscire a mettere il
maggior numero di transistor su un singolo
chip, quindi il loro sviluppo prese il via con
lindustria dei semiconduttori pi che con
lavvento del computer. Come risultato, il
progetto dei microprocessori mostr una
mancanza di originalit a livello di
architettura, in particolare pensando alla
tecnologia utilizzata. I progettisti, presero le
idee dallindustria dei mini-computer dove la
tecnologia era molto differente. In particolare,
il microcodice nella ROM che serviva per le
routine complesse prendeva un'area
esageratamente grande del chip, lasciando
una zona molto piccola per le altre
caratteristiche.
Questapproccio port alla fine degli anni '70
ai CISCs (Complex Instruction Set Computers)
su singolo chip, che erano microprocessori
con il set di istruzioni dei mini-computer
gravemente ridotto a causa delle limitate
risorse di silicio disponibili.
59
La rivoluzione del RISC

In questo panorama di istruzioni sempre pi


complesse nacque il Reduced Instruction Set
Computer (RISC). Il concetto di RISC fu il
maggior ispiratore per il processore ARM;
infatti, RISC la R nellacronimo ARM. Ma
prima di guardare nel dettaglio il RISC e
lARM abbiamo bisogno di altre nozioni
riguardo cosa fanno i processori e su come
possano essere progettati rapidamente. Se
ridurre il gap semantico tra il set di istruzioni
del processore e il linguaggio di alto livello,
non la soluzione corretta, quali altre opzioni
ci sono per il progettista?

Cosa fanno i processori

Se vogliamo che un processore vada pi


veloce, dobbiamo capire in quale modo
impiega il suo tempo. un errore comune
pensare che un computer utilizzi gran parte
del tempo in elaborazioni, cio effettuando

60
operazioni sui dati dellutente. In realt
impiega molto poco tempo in questo modo.
Sebbene fanno molta aritmetica, la maggior
parte di questa riguarda gli indirizzi con lo
scopo di localizzare dati e routine di
programma necessari. Dopo averli trovati, la
maggior parte del lavoro sta nel trasporto di
questi, pi che qualunque tipo di
processamento. A livello del set di istruzioni,
possibile misurare la frequenza di utilizzo
delle varie istruzioni. molto importante per
avere misure dinamiche, che servono per
misurale la frequenza con la quale vengono
eseguite le diverse istruzioni, piuttosto che la
frequenza statica, che ci da solo un'immagine
binaria delle diverse istruzioni. Un tipico
esempio di statistica mostrato nella Tab.
1.3; queste statistiche sono state raccolte
eseguendo un programma di anteprima di
stampa su un emulatore di istruzioni ARM, ma
esattamente ci che ci si aspetterebbe da
altri programmi.

61
Queste statistiche suggeriscono che
listruzione pi importante da ottimizzare
quella relativa al trasporto dei dati, sia tra i
registri del processore e la memoria, sia tra
due registri. Queste rappresentano quasi la
met di tutte le istruzioni eseguite. Le
62
seconde pi frequenti sono le istruzioni per il
controllo dei flussi come i branch e le
chiamate di procedura che pesano per un
altro quarto. Le operazioni aritmetiche
pesano un 15% quindi poco rispetto alle
prime due.
Ora abbiamo un'idea di come il processore
utilizzi il proprio tempo, possiamo vedere dei
metodi per farlo andare pi veloce. Il pi
importante di questi utilizzare una
pipeline. Un'altra tecnica importante
lutilizzo di memorie cache, che saranno
esaminate nella Sezione 10.3. Una terza
possibilit lesecuzione di un'istruzione
super-scalare, molto complessa, e non viene
utilizzata nellARM, quindi non verr discussa
neanche in questo testo.

63
Le pipeline

Il processore esegue una singola istruzione


con una serie di passaggi. Una sequenza
tipica pu essere:

1. Caricare listruzione dalla memoria


(fetch).
2. Decodificarla per capire di che tipo
(dec).
3. Accedere ai vari operandi che sono
richiesti, situati nel banco dei registri
(reg).
4. Combinare gli operandi per ottenere il
risultato o un indirizzo di memoria (ALU).
5. Se necessario, accedere alla memoria
per prelevare un operando (mem).
6. Riscrivere il risultato nel banco dei
registri (res).

Non tutte le istruzioni necessitano di tutti


questi passaggi, ma la maggior parte di
queste ne richiedono molti. Questi passi
spesso utilizzano parti di hardware differenti,
64
per esempio la ALU utilizzata probabilmente
solo nel punto 4. Quindi, se un'istruzione non
inizia prima che la precedente sia terminata,
solo una piccola parte dellhardware del
processore utilizzata in ogni step.
Un modo ovvio per migliorare lutilizzo delle
risorse hardware, e anche la resa del
processore, potrebbe essere di iniziare
listruzione successiva prima che quella
corrente sia terminata. Questa tecnica nota
con il nome di pipelinig , ed un modo
molto efficace per valorizzare i processori
general-purpose.
Prendendo la sequenza di operazioni scritte
sopra, il processore organizzato in modo
che appena un'istruzione finisce il primo
passo e si sposta verso il secondo, listruzione
successiva parte con il punto 1. Questo si pu
vedere nella Fig. 1.13. In linea di principio
questo sistema dovrebbe portare a una
velocit sei volte superiore rispetto al caso
senza pipeline; in pratica non funziona tutto
cos bene per dei motivi che vedremo in
seguito.
65
I rischi della pipeline

abbastanza frequente nei tipici programmi


per computer, che il risultato di un'istruzione
serva come operando per la successiva.
Quando ci accade la pipeline mostrata in
Fig. 1.13 sinterrompe, fino a che il risultato
della prima istruzione non disponibile come
operando per la seconda. Listruzione 2 deve
quindi aspettare fino a che il risultato
precedente non disponibile, mostrando il
66
comportamento di Fig. 1.14. Questo
inconveniente delle pipeline noto come
read-after-write.

Le istruzioni di branch portano a risultati


anche peggiori nella pipeline in quanto la fase
di fetch dellistruzione successiva
influenzata dal calcolo dellindirizzo di
destinazione del branch e deve quindi essere
ritardata. Sfortunatamente, si eseguiranno
pi fetch successivi mentre il branch viene
decodificato e prima che venga identificato
come tale, quindi le istruzioni caricate
potrebbero essere scartate. Se, per esempio,
lelaborazione dell'indirizzo del branch
67
eseguita nel passaggio ALU della pipeline in
Fig. 1.13, tre istruzioni saranno caricate prima
che la destinazione del branch sia disponibile
(vedere la Fig. 1.15). Se possibile meglio
elaborare nella pipeline prima il risultato del
branch, anche se ci richieder
probabilmente dellhardware dedicato. Se
listruzione di branch ha un formato
prefissato, allora il risultato pu essere
calcolato in modo speculativo (cio, prima
che si sia determinato che si tratti
effettivamente di un branch) durante la fase
dec, riducendo cos la latenza del branch a
un singolo ciclo. Bisogna per notare che in
questa pipeline potrebbero esserci ancora dei
rischi per un branch condizionato, dovuti alla
dipendenza dal risultato del codice
condizionale dellistruzione che precede il
branch. Alcune architetture RISC (anche se
non lARM) definiscono che listruzione dopo il
branch venga eseguita sia nel caso in cui il
branch sia svolto, sia che non venga svolto.
Questa tecnica nota come branch
ritardato.
68
Efficienza della pipeline

Anche se ci sono tecniche che riducono


limpatto di questi problemi sulle pipeline,
non possono eliminarli del tutto. Pi stadi ci
sono nella pipeline pi sono i problemi. Per un
processore abbastanza semplice, si
riscontrano benefici significativi introducendo
una pipeline da cinque stadi al posto di una
69
da tre, ma andando oltre la regola di
aumentare gli stadi inizia a non valere e la
complessit aumenta superando i benefici.
chiaro che le pipeline forniscono benefici
per tutte quelle istruzioni che seguono un
processo simile. Processori con istruzioni
molto complesse che si comportato tutte in
modo differente sono difficili da
implementare con una pipeline. Nel 1980 il
CISC pi avanzato non aveva implementata
una pipeline a causa: del ridotto spazio di
silicio disponibile, dei limitati strumenti per la
progettazione e dellelevata complessit nel
progettare una simile pipeline.

1.6 Il Reduced Instruction Set


Computer

Nel 1980 Patterson e Ditzel pubblicarono un


articolo intitolato The Case for the Reduced
Instruction Set Computer. In questo lavoro
innovativo spiegarono il loro punto di vista,
70
cio che larchitettura ottimale per un
processore a singolo chip non dovesse essere
uguale a quella per un processore con pi
chip. I loro argomenti furono in seguito
supportati dai risultati ottenuti da un gruppo
di laureati di Berkeley, i quali progettarono un
processore con un'architettura RISC. Questo
progetto, il Berkeley RISC I, era pi semplice
dei processori CISC in commercio allepoca e
richiese uno sforzo molto inferiore per essere
sviluppato, ma ciononostante raggiungeva
performance molto simili.
Il set di istruzioni del RISC I differiva da quello
dei CISC in commercio, per vari aspetti.
Questo set era caratterizzato da:

Architettura RISC

Istruzioni con dimensione fissa


(32-bit) e pochi formati; i processori CISC
avevano tipicamente istruzioni di
dimensione variabile e vari formati.

71
Architettura load/store nella quale le
istruzioni che processano dati operanti
solo sui registri sono separate da quelle
che accedono alla memoria; i processori
CISC tipicamente permettevano di
utilizzare operandi sia residenti in
memoria che nei registri.
Un grande banco di trentadue registri
da 32-bit, ognuno dei quali pu essere
usato per ogni scopo, al fine di rendere
efficiente larchitettura load/store; i
registri dei CISC erano anche di pi, ma
consentivano utilizzi specifici (per
esempio, nel Motorola MC68000 cerano i
registri per i dati e quelli per gli indirizzi).

Queste differenze semplificarono


notevolmente il progetto del processore e
permisero ai progettisti di implementare
larchitettura utilizzando caratteristiche
organizzative che contribuirono alle
performance del prototipo.

72
Organizzazione del RISC
Logica di decodifica delle istruzioni
hard-wired; i processori CISC usavano un
pesante microcodice in ROM per
decodificare le istruzioni.
Esecuzione con una pipeline; i processori
CISC, quando previsto, permettevano solo
piccole sovrapposizioni tra istruzioni
consecutive (ora lo fanno).
Esecuzione in un solo ciclo di clock; i
processori CISC richiedevano spesso vari
cicli per completare una singola istruzione.

Integrando in una sola volta tutti questi


cambiamenti organizzativi e nellarchitettura,
il microprocessore RISC di Berkeley super il
problema che affliggeva il progresso grazie a
graduali miglioramenti.

Vantaggi del RISC

Petterson e Ditzel sostenevano che il RISC


offriva tre vantaggi principalmente:
73
Una minore dimensione.
Un processore semplice avrebbe richiesto
meno transistor e quindi un'area di silicio
inferiore. Quindi lintera CPU dovr entrare
in un chip e se il RISC occupasse meno
spazio, ci sarebbe un'area di silicio libera
per introdurre caratteristiche aggiuntive
come memoria cache, funzioni per la
gestione della memoria, e cos via.

Tempo di sviluppo ridotto.


Un processore semplice richiede sforzi
minori per essere progettato e quindi avr
un costo di progetto inferiore e si adatter
meglio al processo tecnologico.

Prestazioni pi elevate.
Questa la pi interessante! I primi due
punti sono facili da accettare, ma in una
realt in cui le migliori prestazioni sono
sempre accompagnate da una
complessit crescente, quest'idea pi
difficile da capire.

74
Largomentazione suonava pi o meno cos:
le cose pi piccole hanno una frequenza
naturale pi alta (gli insetti battono le ali pi
velocemente degli uccellini, i quali a loro
volta le battono pi rapidamente degli uccelli
pi grandi, e cos via). Quindi un processore
semplice dovrebbe permettere di lavorare a
una frequenza di clock maggiore. Quindi
iniziamo a progettare il nostro processore
complesso partendo da uno semplice, dopo
aggiungiamoci istruzioni complesse una alla
volta. Quando aggiungiamo un'istruzione
complicata questa svolger funzioni di pi
alto livello in modo pi efficiente, ma
abbasser anche un po il clock di tutte le
istruzioni coinvolte. Possiamo misurare i
benefici complessivi di un programma tipico,
e quando lo facciamo vediamo che tutte le
istruzioni complesse contribuiscono ad
abbassare la velocit di esecuzione. Infine le
aggiungiamo al semplice processore da cui
siamo partiti.

75
Questi argomenti sono stati sostenuti da
risultati sperimentali e un prototipo di
processore (il Berkeley RISC II venne poco
dopo il RISC I). Inizialmente le aziende di
processori erano scettiche ma molte nuove
imprese che progettavano processori per
conto loro videro un'opportunit per
abbattere i costi di sviluppo ed entrare cos
nel mercato. Questi RISC commerciali, il
primo dei quali fu ARM, mostrarono che lidea
funzionava, e dal 1980 tutti i nuovi processori
general-purpose abbracciarono, chi pi chi
meno, i concetti del RISC.

Analisi a posteriori dei RISC

Dal momento che il RISC ormai ben


consolidato in ambito commerciale,
possibile guardare indietro per capire meglio
qual stato veramente il suo contributo per
levoluzione dei microprocessori. I primi RISC
raggiunsero le loro prestazioni attraverso:

76
Pipelining.
La pipeline il modo pi semplice per
ottenere processori con velocit
raddoppiate o triplicate. Un insieme di
istruzioni semplici semplifica
notevolmente il progetto della pipeline.

Alta frequenza di clock ed esecuzione


in un solo ciclo.
Nel 1980 le normali memorie a
semiconduttore (DRAM Dynamic
Random Access Memory) potevano
lavorare a circa 3 MHz quelle ad accesso
casuale e fino a 6 MHz quelle ad accesso
sequenziale. I processori CISC di quel
periodo potevano accedere alla memoria
al massimo a 2 MHz, quindi la banda della
memoria non era sfruttata del tutto. I
processori RISC essendo pi semplici,
poterono essere progettati per coprire
lintera banda di frequenze disponibile.

Nessuna di queste propriet caratteristica


dellarchitettura, ma entrambe dipendono dal
77
fatto che larchitettura stata semplificata
sufficientemente per poterle incorporare. Le
architetture RISC furono di successo perch
erano abbastanza semplici da consentire ai
progettisti di sfruttare queste tecniche
organizzative. Era del tutto fattibile
implementare istruzioni di lunghezza fissata,
e un'architettura load/store, il tutto usando
un microcodice, ma senza pipeline e con
esecuzioni in vari cicli di clock, non si
avevano grossi vantaggi rispetto ai CISC in
vendita. Era impossibile allepoca
implementare un CISC con pipeline ed
esecuzioni in un singolo ciclo. Ma ora lo !

Frequenza di clock

Come conclusione allanalisi svolta sopra, ci


sono due aspetti della frequenza di clock che
vanno spiegati:

I processori CISC degli anni 80 avevano


spesso frequenze di clock maggiori

78
rispetto ai primi RISC, ma impiegavano
vari cicli di clock per eseguire un accesso
alla memoria, quindi eseguivano un
numero inferiore di accessi alla memoria
per unit di tempo. Attenzione a giudicare
un processore solo dalla sua frequenza di
clock!
Lo scostamento tra il rate di accessi alla
memoria eseguibili dal CISC e la
larghezza di banda disponibile appariva in
contrasto con quanto detto nel paragrafo
Complex Instruction Set Computer dove
luso del microcodice era giustificato nei
minicomputer dei primi anni 70, poich
la memoria principale era lenta rispetto al
processore. La soluzione di
questapparente contraddizione sta nel
fatto che le memorie in dieci anni hanno
fatto grandi balzi tecnologici in avanti,
mentre i primi CISC erano pi lenti dei
processori dei minicomputer. Questa
diminuzione di velocit dovuta al
passaggio dalla tecnologia bipolare a
quella NMOS, che serviva per raggiungere
79
la densit di porte necessarie per avere
un processore su singolo chip.

Inconvenienti dei RISC

I processori RISC hanno chiaramente vinto la


sfida sulle performance e hanno abbassato i
costi di progettazione, hanno quindi solo
caratteristiche positive? Col passare del
tempo sono venuti alla luce due
inconvenienti:

I RISC hanno generalmente una densit di


codice inferiore rispetto ai CISC.
I RISC non eseguono il codice x86.

La seconda difficile da risolvere, anche se


un software che emula il PC disponibile per
molte piattaforme RISC. comunque un
problema se si vuole costruire una macchina
IBM compatibile; per altre applicazioni si pu
tranquillamente ignorare.

80
La bassa densit di codice deriva dalla
lunghezza fissa delle istruzioni ed un
problema pi serio per un gran numero di
applicazioni. In assenza di una cache, la
bassa densit di codice porta alla necessit di
utilizzare una banda maggiore per il fetch
delle istruzioni nella memoria principale, con
il risultato che la memoria assorbir pi
potenza. Quando il processore incorpora sul
chip una cache di una dimensione fissata, la
bassa densit di codice porta ad avere un
minor numero di istruzioni salvate e di
conseguenza una memoria con banda
maggiore e pi assorbimento di potenza.

Densit di codice ARM e Thumb

Il processore ARM progettato basandosi sul


principio del RISC, ma per varie ragioni soffre
di meno per la bassa densit di codice
rispetto alla maggior parte dei RISC. La
densit di codice raggiunta, comunque
inferiore a quella ottenibile con i CISC. Dove

81
questa risulta di primaria importanza. La ARM
Limited introdusse in vari suoi processori, un
nuovo meccanismo, chiamato architettura
Thumb. Il set di istruzioni nella modalit
Thumb compresso a 16-bit rispetto
alloriginale set di istruzioni ARM a 32-bit, e
impiega un hardware per la decompressione
dinamica delle istruzioni nella pipeline. La
densit di codice nella modalit Thumb pi
alta di quella ottenibile dalla maggior parte
dei processori CISC. Larchitettura Thumb
verr descritta nel Cap. 7.

Oltre il RISC

difficile immaginare che il RISC sia lo stadio


finale nelle architetture dei computer, quindi
ci sono segni di ulteriori passi avanti che
renderanno lapproccio dei RISC obsoleto?
Non ci sono sviluppi visibili al momento in cui
viene scritto questo libro, che suggeriscano
un cambiamento cos radicale come fu il
RISC, ma il set di istruzioni continua a

82
evolversi fornendo un supporto sempre pi
efficiente per applicazioni nuove, come quelle
multimediali.

1.7 Progettazione di sistemi a


basso consumo

Sin dallintroduzione dei computer digitali 50


anni fa c stato un continuo miglioramento
del rapporto costi/efficienza a un tasso non
paragonabile a nessunaltra tecnologia. Come
effetto secondario di questo processo, i
consumi di potenza dovevano essere
necessariamente abbassati. Solo
recentemente, comunque, muoversi verso il
minimo consumo di potenza diventato
importante come laumento delle prestazioni,
e in certe applicazioni anche di pi. Questo
cambiamento si avuto in seguito alla
crescita del mercato di dispositivi portatili
alimentati a batteria come i cellulari o i

83
lap-top, che utilizzano componenti dalle
altissime prestazioni.
In seguito allintroduzione dei circuiti integrati
il business dei computer si trovato nella
situazione ottimale in cui i transistor
diventavano sempre pi piccoli e meno
costosi, avevano prestazioni migliori e minori
consumi di potenza. Ora, per, i progettisti
hanno iniziato a lavorare specificamente per
ottenere consumi inferiori, anche sacrificando
un po le prestazioni se necessario per certe
applicazioni.
Il processore ARM si trova al centro di questo
sviluppo indirizzato allefficienza dei consumi.
Sembra pertanto appropriato considerare le
problematiche di una progettazione rivolta a
ridurre i consumi.

Dove va la potenza?

Il punto di partenza per una progettazione


volta a ridurre i consumi, capire in che
modo viene assorbita la potenza nei circuiti

84
attuali. La tecnologia dominante per
elettronica di alte prestazioni, quella dei
CMOS, che ha intrinsecamente buone
caratteristiche per una progettazione
efficiente, quindi vediamo in che modo
consumano i circuiti.
Un tipico circuito CMOS quello che
implementa delle porte NAND statiche,
illustrate in Fig. 1.2. Tutti i segnali vanno dalla
tensione di alimentazione fino alla massa,
quindi Vdd e Vss, fino a poco fa lo standard
erano 5 volt di alimentazione, ma ora
richiedono tipicamente 3 volt o addirittura tra
1 e 2 volt, e landamento di ridurre sempre
di pi questa tensione nel futuro. Le porte
operano connettendo luscita sia alla tensione
Vdd che a Vss attraverso una rete di pull-up
fatta da PMOS nel primo caso e di NMOS per
il secondo. Quando entrambi gli ingressi sono
prossimi a uno degli estremi, allora una delle
due reti condurr e laltra inevitabilmente no,
quindi non c un collegamento tra V dd e Vss
allinterno della porta. Inoltre, luscita
normalmente connessa allingresso di una
85
porta simile e vedr quindi un carico
capacitivo. Una volta che luscita si trova
vicino a un estremo non servir corrente per
tenerla in quello stato. Quindi subito dopo
che la porta passa da uno stato allaltro, il
circuito raggiunge una condizione di stabilit
e non verr prelevata corrente
dallalimentazione.
Questa caratteristica di consumare potenza
solo nel momento in cui si passa da un livello
allaltro non comune a tutte le tecnologie
ed stato il fattore predominante che ha
portato a scegliere la tecnologia CMOS per i
circuiti integrati ad alta densit.

Potenza assorbita da componenti CMOS

Il consumo totale di potenza in un circuito


CMOS si pu dividere in tre parti:

Potenza di commutazione.
Quando gli ingressi della porta si trovano a
un livello intermedio, sia le reti PMOS che

86
quelle NMOS conducono. Questo causa un
temporaneo collegamento tra Vdd e Vss.
Con un circuito ben progettato (cio in
generale dove si evitano le transizioni
lente) la potenza di cortocircuito solo
una piccola frazione di quella di
commutazione.

Correnti di perdita.
La rete di transistor deve condurre una
corrente piccolissima quando si trova nello
stato di off; sebbene questa corrente nei
processi convenzionali molto piccola
(frazioni di nA per porta), lunica
corrente nel circuito quando questo
alimentato ma inattivo, e pu essere
alimentata per un lungo periodo. Questa
corrente trascurabile nei circuiti attivi.
In un circuito attivo che sia ben progettato
la potenza di commutazione deve
dominare, la corrente di cortocircuito pu
aggiungere un 10%-20%, e le correnti di
perdita possono non essere trascurate
solo quando il circuito inattivo.
87
Comunque landamento di abbassare
sempre pi la tensione di alimentazione,
questo porta a trovare dei compromessi
tra prestazioni e correnti di perdita come
verr spiegato in seguito, infatti, le perdite
causano sempre pi preoccupazioni in
vista degli sviluppi futuri.

Potenza assorbita nei circuiti CMOS

La potenza totale dissipata, Pc, di un circuito


CMOS, trascurando le perdite e la parte di
cortocircuito, pertanto data dalla somma
delle dissipazioni in ogni porta (gate) g
presente nel circuito C:

dove f la frequenza di clock, A g lactivity


factor della porta (riflette il fatto che non
tutte le porte commutano a ogni ciclo) e CgL

88
il carico capacitivo dato dalla porta. Notare
che con due transizioni per ciclo di clock si ha
un activity factor di 2.

Progetto di circuiti con basso


assorbimento di potenza

Tipicamente il carico capacitivo della porta


dipende dal processo tecnologico e quindi
non controllabile direttamente dal
progettista. Il resto dei parametri nellEq. 3
suggeriscono vari approcci per sviluppare un
progetto che abbassi i consumi. Verranno ora
elencati in ordine di importanza:

Minimizzare la tensione di alimentazione,


Vdd.
Avendo la potenza, una dipendenza
quadratica dalla tensione di alimentazione,
fa di questa un obiettivo primario. Verr
discusso meglio in seguito.
Minimizzare lattivit del circuito, A.
Tecniche quali la moltiplicazione del clock
89
rientrano in questambito. Il clock
dovrebbe essere reso inattivo per tutte le
sezioni hardware non utilizzate.

Minimizzare il numero di porte.


Circuiti semplici utilizzano meno potenza
di quelli complessi, a parit di altri fattori,
poich la sommatoria fatta su un
numero minore di contributi.

Minimizzare la frequenza di clock, f.


Evitare frequenze di clock inutilmente
elevate chiaramente desiderabile, ma
daltronde questo ridurr anche le
performance, facendo restare invariato il
rapporto tra consumi ed efficienza
(misurato, ad esempio, in MIPS Milions of
Instruction Per Second per watt). Se,
tuttavia una frequenza di clock ridotta
consente di lavorare a una Vdd inferiore,
questo porter grandi benefici al rapporto
potenza/efficienza.

90
Abbassare la Vdd

Con il diminuire delle dimensioni dei circuiti


CMOS, c anche una spinta a ridurre la
tensione di alimentazione. Questo dovuto al
fatto che i materiali per fare i dispositivi non
possono sopportare un campo elettrico
eccessivamente elevato, e con il rimpicciolirsi
dei transistor se la tensione non viene ridotta
il campo elettrico crescer continuamente.
Comunque, con il crescente interesse
nellabbassare i consumi ci si aspetta che la
tensione di alimentazione si riduca pi del
necessario in modo da evitare anche processi
di breakdown.
Cosa impedisce di usare tensioni cos basse
gi adesso?
Il problema riducendo la Vdd un
conseguente abbassamento delle prestazioni
del circuito. La corrente di saturazione nei
circuiti data da:

91
dove Vt la tensione di soglia del transistor.
La carica presente ai nodi del circuito
proporzionale a Vdd, quindi la massima
frequenza di lavoro sar:

Da cui si vede che la massima frequenza


operativa si riduce in modo solidale a V dd. La
diminuzione delle prestazioni in processi
sub-micrometrici pu non essere cos grave
come suggerito dallEq. 5 poich la corrente
ad alte tensioni pu essere limitata dalla
velocit di saturazione della carica, ma ad
ogni modo un po le prestazioni caleranno.
LEq. 5 ci suggerisce che un modo ovvio per
risolvere questo problema sarebbe abbassare
la Vt. Tuttavia la corrente di perdita
fortemente legata a Vt.

92
Anche una piccola diminuzione di Vt pu
aumentare significativamente la corrente di
perdita, aumentando lassorbimento da parte
del circuito inattivo. Bisogna quindi trovare un
compromesso tra il massimizzare le
prestazioni e minimizzare la potenza in
standby, e la questione va considerata con
attenzione dai progettisti di sistemi in cui
entrambe sono importanti. Anche quando la
potenza di standby non fondamentale, il
progettista deve stare attento a massimizzare
le prestazioni usando transistor con tensione
di soglia troppo bassa, perch questo causa
un aumento della potenza di perdita che
potrebbe diventare comparabile con quella
dinamica, necessario quindi tenerne conto
quando si scelgono i package e il sistema di
raffreddamento.

93
Strategie per abbassare i consumi

Per concludere questa introduzione alle


tecniche di progettazione per bassi consumi
di potenza, elenchiamo alcune strategie:
Minimizzare Vdd.
Scegliere la pi bassa frequenza di clock
che garantisca le prestazioni richieste, poi
lalimentazione pi bassa possibile che
permetta tale frequenza di lavoro e il
funzionamento di tutti i componenti. Stare
attenti a non ridurre troppo la tensione
per evitare che la potenza di perdita si
avvicini troppo a quella di standby.
Minimizzare lattivit off-chip.
Le capacit off-chip sono molto maggiori
dei carichi nel chip, quindi sempre
minimizzare lattivit off-chip. Evitare che
nei transitori siano pilotati carichi off-chip
e utilizzare le cache per ridurre gli accessi
alle memorie off-chip.
Minimizzare lattivit on-chip.
Meno importante della precedente, ma ad
94
ogni modo evitare di attivare parti di
circuito inutilizzate (per esempio con
moltiplicatori di clock) e introdurre la
modalit sleep quando possibile.
Sfruttare il parallelismo.
Quando la potenza della tensione di
alimentazione una variabile
indipendente, il parallelismo pu essere
sfruttato per accrescere il rapporto
potenza/efficienza. La duplicazione del
circuito permette di raggiungere le stesse
prestazioni delloriginale ma con una
frequenza di clock dimezzata, e con
unalimentazione ridotta.

La progettazione per basse potenze unarea


di ricerca attiva nella quale le idee nascono
continuamente. Si prevede che nel prossimo
decennio il miglioramento dei processi
tecnologici e delle capacit di progettazione
permetteranno di incrementare
considerevolmente la velocit e il rapporto
potenza/efficienza nei circuiti digitali.

95