Sistemi Elettronici Digitali
Sistemi Elettronici Digitali
Sistemi Elettronici Digitali
Alberto Tibaldi
25 giugno 2009
Indice
4 Circuiti aritmetici 33
4.1 Sommatori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
4.1.1 Ripple-carry adder . . . . . . . . . . . . . . . . . . . . 35
4.2 Sottrazioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.2.1 Overflow . . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.3 Sommatori veloci . . . . . . . . . . . . . . . . . . . . . . . . . 37
4.3.1 Carry-bypass adder . . . . . . . . . . . . . . . . . . . . 38
4.3.2 Carry-select adder . . . . . . . . . . . . . . . . . . . . 38
4.3.3 Carry-lookahead adder . . . . . . . . . . . . . . . . . . 39
1
4.4 Altre funzioni aritmetiche . . . . . . . . . . . . . . . . . . . . 40
4.4.1 Incrementatore - Contrazione . . . . . . . . . . . . . . 40
4.4.2 Moltiplicatore / divisore per 2n . . . . . . . . . . . . . 41
4.4.3 Moltiplicatore binario . . . . . . . . . . . . . . . . . . . 41
4.5 Cenni a rappresentazioni numeriche alternative . . . . . . . . 42
5 Circuiti sequenziali 43
5.1 Principali blocchi circuitali con memoria . . . . . . . . . . . . 43
5.1.1 SR-Latch . . . . . . . . . . . . . . . . . . . . . . . . . 43
5.1.2 Gated D-Latch . . . . . . . . . . . . . . . . . . . . . . 44
5.1.3 Edge-Triggered D flip-flop . . . . . . . . . . . . . . . . 44
5.2 Metastabilità . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
5.2.1 Parametri temporali del D-flip-flop . . . . . . . . . . . 47
5.3 Macchine a stati finiti . . . . . . . . . . . . . . . . . . . . . . 49
5.4 Alcuni semplici esempi di circuiti sequenziali . . . . . . . . . . 52
5.4.1 Shift register . . . . . . . . . . . . . . . . . . . . . . . 53
5.4.2 Flip-flop tipo non-D . . . . . . . . . . . . . . . . . . . 53
5.4.3 Contatori asincroni . . . . . . . . . . . . . . . . . . . . 54
5.4.4 Contatori sincroni . . . . . . . . . . . . . . . . . . . . . 55
5.4.5 Contatori a caricamento parallelo . . . . . . . . . . . . 55
5.4.6 Contatori a frequenza elevata . . . . . . . . . . . . . . 55
5.5 Macchine a stati algoritmiche - ASM Charts . . . . . . . . . . 56
5.5.1 Codifica degli stati . . . . . . . . . . . . . . . . . . . . 57
5.5.2 ASM Charts . . . . . . . . . . . . . . . . . . . . . . . . 57
5.5.3 Progetto di sistemi elettronici digitali complessi . . . . 59
5.6 Pipelining . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
7 Memorie 68
7.1 Random Access Memory (RAM) . . . . . . . . . . . . . . . . 69
7.1.1 Static Random Access Memory . . . . . . . . . . . . . 70
7.1.2 Dynamic Random Access Memory . . . . . . . . . . . . 70
7.1.3 Content-Addressable Memory . . . . . . . . . . . . . . 73
7.2 Read Only Memory (ROM) . . . . . . . . . . . . . . . . . . . 74
2
Capitolo 1
Introduzione all’elettronica
digitale
L’elettronica digitale basa tutta la propria forza sulla semplicità derivata dal-
l’uso di un’algebra binaria: l’algebra di Boole; al fine di studiare l’elettronica
digitale, quindi sarà fondamentale un’introduzione ai principi dell’algebra di
Boole, che sarà utilizzata per tutta la trattazione.
In termini elettronici, l’algebra di Boole si può pensare come un linguaggio
formale in grado di gestire, in sostanza, gli stati di un interruttore.
Gli interruttori possono essere collegati tra loro (ed eventualmente ad altri
dispositivi) mediante diverse topologie: in serie, in parallelo, o in altri modi.
Tutti questi altri modi vengono rappresentati, mediante un particolare tipo
di simboli: le porte logiche.
0·1=1·0=0 1+0=0+1=1
Se x = 0 =⇒ x = 1
Se x = 1 =⇒ x = 0
3
A partire da questi assiomi, è possibile ricavare le seguenti proprietà:
• Proprietà commutativa:
x·y =y·x
x+y =y+x
• Proprietà associativa:
x · (y · z) = (x · y) · z
x + (y + z) = (x + y) + z
• Proprietà distributiva:
x · (y + z) = x · y + x · z
x + y · z = (x + y) · (x + z)
• Proprietà combinativa:
x·y+x·y =x
(x + y) · (x + y) = x
• Proprietà “Absopition”:
x+x·y =x
x · (x + y) = x
• Teoremi di De Morgan:
x+x·y =x+y x · (x + y) = x · y
4
• Proprietà “Consensus”:
x·y+y·z+x·z =x·y+x·z
(x + y) · (y + z) · (x + z) = (x + y) · (x + z)
5
di realizzare la stessa funzione logica; spesso quindi si utilizzano, a parti-
re dalla tavola di verità, tecniche in grado di semplificare notevolmente le
espressioni rispetto a quelle canoniche, riducendo di conseguenza il numero
di componenti da utilizzare; il più famoso di questi metodi consiste nell’uso
delle mappe di Karnaugh.
1.2.1 VHDL
Al fine di progettare un sistema digitale, è possibile usare, come si dirà fre-
quentemente nel resto della trattazione, metodi fondamentalmente manuali,
basati sull’uso della teoria che verrà almeno in buona parte presentata, o
metodi informatici, basati sull’uso di linguaggi di descrizione dell’hardware.
I due linguaggi di questo genere più utilizzati ai giorni nostri sono VHDL e
Verilog.
Si noti che si parla di “linguaggi di descrizione” e non di “linguaggi di
programmazione”: come si vedrà meglio in seguito, VHDL (il linguaggio che
verrà utilizzato per il resto della trattazione) è un linguaggio nato (per quanto
poi si sia evoluto anche in altre direzioni) per descrivere sistemi elettronici
digitali. Assieme al linguaggio di descrizione, in seguito, sono stati introdotti
altri strumenti informatici ed elettronici i quali, basandosi sulla descrizione
proposta dal linguaggio, permettono la simulazione (a componenti ideali e
pure reali, come si vedrà) del sistema, e addirittura la realizzazione pratica
mediante tecnologie di vario tipo (processo di “sintesi”).
Si noti che questo tipo di linguaggio non è una soluzione definitiva, una so-
luzione in grado di eliminare il mestiere del progettista: è sempre e comunque
necessario avere le idee chiare riguardo il sistema che si intende progettare,
prima di realizzarlo (o farlo realizzare dal sintetizzatore); nella fattispecie, i
grandi passi da seguire sono i seguenti:
• Descrivere nella maniera più prossima possibile, per quello che VHDL
permette, il circuito ideato, in modo da effettuare in seguito i processi
di simulazione e sintesi.
6
1.3 Progetto di circuiti combinatori
Sia per quanto riguarda i circuiti combinatori sia quelli sequenziali, esisto-
no tecniche informatiche in grado di descrivere e sintetizzare, “in pratica”,
i circuiti logici di qualsiasi tipo. Al fine di poter tuttavia implementare
metodi migliori per la sintesi, e comunque di poter correggere facilmente
eventuali errori o mancate minimizzazioni, un buon ingegnere deve essere in
grado di sintetizzare manualmente (nei limiti della complessità) un circuito;
le motivazioni dietro questo fatto sono sostanzialmente due dunque:
7
4. Si mappa il progetto finora realizzato in una tecnologia disponibile
(porte logiche del tipo a disposizione);
5. Si verifica il corretto funzionamento del sistema.
8
– Una orta OR viene mappata in una porta NAND semplicemente
introducendo un inverter prima di ciascun ingresso;
Y = S · I0 + S · I1
Come funziona questo circuito? si ha un meccanismo di decodifica del
segnale di controllo, regolato in questo caso da un inverter, e una serie di
porte AND, le cui uscite si collegano a una OR. Sostanzialmente, dati i
segnali di selezione, al fine di poter selezionare solo uno dei segnali di ingresso,
è necessario effettuare un’operazione di “splitting”, di “suddivisione”, cosa
effettuabile con un decoder, ossia un circuito in grado di “decodificare” un
certo segnale. Il fatto di mandare ciascun segnale di selezione decodificato
in porte AND, il cui altro ingresso è un segnale di ingresso, permette di
selezionare, mediante tutti questi segnali “splittati”, un singolo segnale, ossia
l’ingresso che si intende selezionare. Questa tecnica si può generalizzare:
introducendo in ingresso un decoder per i segnali di controllo, collegando
le uscite di questo a un’AND e le uscite delle AND a degli OR, è possibile
generalizzare la costruzione logica del multiplexer. Come implementare un
decoder sarà visto in seguito.
Si noti che, a partire da multiplexer a “pochi” ingressi, è possibile realiz-
zarne di più “grossi”:
9
Ogni segnale di controllo, tendenzialmente, viene usato per comandare
i segnali di controllo di un “livello” di multiplexer, in modo da selezionare
il segnale “a livelli”, fino a ottenere in uscita, di tutti gli ingressi, quello
interessato1 .
Una volta descritto e implementato un multiplexer, studiamo un modo di
realizzare, a partire da essi, generici circuiti combinatori. Una volta scritta la
tavola di verità, la si ordina in modo da avere gli ingressi in ordine crescente;
generalmente, a questo punto, è possibile suddividere in maniera facile la
funzione logica in due parti: una con gli ingressi che “cominciano per zero”,
una con gli ingressi che “cominciano con uno”; il fatto di aver detto “dividere”
non è casuale: un multiplexer può servire per “dividere” e “scegliere” quale
delle due metà della tavola di verità realizzare, con funzioni logiche di tipo
diverso, a seconda della relazioni.
Per chiarezza, riassumiamo come si deve procedere:
10
w1 · f (0; w2 ; ...; wn ) + w1 · f (w1 ; w2 ; ...; wn ) = w1 · w2 · f (0; 0; w3 ; ...; wn )+
+w1 ·w2 ·f (0; 1; w3 ; ...; wn )+w1 ·w2 ·f (1; 0; w3 ; ...; wn )+w1 ·w2 ·f (1; 1; w3 ; ...; wn )
2. Spesso, capita di dover sintetizzare circuiti in cui gli ingressi della fun-
zione logica sono in numero maggiore rispetto a quelli della LUT tec-
nologicamente realizzabile. In questi casi, può tornare molto utile il
11
teorema di espansione di Shannon, in grado di “separare” dalle funzio-
ni una variabile (che diventerà la variabile di riferimento), in modo da
realizzare con una o più LUT i cofattori, quindi usare una o più LUT
per “agganciare” tra loro i vari “pezzi di funzione”. Trucco spesso con-
veniente è quello di cercare una variabile “sempre presente” nelle varie
sottofunzioni, e, se possibile, fare in modo che i cofattori siano uno
l’opposto (il NOT) dell’altro, in modo da semplificare ulteriormente il
circuito e ridurre ulteriormente il numero di LUT da utilizzare.
1.3.5 Decoders
Un altro metodo si sintesi di circuiti combinatori è basato sull’uso di decoders.
Un decoder è un blocco combinatorio in grado di accettare un certo in-
sieme di ingressi, codificati in qualche maniera, e di abilitare una sola linea
in uscita; spesso il circuito è dotato di un segnale di “enable”, atto ad atti-
vare o meno il circuito, e stabilire se usare o meno una delle uscite, ossia se
abilitarne una o se non abilitarne nessuna.
L’idea alla base del decoder è la seguente:
Sostanzialmente, collegando delle porte AND a n + 1 ingressi, dove n è
il numero di ingressi del decoder, lasciando l’ultimo per il segnale di enable,
e a tutte le combinazioni degli ingressi e dei loro complementari, si riesce ad
ottenere questo tipo di funzione. Ciascun ingresso viene complementato; nelle
porte AND vengono introdotti i segnali che, se entrambi affermati, faranno
uscire “1”. Solo un segnale in uscita di tutte le AND può essere affermato: le
AND sono introdotte in modo da essere attivate se e solo se tutti i segnali al
loro interno sono unitari; usando combinazioni diverse, solo una combinazione
sarà interamente affermata. A seconda degli ingressi, dunque, solo una AND
sarà attiva. Si aggiunge per ciascuna AND un segnale aggiuntivo, ossia quello
di enable: se il segnale di enable è attivo allora una delle AND potrà avere
uscita affermata, altrimenti nessuna.
Trattandosi di blocchi abbastanza complicati, esistono metodi semplici
per effettuare la sintesi di decoder complessi a partire da blocchi semplici, a
più stadi, proprio come nel caso dei multiplexer: volendo realizzare, a partire
dal decoder 2 to 4, un decoder 4 to 16, è sufficiente usare un primo decoder,
dotato di segnale di enable, che gestirà i successivi stadi; questi verranno
“guidati” da due segnali w0 e w1 , e i loro segnali di enable deriveranno,
semplicemente, dalle uscite del primo stadio!
I decoder sono fondamentali, per molti scopi, ad esempio per la realiz-
zazione di memorie: per gestire le interfacce delle memorie vi sono sistemi
di decodifica in grado di selezionare quale degli ingressi va aperto, quindi
quale delle parole di memoria va usata. In una memoria da un megabyte, ad
12
esempio, serviranno diverse parole da un bytte, decoder a 20 linee di ingresso
e quindi 220 linee in uscita.
Un altro uso particolare dei decoder è la realizzazione di multiplexer:
usando un decoder associato (in uscita) a una serie di buffer tri-state (uno
per uscita), si ottiene un dispositivo di tipo selettivo:
Si noti che se, usando invece che dei buffer tri-state delle porte AND, le
cui uscite confluiscono in un OR, si può ottenere comunque un multiplexer,
senza ricorrere ai tri-state.
Un modo generale di realizzare un decoder è il seguente: date 2n uscite,
ciascuna proverrà da una batteria di porte AND; partendo dall’uscita, si va
a ritroso, poichè questa batteria “finale” di AND sarà a sua volta controllata
da stadi di decodifica di ordine inferiore. Quando si arriva, a suon di batterie
di AND, al dover introdurre lo stadio 1 to 2, esso sarà semplicemente un filo
in parallelo ad un inverter: esso di fatto “sdoppia” il segnale, dividendolo in
sè stesso e nel suo complementare, generando il più elementare degli stadi di
decodifica.
Terminata la descrizione del decoder, passiamo ad una descrizione del
metodo di sintesi già citato: il metodo di sintesi di circuiti mediante decoder
è sostanzialmente il seguente: come si sa, il decoder fornisce, dato un certo
numero di ingressi, tutte le possibili combinazioni in uscita; data questa
osservazione, l’idea potrebbe essere quella di prendere la tavola di verità, e
usare il fatto che un decoder produce un “1” in uscita quando si desidera.
Collegando a delle porte OR ciascuna delle uscite interessate, si realizza il
circuito.
Proponiamo un esempio banale: supponendo di voler realizzare la funzio-
ne logica f , definita come:
8
X
f (w1 ; w2 ; w3 ) = m(1; 2; 5; 8)
m=1
13
Demultiplexer
Si tratta di un blocco combinatorio duale al multiplexer: dato un singolo
ingresso, e n bit di selezione, il blocco combinatorio semplicemente collega
l’ingresso ad una delle 2n possibili uscite.
Encoder
Dati 2n ingressi, il blocco produce n uscite, in maniera del tutto duale al
decoder. Questo blocco usa una codifica nota come “one-hot encoding”: uno
solo degli ingressi deve valere “1”, tutti gli altri “0”; in altri casi, l’uscita
dell’encoder vale “don’t care”, e non è possibile dire altro.
Priority Encoder
Il priority encoder rappresenta una variante rispetto al precedentemente de-
scritto encoder: si utilizza in sostanza un concetto di priorità, nel seguente
senso: a partire dal primo bit a “1”, stabilito un senso di priorità, l’uscita
dell’encoder è definita; in seguito al primo bit (più significativo) a uno, l’u-
scita è definita, gli altri ingressi (meno significativi) sono don’t care. Come
già detto, si tratta di un’estensione del precedente blocco: in questo modo
un encoder può solo accettare “combinazioni permesse”, rendendo di fatto
molto più flessibile il blocco, annullando in sistanza le uscite insensate.
Convertitori di Codici
Senza entrare nello specifico, molto spesso è necessario passare da codifiche
di un tipo a codifiche di altri tipi; i convertitori di codici sono blocchi i quali,
dato un certo ingresso, restituiscono un’uscita con un significato differente, in
termini di codifica, da quella appena entrata, in modo da convertire di fatto
la codifica di un numero da una di partenza a una di arrivo, come potrebbero
essere binario e BCD, o 7-segment.
14
Capitolo 2
Come già precedentemente visto, una via per sintetizzare circuiti combinatori
è quella di partire dalla tavola di verità, quindi mediante procedimenti sem-
plificativi quali mappe di Karnaugh o uso di teoremi dell’algebra booleana si
semplificano e si sintetizzano con una certa tecnologia a disposizione.
Quando bisogna progettare sistemi elettronici complicati, metodi “ma-
nuali” quali quelli appena citati sono assolutamente impossibili da utilizzare;
un buon sistemista digitale deve essere in grado di sintetizzare circuiti con
migliaia di transistori e moltissimi componenti. Al fine di fare progetti “seri”,
sfruttando la facilità di gestione di ciascuna singola porta logica, è possibile
utilizzarle come blocchetti fondamentali al fine di costruire blocchi sempre
più grandi, blocchi che, una volta collegati in maniera appropriata, costitui-
ranno il sistema elettronico. Si utilizzano dei CAD in grado di sviluppare
circuiti complicati; serve una metodologia di tipo “industriale”: si deve pri-
ma di tutto, pensare al sistema, visualizzare il progetto e comprendere come
si intende svilupparlo; dopo, esso va descritto in qualche maniera, mediante
il linguaggio di descrizione.
Al fine di effettuare la descrizione del sistema si possono utilizzare mezzi
“grafici”, quali i vari “Schematic editors”, o qualcosa di più fine: un lin-
guaggio di descrizione dell’hardware, quale il già citato VHDL. VHDL è un
acronimo per la seguente sigla: VHSIC Hardware Description Language, do-
ve per VHSIC si intende il sotto-acronimo di Very High Speed Integrated
Circuits. Come il nome suggerisce, in sostanza, esso è un linguaggio atto
a rappresentare e descrivere circuiti che verranno poi integrati (o in realtà
anche implementati su schede, come si vedrà in seguito). Nel resto della trat-
tazione si considererà, come mezzo per la descrizione dell’hardware, proprio
questo linguaggio, VHDL: mediante il compilatore / simulatore / sintetizza-
tore, una volta introdotto il codice, è possibile verificare che tutto funzioni,
effettuare simulazioni, e occuparsi del design fisico del progetto.
15
Lavorare con il sintetizzatore, ossia con il software che, a partire dalla
descrizione VHDL dell’oggetto fornisce un’implementazione reale (che verrà
quindi caricata su di un hardware appropriato, ad esempio su di una FPGA),
non è mestiere facile: il sintetizzatore implementa ma con “poca fantasia”, nel
senso che elabora, con l’hardware e/o la tecnologia a disposizione, un’imple-
mentazione in qualche modo “vicina”, “simile” a quella descritta nel listato
VHDL, per quanto gli sia possibile; se si descriverà un circuito con porte
logiche, dunque, ci si potrà aspettare un’implementaziona basata sull’uso di
porte logiche; se si descriverà un circuito basato su multiplexer, decoder,
o altri blocchi di questo tipo, ci si può aspettare, nell’implementazione, la
presenza di componenti di questo genere.
Il VHDL nasce negli anni ’80, e solo nel 1987 viene adottato come stan-
dard per la IEEE; subisce diverse revisioni, tra cui la fondamentale, del 1993,
nota come standard IEEE 1164; inizialmente, esso veniva utilizzato solo per
documentazione (ossia per la descrizione di sistemi) e per la loro simulazione;
a questo punto dell’evoluzione tecnologica esso è lo strumento fondamentale
per il progetto di un sistema elettronico digitale.
LIBRARY ieee;
USE ieee.std_logic_1164.all;
16
il blocco con approccio “blackbox”: si definiscono tutti i parametri
concernenti ingressi, uscite, eventualmente ritardi (per simulazioni, ov-
viamente: non è possibile “imporre” un ritardo al sintetizzatore, poichè
esso utilizzerà hardware a disposizione dotato di un determinato ritardo
intrinseco), e altri eventuali parametri riguardanti però esclusivamente
l’aspetto “esteriore” del blocco o del sistema;
17
SIGNAL y : STD_LOGIC;
SIGNAL x : STD_LOGIC_VECTOR(7 DOWNTO 0);
Sono stati ora presentate due righe di codice da utilizzare molto frequente-
mente: le dichiarazioni di segnali. Nella fattispecie, una volta chiamati i pac-
chetti precedentemente illustrati, è possibile utilizzare questo tipo, contenen-
te una maggior varietà di informazioni rispetto al tipo vecchio, nativamente
implementato in VHDL.
Si introduce brevemente dunque il tipo standard logic, esponendo i prin-
cipali valori che può assumere:
• D (don’t care): il segnale può assumere valore zero o uno, dal momento
che non è fondamentale ai fini del funzionamento finale del sistema;
• L (livello logico basso debole): si tratta di uno “0” debole, non ben
riconoscibile dall’hardware; il senso della frase “non ben riconoscibile”
significa che, in presenza di uno scontro con un altro segnale “forte”,
esso prevale su quello debole; un esempio di questo tipo di segnali può
essere un segnale collegato ad un resistore di pull-down;
18
• W (valore non-valido debole): il fatto che due segnali deboli si scontrino
tra loro, provoca un’indeterminazione analoga alla precedente, ma che
viene definita per valori esclusivamente deboli.
Vettori e matrici
Precedentemente è stato proposto un costrutto in grado di realizzare array
monodimensionali, ossia vettori costituiti da un certo tipo (standard logic,
il tipo prevalentemente utilizzato nell’ambito dei sistemi elettronici digitali);
dal momento che le memorie tuttavia, come si vedrà, hanno un aspetto “ma-
triciale”, può tornare utile il progetto di un array bidimensionale di elementi,
ossia una matrice di standard logic. Non è difficile produrre qualcosa di que-
sto tipo: è sufficiente utilizzare ricorsivamente il comando precedentemente
presentato, ottenendo qualcosa del tipo:
Cosa è stato fatto? Beh, qua è stata buttata molta carne al fuoco, carne
che andrebbe controllata passo per passo: il comando TYPE permette di
definire un tipo nuovo, non presente nello standard IEEE 1164. RegArray è
il nome che si attribuisce al tipo: si decide di chiamarlo cosı̀, ma un qualsiasi
nome sarebbe stato valido, restando nei limiti della sintassi del VHDL; il
comando ARRAY permette di definire un vettore (in questo caso di 4 ele-
menti) di vettori di standard logic (di 8 elementi); in questo modo, al fine di
accedere a ciascun elemento della matrice, si può utilizzare una sintassi del
tipo:
19
mat(i)(j);
20
siderando tutto “già a posto” in termini di interconnessioni con altri
blocchi.
21
funzione di sintesi è stata introdotta al fine di utilizzare la descrizione pro-
posta per il sistema per una realizzazione materiale del progetto. Una volta
nati i processi di integrazione su semiconduttore o le logiche FPGA, disporre
di un mezzo semplice e al contempo efficace di descrivere un sistema poteva
essere importante per la produzione su scala industriale di un certo prodotto:
una FPGA come si vedrà in seguito è un dispositivo logico programmabile
mediante un calcolatore elettronico, dispositivo sul quale è possibile caricare
le caratteristiche di un sistema realizzandolo di fatto fisicamente su di esso.
Molte aziende produttrici di integrati, inoltre, distribuiscono ai progettisti
che lavorano con loro modelli PSpice o VHDL dei loro dispositivi, in modo
da poter produrre un listato in grado di essere immediatamente realizzato su
maschera, per quanto riguarda i progetti più costosi, da realizzare su scala
industriale. Il sintetizzatore, dunque, è in grado di realizzare su di un qualche
supporto un’implementazione fisica dell’hardware, analogamente a come un
utente fa con una breadboard e componenti discreti.
Il simulatore lavora a livello puramente logico: a partire dalla descri-
zione contenuta nel listato VHDL, è possibile effettuare una simulazione
del comportamento del circuito, senza introdurne alcuna implementazione
reale. Esistono costrutti in grado di introdurre eventuali ritardi, in modo
da poter rendere più realistica la simulazione, rendendola dunque non solo
“funzionale”, bensı̀ “comportamentale”, prossima a quella del circuito reale.
Il processo di sintesi è piuttosto complicato e non riguarda questo tipo di
trattazione; si sceglie tuttavia di introdurre alcuni concetti ulteriori riguardo
la simulazione, in modo da comprenderla maggiormente ed evidenziare alcune
differenze con software quali PSpice.
2.2.1 Simulazione
Studiando l’elettronica analogica, molto spesso risulta fondamentale l’uso di
un simulatore in grado di fornire un andamento delle uscite di un generico
circuito. L’elettronica digitale risulta essere una semplificazione dell’elettro-
nica analogica: anzichè poter assumere qualsiasi valore, un segnale digitale
può assumere sostanzialmente due valori. Il fatto di introdurre questa no-
tevole semplificazione (senza considerare gli aspetti elettrici contenuti nel-
l’elettronica digitale, considerando dunque che tutte le porte logiche siano
della stessa famiglia e quindi si “parlino” correttamente) permette diverse
semplificazioni anche per quanto riguarda il modello complessivo, e la tec-
nica di simulazione: se da un lato, nell’elettronica analogica, è necessario
continuamente presentare nuovi valori, dal momento che essi sono reali, dun-
que effettuare una simulazione a tempo continuo (in prima approssimazione
continuo, dal momento che comunque si discretizza il tempo reale per poter
22
ricondurre le equazioni differenziali dei componenti a equazioni alle differen-
ze finite), dall’altro è sufficiente accorgersi di un fatto: la variazione di un
determinato segnale. Di fatto, non è necessario effettuare continuamente la
simulazione, ossia simulare tutti gli istanti di tempo, bensı̀ può essere suf-
ficiente effettuare una simulazione del comportamento del sistema solo in
determinati istanti, dove “avviene qualcosa”, ossia dove, in seguito a deter-
minate variazioni di un certo segnale, si abbiano condizioni in grado di far
nascere fenomeni importanti.
Questo tipo di simulazione è detta “simulazione ad eventi”: ogni qual
volta si abbia un cambio di stato o di uscita per quanto riguarda il sistema,
il simulatore introduce in una sorta di “coda ordinata”, dove il parametro
ordinante è il tempo in cui deve avvenire un certo nuovo evento, le carat-
teristiche dell’evento. Una volta eseguito e terminato il primo evento, il
simulatore entra nella coda, verifica le caratteristiche e gli istanti in cui il
nuovo evento deve arrivare, quindi lo esegue; questo nuovo evento a sua volta
potrà introdurre uno o più nuovi eventi nella cosiddetta “event list”, eventi
che potranno essere eseguiti, e cosı̀ via.
Questo tipo di simulazione è, come si vede, molto differente da quella
classica di PSpice, a tempo continuo: in seguito a una certa eccitazione,
fornita per esempio da un ingresso, si ha un inserimento di un evento in
una lista, contenente esclusivamente informazioni riguardo i suddetti; questi
fanno variare le caratteristiche del segnale, la risposta del sistema. Non si
considera punto per punto la soluzione numerica di una certa equazione, bensı̀
una tecnica in grado di modificare le caratteristiche di un segnale, appuntare
eventuali future caratteristiche da presentare e con quale priorità, dove la
priorità è dipendente dall’istante temporale in cui l’evento deve apparire. Il
tempo di simulazione non “scorre effettivamente” per il calcolatore, nel senso
che serve esclusivamente ad attribuire una determinata priorità ai diversi
elementi della coda, in modo da fornire un ordine.
Come anticipato, è possibile introdurre un ritardo per ciascuna porta
logica: un’analisi di tipo funzionale fornisce un andamento puramente com-
portamentale del codice, senza introdurre in alcun modo ritardi; è possibile
introdurre ritardi mediante un costrutto di questo tipo:
23
si introduce un piccolo ritardo simbolico, per un certo motivo); specifican-
do mediante AFTER un determinato tempo, si introduce un ritardo nella
simulazione, in modo da simulare l’andamento di una porta reale.
Per quanto riguarda la simulazione, a seconda di ciò che si intende fare
e del software da utilizzare, si possono progettare segnali di prova. Al fine
di effettuare una simulazione è necessario simulare un determinato ingresso,
in modo da simulare l’eccitazione del sistema. I software spesso presentano
metodi per la realizzazione grafica di segnali di questo tipo; una tecnica per
realizzare questi segnali è basata sull’uso di after:
sig <= ’0’, ’1’ AFTER 10 ns, ’0’ AFTER 20 ns, ’1’ AFTER 40 ns;
• Ciascun ritardo parte dal tempo nullo; ciascun AFTER si riferisce dun-
que allo stesso istante, quindi, nell’esempio proposto, si parte da t = 0,
si va a t = 10, passan 10 ns e si arriva a t = 20, e cosı̀ via. Ciascun
“after” si riferisce al tempo nullo.
24
• Ritardo di trasporto: se il ritardo inerziale è molto realistico, nel senso
che potrebbe portare alla cancellazione di eventi a causa di mancata
presenza di alcune condizioni sui segnali causate dai delay, il ritardo
di trasporto semplicemente “trasla” tutti i segnali di un certo ritardo,
senza però avere l’effetto “reale” che aveva il ritardo precedentemente
descritto;
Ciascun evento può contenere uno o più comandi; la cosa sempre vera, co-
munque, è che ciascuno di essi viene eseguito in maniera concorrente rispetto
agli altri, ossia “contemporaneamente”: ogni evento è un insieme di azioni
che vengono eseguite allo stesso istante di tempo. Si consideri ad esempio il
fatto che in un evento, in qualche modo, vengano eseguite queste espressioni:
A <= B;
C <= A;
25
Capitolo 3
26
• Utilizzare dei fusibili, ossia dei dispositivi in grado di far passare la
corrente entro un certo limite di intensità, per poi “fondersi” in modo
irreversibile, di fatto “programmando” un’interconnessione mancante,
un circuito aperto;
• Utilizzare degli antifusibili, ossia dei dispositivi duali ai fusibili: fino a
quando non si introduce un’opportuna differenza di potenziale ai capi
degli antifusibili, non si ha un contatto; da quando si è introdotta questa
tensione, il dispositivo si chiuderà irreversibilmente, permettendo al
segnale di passare;
• Utilizzare transistori associati a memorie di tipo EEPROM o Flash
(meglio descritti in seguito), programmando la memoria mediante zeri
o uni;
• Collegando un transistore a una memoria RAM, funzionante in modo
simile a prima.
f = I1 + I2
Data una matrice di questo tipo, costituita da linee come queste, in un
circuito integrato dunque si devono semplicemente posizionare i transistori
nella maschera in modo da definire la funzione logica che si intende pro-
gettare; volendo realizzare circuiti programmabili, in ogni incrocio vi sarà il
transistore che, anzichè al potenziale di riferimento del sistema, sarà collega-
to a un elemento programmabile (in modo permanente o meno), a sua volta
collegato allo 0 V.
la logica appena presentata permette di realizzare una logica di tipo NOR;
una volta realizzata, mediatne i teoremi di De Morgan, è possibile definire
piani (ossia rappresentazioni bi-dimensionali) di tipo AND, OR, NAND, e
simili, ossia insiemi di possibili funzioni logiche selezionabili e utilizzabili in
seguito a un processo di programmazione.
Presensiamo a questo punto le principali strutture programmabili, accen-
nando ai metodi utilizzati per programmarle, e ai loro limiti e vantaggi. In
27
tutte queste, l’idea fondamentale è quella di avere due “piani”, due insiemi
di funzioni logiche di un certo tipo, collegato a piani di funzioni logiche del-
lo stesso o di un altro tipo, ad esempio AND e OR; le varie tecnologie ora
descritte si differenziano dal fatto che solo alcuni elementi, o piani, possono
essere programmati, o entrambi.
PROM
Per PROM si intendono le Programmable Read Only Memory: il primo
piano è non-programmabile, e spesso costituito da funzioni logiche di tipo
AND (fixed AND plane); le interconnessioni tra questo piano e il piano OR
in cascata a esso sono programmabili, dunque solo la “seconda parte” risulta
essere programmabile.
Dal momento che il piano AND è “fixed”, in uscita da questo si avranno,
in sostanza, dei minterm già “scelti” dal progettista della PROM; sostanzial-
mente, selezionando nel piano OR quali di questi minterm vanno sommati,
si ottiene la funzione di uscita. Il piano AND è praticamente un decoder: in
uscita da esso si hanno minterm decodificati, che poi verranno “filtrati” dal
piano OR programmabile. Una PROM, quindi, si può in sostanza pensare
come una memoria i cui ingressi sono gli indirizzi nei quali sono dislocati i
dati, e le cui uscite sono i dati stessi.
PAL
Le PAL, o Programmable Array Logic, sono dispositivi duali alle PROM: il
piano AND è infatti interamente programmabile, ma il piano OR è fixed.
Questo fatto presenta vantaggi e svantaggi:
• Uno svantaggio è il fatto che, pur essendovi una buona flessibilità, po-
trebbe non essere possibile mappare qualsiasi funzione, dal momento
che si è vincolati dal numero di ingressi, finito;
28
ingressi” nel sistema, in modo da aumentare la flessibilità del sistema,
senza introdurvi per forza una memoria o un controllo. Le uscite del
piano OR possono dunque essere re-introdotte, in modo da essere usate
come ingressi aggiuntivi, ovviamente al prezzo di aumentare i tempi di
latenza (dal momento che, per re-introdurre il segnale, è necessario che
esso venga elaborato dalla logica!);
PLA
Le PLA, o Programmable Logic Array, sono le strutture più flessibili tra
quelle finora analizzate, e dotate delle maggior risorse, che permettono di
sintetizzare circuiti combinatori anche piuttosto complessi. Nelle PLA, sia
il piano AND che il piano OR sono programmabili, da qui la flessibilità
dei blocchi. Le PLA presentano vantaggi, ma anche svantaggi, come ora
esporremo:
Una PLA può essere implementata sia con piani AND-OR sia con piani
NOR-NOR: usando funzioni di tipo NOR e complementando il tutto con
degli inverter, è possibile infatti ottenere funzioni logiche di tipo qualunque.
Le PLA si possono implementare in diversi modi: usando transistori pro-
grammabili mediante fusibili (o, più comunemente negli ultimi anni, anti-
fusibili), o mediante transistori di tipo EEPROM (in serie ai transistori si
introduce una memoria EEPROM/Flash/RAM).
29
CPLD
I CPLD, o Complex Programmable Logic Devices, sfruttano dei blocchi PAL-
like (detti “macrocelle”) per realizzare strutture complesse basate sull’inter-
connessione di blocchi più semplici; il grosso limite legato a queste strut-
ture è la lunghezza delle linee: grandi lunghezze implicano grandi capacità
parassite, quindi grandi latenze.
Negli anni ’90 è stato introdotto, al fine di migliorare le logiche, un cir-
cuito noto come “sense amplifier”: si tratta di un amplificatore analogi-
co differenziale atto a studiare le differenze tra un certo segnale e uno di
riferimento.
Il problema di questo circuito, divenuto fondamentale, è il grosso consumo
di corrente che provoca: esso consuma sempre e molto, cosa che rende i
circuiti poco appetibili per applicazioni di tipo portatile.
LUT
Le LUT o Look-Up Tables, sono strutture già descritte che sfruttano la se-
guente idea (almeno, in una delle possibili realizzazioni che si possono usare):
si può utilizzare un multiplexer a due vie (anche di più, per realizzare strut-
ture più complesse), con gli ingressi collegati a due segnali esterni, x e y; si
può fare una cosa di questo tipo:
A seconda di come si collegano x e y al multiplexer, si possono ottenere
funzioni di qualsiasi tipo. Usando un multiplexer a più vie, si possono rea-
lizzare funzioni logiche ancora più complesse, fino a ottenere un dispositivo
in grado di realizzare funzioni di fatto qualsiasi: una look-up table!
FPGA
Le FPGA, o Field Programmable Gate Array, si basano sull’unione di due
idee: date da un lato le LUT, in grado di creare funzioni generiche, e dall’altro
le strutture delle CPLD, dall’unione delle due nascono quelli che al giorno
sono gli strumenti più potenti e versatili per il progetto di sistemi elettronici
digitali: le FPGA.
Come nelle vecchie CPLD, è possibile utilizzare in uscita sia un blocco
puramente combinatorio che uno sequenziale, in modo da introdurre quindi
elementi in grado di mantenere la memoria degli stati precedenti del siste-
ma. Molto spesso si usa una struttura tipo “Manhattan”, ossia composta da
linee “tra di loro ortogonali”: Manhattan, come d’altra parte Torino, ha una
struttura “a scacchiera” come organizzazione stradale, che ha ispirato molti
progettisti di FPGA. Questo tipo di tecnologia presenta un grosso proble-
ma: spesso, per circuiti complicati, non è possibile effettuare l’operazione di
30
sintesi, dal momento che, una volta che si crea un’interconnessione tra due
blocchi, essa non può essere poi riutilizzata. Per questo motivo molti dei ga-
te di una FPGA non possono essere usati in un progetto: un buon progetto
riesce a sfruttare tendenzialmente il 60 % dei gate presenti in una scheda.
Duranete il processo di sintesi un algoritmo stabilisce quali e quante in-
terconnessioni creare; questo è detto “algoritmo di routing”, e deve essere
particolarmente ottimizzato, se si vuole sfruttare correttamente il potenziale
della scheda.
Solitamente si fa in modo da non realizzare “vie” molto lunghe: una
volta che si “blocca una via” si preclude di fatto la possibilità, a molti gate,
di essere utilizzati; una soluzione a questo tipo di inconvenienti è quella
di adottare una struttura fortemente gerarchizzata, cercando di privilegiare
l’elaborazione “locale”, ossia cercando di usare interconnessioni tra blocchi
“vicini” disponendoli in modo intelligente, facendo in modo da usare meno
possibile le “vie principali”, ossia quelle che collegano blocchi “distanti” tra
loro. Si introduce dunque una struttura multilivello, atta a massimizzare la
localizzazione dell’elaborazione.
Come si programmano questi circuiti? Beh, vediamo quali sono le due
possibilità:
31
Se l’utente intende vendere un prodotto, tuttavia, non può sempre usare
una FPGA come base del proprio sistema: si tratta di circuiti comunque ab-
bastanza costosi, dunque spesso inaccessibili al mercato. Volendo vendere ai
grandi mercati, integrare il processo può essere una buona idea; il processo
di integrazione, tuttavia, richiede l’uso di maschere di integrazione, molto
costose da realizzare (si parla dell’ordine dei 100.000 euro); volendo vendere
milioni di circuiti l’integrazione è senza dubbio la via più conveniente, anche
sotto il punto di vista delle prestazioni, ma può essere inaccessibile al piccolo
produttore. Per integrare si usa spesso il metodo delle “standard cell”: la
sylicon foundary fornisce librerie VHDL/Spice con i modelli dei propri dispo-
sitivi realizzabili, e l’ingegnere deve solo usarli al fine di realizzare il progetto;
l’algoritmo di routing gestirà le interconnessioni.
Esiste una via di mezzo tra l’uso di FPGA e l’integrazione: poichè i costi
delle maschere sono molto elevati, le aziende forniscono maschere “già pronte”
per i componenti più importanti quali porte logiche, flip-flop e simili; l’utente
da qui deve solo fornire indicazioni riguardo le interconnessioni, pagando
dunque solo i costi delle maschere per le interconnessioni, ptogettando una
matrice di gate (gate array); i costi si abbattono, poichè solo parte delle
maschere va realizzata, tagliando anche di cinque volte i costi non ricorrenti.
Questo tipo di tecnica è meno costosa dell’integrazione vera e propria, ma
presenta anche uno svantaggio: essendo il gate array già progettato, spesso
capita di avere in un chip molte più porte di quante ne servano. Dei gate
array robusti e con un numero di livelli sufficiente alla realizzazione di circui-
ti abbastanza complessi può anche valere 20000 euro, quindi relativamente
poco.
32
Capitolo 4
Circuiti aritmetici
4.1 Sommatori
Quella dei sommatori, ossia dei circuiti logici (combinatori) in grado di rea-
lizzare la più semplice delle funzioni aritmetiche, probabilmente è una delle
classi più ampie di circuiti di questo genere. Il problema sostanzialmente è il
seguente: dati due bit in due differenti ingressi, volendo ottenere un circuito
in grado di realizzare la somma dei due bit in termini di “bit di somma” S e
“bit di riporto” C, l’idea più semplice potrebbe essere la seguente:
Questa è la più semplice delle realizzazioni per un circuito di questo tipo.
Per ottenerla, e per ottenere le altre possibili rappresentazioni, potrebbe
essere ad esempio possibile calcolare la tavola di verità, utilizzare il metodo di
sintesi mediante mappa di Karnaugh, e a seconda della scelta degli implicanti
ottenere altre espressioni del circuito logico. Blocchi di questo tipo, che da
due bit ricavano somma e carry, sono comunemente noti col nome di “half
adder”.
Un’estensione di questo tipo di blocchi potrebbe essere il cosiddetto “full-
adder”: un circuito in grado di prelevare parole di bit e sommarle tra loro
non può essere basato su half adder, poichè essi non prevedono un fatto: che
33
il numero in ingresso sia già dotato di un carry. Ciò che si potrebbe dunque
fare è costruire una tavola della verità in grado di prevedere anche l’intro-
duzione di un bit di carry, dunque mediante mappe di Karnaugh trovare
un’espressione in grado di fornire, in termini di porte logiche elementari, il
carry per il bit successivo (i + 1-esimo) e la somma per il blocco presente
(i-esimo); mediante questo procedimento, si può dimostrare che:
s i = x i ⊕ y i ⊕ ci
ci+1 = xi · yi + xi · ci + yi · ci
Date queste funzioni è possibile sintetizzare, riciclando eventualmente il
blocco “half adder”, un circuito per il full-adder. L’idea sostanzialmente è
quella di considerare, in uscita dagli half adder, l’OR dei vari carry, ottenendo
qualcosa di questo tipo:
Questo circuito è abbastanza complesso, ma la cosa positiva è che si può
fare di meglio, studiando in maniera più idonea l’idea nascosta dietro al
concetto di carry, di riporto. In un full adder, sostanzialmente, potrebbero
capitare due cose, per quanto riguarda il carry, da quello in ingresso ad esso
a quello che deve produrre: il carry potrebbe rimanere inalterato, a causa
della somma nel blocco, o potrebbe essere modificato. Quello che si fa è
una sorta di “cambio di base”, per la funzione di generazione del carry:
anzichè considerare l’attuale casistica, si scompongono le casistiche in “carry
generato”, ossia modifica rispetto al carry attualmente presente, o “carry
propagato”, ossia mantenimento dell’attuale carry. Si considerano dunque
due segnali, Gi e Pi , che permettono, come si può dimostrare, di riscrivere
l’espressione del carry in uscita da un blocco full-adder, Co , nel seguente
modo:
Co = G + P · Ci
Ossia, o si ha la generazione di un carry (OR), o si ha la propagazio-
ne del carry già presente nell’ingresso del blocco. In questo modo si può
semplicemente estendere il concetto di half adder precedentemente prodotto,
introducendo una logica di questo tipo:
Questa idea sarà molto interessante, e in seguito ripresa e sviluppata per
presentare alcuni tipi di sommatori veloci. Per ora comunque ci ha aiutati a
semplificare l’espressione di partenza, rendendola più compatta.
34
4.1.1 Ripple-carry adder
Si propone a questo punto la prima idea di sommatore su più bit: il ripple-
carry adder:
Questo è il metodo più semplice per realizzare una somma, ossia un’ope-
razione di addizione tra due vettori di bit. Ciò che si può intuire immedia-
tamente, come si vedrà in seguito, è il fatto che circuiti di questo tipo sono
estremamente lenti e inefficienti: per quanto la realizzazione richieda blocchi
relativamente semplici, per generare ogni riporto è necessario attendere che
tutti gli altri riporti vengano prima generati, cosa che di fatto potrebbe es-
sere eccessivamente fastidiosa al fine di implementare una somma in sistemi
elettronici veloci. Se non è richiesta una velocità particolare, tuttavia, questo
sommatore è ottimo e poco costoso da realizzare.
4.2 Sottrazioni
Finora è stata realizzata una tecnica e una circuiteria in grado di effettuare
addizioni binarie; ci si potrebbe a questo punto chiedere come realizzare
l’operazione duale, ossia le sottrazioni. Finora si è attribuito ai vettori di bit
trattati il significato di “numeri senza segno”, “unsigned”; ai fini di fare la
sottrazione con numeri di questo tipo, di fatto, servono circuiti estremamente
complicati e mai utilizzati. Fondamentalmente, i passi da seguire per ottenere
qualcosa di questo tipo sono i seguenti:
D = M − N + 2n
35
essere quella di definire un metodo di conversione dei numeri da positivi a
negativi in modo che, per fare una differenza, sia possibile semplicemente
complementare il sottraendo, dunque fare una normale somma di numeri ap-
parentemente unsigned. Avendo a disposizione una circuiteria semplice per
il processo di complementazione ed avendo già nozioni riguardo la somma di
numeri unsigned, un processo di questo genere risulterebbe molto semplice.
Senza affrontare nei dettagli questi fatti, si considerano procedure sem-
plici per effettuare i processi di complementazione (senza introdurre la teoria
nascosta dietro di essi):
• Per fare il “CA2” (complemento a 2), si può usare uno dei seguenti
procedimenti:
36
4.2.1 Overflow
Si è detto che il complemento a 2 è la miglior soluzione, quando si inten-
de effettuare operazioni aritmetiche con segno. Riguardo le operazioni con
numeri signed, esiste sostanzialmente un grosso limite che ci blocca: dati n
bit a disposizione, potrebbe capitare che siano necessari, al fine di presentare
correttamente il risultato, n + 1 bit. In questi casi, per fortuna abbastanza
limitati e controllabili, accade che il risultato è privo di significato, avendo
un fenomeno detto “overflow”. Poichè quando si ha overflow il risultato è
privo di significato, è opportuno introdurre un sistema in grado di stabilire
la validità del risultato e segnalare eventuali problemi all’utente o al resto
del sistema.
Una prima osservazione potrebbe essere la seguente: si può avere overflow
sostanzialmente in due situazioni:
• Quando si effettua una somma tra due numeri con lo stesso segno;
• Quando si effettua una differenza tra due numeri di segno opposto.
• Se gli ultimi due bit di carry sono uguali, non si ha mai presenza di
overflow;
• Se i due bit sono diversi, si ha la certezza di avere overflow.
37
annunciato, il problema di questa struttura è il fatto che essa è estremamente
lenta: supponendo di dover realizzare un sommatore a 64 bit da 1 GHz, le
porte dovrebbero avere una latenza inferiore ai 4 ps (provare a fare i conti
per credere!), quando le migliori tecnologie, per costi elevatissimi, possono
arrivare circa a 25 ps. Quello che bisogna dunque fare non è cercare di miglio-
rare la tecnologia delle porte logiche, bensı̀ cercare modi per “rivoluzionare”
il circuito, partendo sempre dal full adder, ma evitando di utilizzare metodi
di questo tipo.
Un’idea è già stata proposta: l’introduzione di questi segnali Gi e Pi , per
ciascun i-esimo full adder. Ciò che si può per ora fare è cercare di migliorare,
concettualmente parlando, il ripple-carry adder, introducendo una notazione
basata sull’uso di questo nuovo concetto.
Come si può dimostrare, osservando le tavole di verità, G e P possono
essere ricavati utilizzando le seguenti espressioni:
G=A·B
P =A⊕B
A partire da queste informazioni, proponiamo alcune idee che permettano
di velocizzare l’attuale sistema.
38
adder calcola per ciascun bit da sommare i carry che dovrebbero esservi,
mediante la semplice applicazione delle formule precedentemente introdotte,
considerando due casistiche differenti, in parallelo: il fatto che il carry in
ingresso al sommatore, Cin , valga “0” o “1”. Mediante un multiplexer, ai cui
ingressi sono collegati i carry prodotti con le due possibilità, si selezionano,
usando come segnale di ingresso Cin , i carry “corretti”, che verranno quindi
utilizzati per produrre le somme parziali di bit, mediante i soli segnali P
e Ci ; sostituendo le espressioni precedentemente introdotte nell’espressione
della somma di due bit, si può ottenere:
S i = P ⊕ Ci
Costruendo blocchi combinatori in grado di riprodurre questa funzione
logica e unendoli (secondo lo schema a blocchi fornito nell’esercitazione), si
può ottenere il sommatore basato sul meccanismo del carry-select.
L’idea sostanziale è quella di “selezionare”: si producono dunque in paral-
lelo due differenti uscite, che vengono poi unificate. Il blocco di produzione
dei segnali di generate e propagate sono decisamente più veloci rispetto al
tradizionale full adder, dunque si riesce a ottenere, rispetto ai sommatori
precedentemente presentati, un notevole miglioramento.
Per architetture di questo genere esistono alcune sotto-varianti, che ver-
ranno ora presentate in modo quantomeno primordiale:
39
L’idea fondamentale è quella di realizzare una logica combinatoria la qua-
le, per quanto complessa, possa determinare “a priori” tutti i carry in par-
tenza, appena introdotto il numero. Sfruttando le definizioni di generate e
propagate, nella fattispecie, si potrebbe pensare a qualcosa del genere:
ci+1 = xi · yi + xi · ci + yi · ci = gi + pi · ci
Partendo da i = 0:
c1 = g0 + p0 · c0
Re-iterando, come si mostra in questo esempio, si può ottenere:
c2 = g1 + p1 · c1 = g1 + p1 · (g0 + p0 · c0 )
Allo stesso modo si potrebbe ricavare c3 e i seguenti allo stesso modo.
Implementando una logica combinatoria di questo tipo si potrebbe im-
mediatamente generare tutti i carry, immediatamente. Il problema di questa
architettura però risulta essere lampante: la complessità delle porte logiche
da usare! Come si può intuire, per un sommatore a 256 ingressi sarebbe
necessario usare degli AND a 256 ingressi, o cose del genere; utilizzare porte
con un fan-in molto elevato non è positivo, dunque è necessario limitarsi.
Un’alternativa potrebbe essere quella di utilizzare qualcosa del genere,
con una struttura di tipo gerarchica: introducendo blocchi complessi, ma
in numero limitato, si potrebbe ovviare questo problema almeno in parte,
rendendo il tutto più semplice e più facilmente realizzabile.
40
un certo numero di porte logiche, che tuttavia non saranno sempre utilizzate:
fissando infatti un ingresso, è possibile che l’uscita non sia più complicata
come nel caso di due ingressi variabili, liberi. L’idea di partenza è sicuramente
valida, ma si può far di meglio: si potrebbe osservare come funziona, data
l’imposizione di un ingresso costante, che non verrà variato (o 0 o 1), la
tavola di verità del sistema, dunque notare eventuali semplificazioni; se se ne
trovano, dunque si potrà sostituire una porta logica con una meno complessa,
come ad esempio un filo o un inverter. Si supponga ad esempio di avere uno
XOR, con un ingresso B fissato a “0”:
Se A = 1, A ⊕ B = 1; se A = 0, 0 ⊕ 0 = 0; si può dunque dire che, dato B
= 0, sull’uscita si avrà sostanzialmente l’ingresso A: lo XOR è trasparente ad
A. Nella sintesi, in definitiva, si potrà dire che lo XOR si può rimpiazzare con
un semplice filo che collega A all’uscita. Questo processo di semplificazione
è noto con il nome di “contrazione”. In modo del tutto simile si può realiz-
zare, anzichè un incrementatore, un decrementatore, a partire dal circuito di
somma, contratto.
41
fattore per tutte le cifre del primo; per ciascuno di questi “prodotti
parziali” si otterrà un numero che, per ciascuna cifra da moltiplicare
parzialmente, verrà shiftato a sinistra di una posizione, collegando in
maniera opportuna i vari sommatori;
n−1
X
V (B) = bi 2i
i=−K
42
Capitolo 5
Circuiti sequenziali
5.1.1 SR-Latch
Un SR-Latch è un dispositivo costituito da questo set di porte logiche:
Tendenzialmente si può vedere che S (set) imposterà il valore dell’uscita
positiva Qa ; reset, o R, dualmente, imposterà il valore dell’altra uscita. Si
noti che, di solito, è buona cosa che S = R: come si riprenderà tra breve,
esistono configurazioni che “sarebbe meglio non usare”, quali in questo caso
S = R = 1. Al contrario, S = R = 0 è una configurazione molto inte-
ressante, in quanto introduce la novità rispetto ai circuiti finora analizzati:
43
quando entrambi gli ingressi sono negati, il circuito in uscita mantiene i valori
precedentemente introdotti, ottenendo di fatto un effetto memoria.
44
In blocchi di questo tipo è possibile introdurre segnali di preset o reset
sincroni o asincroni, a seconda delle necessità del sistema. Tipicamente, buo-
na cosa sarebbe introdurre sistemi di reset sincroni, anche se assolutamente
non è detto sia una soluzione obbligatoria, come tra poco si esporrà. Sicuro
è un fatto: tipicamente i circuiti sequenziali devono essere in qualche modo
inizializzati, mediante un reset; potrebbe poi essere necessario, durante l’uso,
re-inizializzarli, o a causa di guasti o a causa di altri fenomeni di vario genere.
Esistono fondamentalmente, come già annunciato, due filosofie per il reset del
sistema: reset sincrono e reset asincrono. Meglio utilizzare reset sincroni o
asincroni? Come annunciato, si tratta di un problema di implementazione:
a volte, resettando, è necessario far tutto solo dentro i colpi di clock, a volte
è necessario un reset immediato. Si analizzano comunque aspetti positivi e
negativi.
Qua riportati i circuiti per il reset sincrono e asincrono:
• Il clock nel reset sincrono per quanto rallentante “filtra” variazioni in-
desiderate dei segnali, ossia i “glitches”: il fatto che si campioni esclu-
sivamente in un istante di tempo anzichè in continuazione, fa sı̀ che la
probabilità di campionare un disturbo sia assolutamente minima. Nel
caso di circuiti con reset asincrono, dove si campiona sostanzialmente
in qualsiasi momento, un glitch può rappresentare un grosso problema:
un disturbo indesiderato può di fatto provocare reset indesiderati del
sistema sequenziale, che potrebbe dunque diventare non funzionante.
45
Si supponga ora di progettare un sistema, e di volerlo realizzare su di un
circuito integrato. Degli integrati prodotti sicuramente non tutti funzione-
ranno, a causa di impurità presenti sui substrati di silicio piuttosto che a
causa di altre motivazioni tecnologiche. Quello che si fa comunemente dopo
la produzione dei circuiti integrati è provarli, introducendo dei dati “corret-
ti” per poi vedere come reagisce il circuito alle eccitazioni. Per rendere più
veloce il progetto della macchina di test spesso si aggiunge dell’hardware per
fare esclusivamente i test di controllo (questa procedura di progetto è solita-
mente nota col nome di “design for testability”). Aver a che fare con circuiti
sincroni è sempre facile; un reset asincrono al contrario potrebbe provocare
probemi, poichè, se qualcosa fa girare il reset, allora questo cambia radical-
mente e immediatamente il comportamento della macchina. Testare un reset
asincrono è abbastanza complicato.
L’unico vantaggio (o uno degli unici, oltre alla velocità) potrebbe inte-
ressare casi particolari, quali il fatto che le uscite dei flip flop vengano usate
per pilotare dei buffer tri-state: se per caso il clock non riesce a temporizza-
re correttamente il reset, i tri-state possono danneggiarsi dal momento che
il circuito rimane in uno stato qualunque. Un reset asincrono all’accensione
del circuito potrebbe risolvere questo problema, imponendo immediatamente
e indipendentemente dal clock uno stato al circuito, evitando danni.
5.2 Metastabilità
Oltre a introdurre tante belle cose quali la possibilità di introdurre la memoria
di uno stato di un sistema, in modo da permetterne l’evoluzione al variare
del tempo, i sistemi sequenziali introducono un enorme problema: l’esistenza
di stati particolari del sistema, in cui di fatto si hanno malfunzionamenti.
Gli elementi con memoria spesso presentano “stati proibiti”, ossia stati che
possono portare al non rispetto del principio di complementarietà delle uscite.
Per questo motivo è fondamentale introdurre tecniche e nozioni atte a evitare
di rientrare in casistiche di questo tipo, mediante la definizione di tempi, di
ritardi che permettano al sistema di operare in maniera corretta.
Il fronte del clock, in un flip-flop, ha un certo andamento, e a seconda
che si violino o meno i tempi di mantenimento del segnale precedentemente
accennati è possibile che si abbiano “risposte strane”. Fondamentalmente,
quando i cosiddetti “stati proibiti” vengono utilizzati, o quando si campiona
l’uscita mentre essa varia, si entra nel cosiddetto “stato di metastabilità”. La
metastabilità è un fenomeno assolutamente negativo per i circuiti sequenziali:
se un flip-flop che deve pilotare altri due elementi con memoria, essi possono
per esempio interpretare in modo diverso il valore dell’uscita, dunque il siste-
46
ma inizia a sbagliare clamorosamente i valori, raggiungendo stati imprevisti;
per far funzionare in modo corretto un flip-flop è necessario aumentare i tem-
pi di ritardo per tenere conto della violazione dei tempi di mantenimento e
di impostazione del segnale di ingresso, in modo da permettere un corretto
campionamento e non l’ingresso nello stato proibito.
47
• ts : tempo di setup: tempo che serve al flip-flop per immagazzinare,
campionare il dato in ingresso; si tratta in pratica dell’ampiezza tempo-
rale dell’ingresso, minima, necessaria perchè il flip-flop possa campio-
nare senza “fraintendimenti” il dato. Si può dire che il tempo di setup
quantifichi, rispetto al colpo di clock, il tempo necessario perchè il dato
sia memorizzato nel flip-flop prima del fronte di campionamento. Si
tratta di un tempo che deve garantire la stabilità del segnale prima del
colpo di clock. Questo tempo solitamente va sempre considerato, e cal-
colato sul percorso di propagazione combinatorio “massimo”, quello che
porta ad una più lenta propagazione del segnale (dunque in funzione
del periodo minimo, per calcolare la massima frequenza di lavoro).
48
1
fmax =
tmin
Nel caso di più percorsi combinatori presenti, sarà necessario scegliere il
maggiore. Il fatto che si parli di “tempo minimo” tendenzialmente esclude la
presenza di tempi di slack, ossia di margini di tempo in cui il segnale viene
mantenuto costante, in modo da poter documentare una frequenza di lavoro
minima ma per qualsiasi casistica reale del circuito.
Una nota conclusiva: l’identificazione dei vari percorsi tra due flip-flop (si
noti che i percorsi da identificare devono essere sempre e comunque fatti tra
due elementi di memoria: uno che campiona l’ingresso di un circuito sequen-
ziale, l’altro che campiona e propone l’uscita del medesimo, o quantomeno
uno stato intermedio) può essere di diverso tipo, e fornire informazioni di
tipo diverso: a seconda del fatto che i flip-flop campionino sul fronte di salita
o di discesa, si possono trarre informazioni di tipo diverso:
• Nella situazione di due flip-flop che operano sullo stesso tipo di cam-
pionamento, l’informazione sarà sul periodo minimo di clock;
• Si noti che per un elettronico è facile produrre segnali con duty cycle
pari al 50 %; nel caso le informazioni sui periodi minimi differissero,
si sceglie quella più vincolante, e l’altra verrà scelta di conseguenza,
per esempio raddoppiando questo periodo scelto. Se poi il periodo
risultante da questa operazione fosse maggiore del periodo massimo, si
sceglierebbe esso come periodo di clock.
49
di macchine a stati sincrone, dunque non si hanno variazioni dello stato e
delle uscite che non siano in qualche modo indipendenti dal clock.
Esistono sostanzialmente due tipi di macchine a stati:
• Una logica di transizione dello stato, ossia una rete puramente combi-
natoria in grado di far “evolvere” lo stato nella direzione interessata dal
progettista: a seconda del comportamento che si intende attribuire alla
macchina a stati, sarà necessario che essa, da uno stato ad un altro,
effettui determinate operazioni logiche; queste vengono realizzate me-
diante funzioni logiche, a partire da una rete combinatoria introdotta
tra i vari elementi con memoria;
50
di decodifica). Il fatto di dover utilizzare codifiche richiede che, per
l’esterno del sistema, le informazioni siano semplicemente decifrabili;
per questo motivo lo stadio finale di una macchina a stati solitamente
è proprio una logica di decodifica.
51
• Nel caso i flip-flop comandino dei tri-state, se non si introduce il reset
e se si hanno stati don’t care tali da produrre un ‘11’ in uscita, si ha
il rischio di farli scoppiare. Anche negli stati non raggiunti serve fare
attenzione ai don’t care, poichè mettere condizioni proibite o rischiare
di farlo può essere molto dannoso, in certi casi patologici quali questo;
• In una macchina con reset sincrono, se per qualche motivo esistono stati
scorrelati dagli altri e collegati solo a sè stessi (per errore), capita che
non se ne esce mai. Per questo motivo di solito le macchine presentano
dei power-on-reset asincroni, e reset sincroni: il power-on-reset viene
utilizzato solo all’avvio e poi disabilitato, il reset utilizzato. I don’t
care potrebbero produrre situazioni di questo tipo.
52
5.4.1 Shift register
Uno shift register è un circuito in grado di memorizzare più informazioni allo
stesso tempo. Se da un lato un flip flop è in grado di memorizzare e mantenere
dunque sull’uscita un singolo bit, un registro è in grado di memorizzare una
sequenza di bit, un vettore. La modalità più semplice con cui un registro
può essere realizzato è la seguente:
Collegando tutti i flip-flop allo stesso clock si sincronizzano tutti i blocchi
sequenziali tra loro; per ogni colpo di clock si “shifta” l’informazione verso
destra (in questo caso): il dato in ingresso viene campionato dal primo flip-
flop, l’uscita di questo passa in ingresso al secondo, e cosı̀ via, fino all’uscita
dell’ultimo flip-flop che viene proposta in uscita. Questo circuito presenta
alcuni ovvi problemi: è molto lento da caricare, per quanto semplice da
utilizzare.
Una variante a questo circuito, per quanto concettualmente simile, po-
trebbe essere la seguente:
Con un circuito di questo tipo è possibile effettuare il caricamento sia
seriale sia parallelo del circuito, del registro, rendendolo di fatto più costoso
sotto il punto di vista dell’area di integrazione, ma molto più versatile. Que-
sto circuito è in grado di fornire uscite in parallelo (prelevando dai pin delle
uscite ciascuna informazione), caricare in ingresso in parallelo l’informazione
(mediante la circuiteria presentata), ma anche in serie, in modalità classica.
La selezione delle modalità viene effettuata mediante un segnale di controllo.
Flip-flop SR
Il flip-flop di tipo più “basilare” (anche più del D) è il cosiddetto flip-flop
SR (Set-Reset, esattamente come per il SR-Latch): anzichè presentare un
singolo ingresso di dato, ne presenta due: uno di set, uno di reset. Dualmente
vengono presentate, nelle implementazioni più comuni, due uscite, una la
negata dell’altra.
Questo circuito presenta sostanzialmente lo stesso limite degli SR-Latch:
è necessario introdurre due dati anzichè uno, rendendo un po’ più complica-
ta la progettazione; inoltre esiste lo stato proibito, ossia lo stato nel quale
53
non si può entrare, pena il rischio di mandare il dispositivo in metastabilità
oscillatoria. Considerando tuttavia come ingressi uniti:
D=S=R
Si ottiene semplicemente il ben noto flip-flop tipo D.
Flip-flop JK
Un ulteriore modo di implementare flip-flop è il cosiddetto “JK”. Come già
detto, il grosso problema dei flip-flop tipo SR è la presenza di uno stato
proibito, non ammissibile. L’idea fondamentale alla base dei flip-flop tipo
JK è quella di eliminare questo tipo di problema, introducendo, al posto
dello stato proibito, un’ulteriore funzionalità del circuito:
Come funziona questo schema? Beh, per le configurazioni di ingressi
“00”, “10” e “01”, esattamente come un normale flip-flop SR; la circuite-
ria introdotta nel sistema tuttavia permette, al posto dello stato proibito,
l’introduzione di una nuova funzionalità: il fatto che si retroazioni l’uscita
negativa nella circuiteria combinatoria, permette di fatto un’inversione logica
delle uscite, facendole “cambiare”: in altre parole, Q diventa Q, e Q diventa
Q, in seguito all’introduzione della combinazione di ingressi “11”.
Flip-flop T
Ultimo blocco piuttosto interessante e spesso utilizzato è il flip-flop tipo T
(dove T sta per “Toggle”, “scambiante”): come appena visto, in un flip-flop
JK si introduce la possibilità di negare i valori delle uscite, conservando i
valori ma negandoli logicamente. Introducendo negli ingressi una piccola
modifica, ponendo J = K, è possibile ottenere qualcosa di questo tipo:
Questo flip-flop, detto tipo T, si comporta nella seguente maniera: quando
T = 0, l’uscita memorizzata rimane tale; quando T = 1, al colpo di clock
l’uscita viene invertita, diventando dunque la negata rispetto alla precedente.
54
presenza di un “1” sull’uscita farà commutare l’uscita del secondo flip-flop e
cosı̀ via, ottenendo di fatto un contatore.
Questi contatori non sono il massimo: i ritardi sequenziali, infatti, ten-
dono ad accumularsi, rendendo di fatto inefficiente questo tipo di circui-
to. Quando si realizza qualcosa del genere conviene mettere pochi stadi
sequenziali, anche in modo da evitare transitori sulle uscite.
55
Esistono almeno due particolari topologie, che ora verranno quantomeno
presentate sommariamente, in grado di lavorare a frequenze ben maggiori
rispetto agli schemi più tradizionali appena mostrati.
Ring counter
La prima idea per realizzare un contatore veloce potrebbe essere la seguente:
In sostanza, l’idea alla base di questo tipo di circuito è quella di usare uno
shift register retroazionato, in cui l’uscita dell’ultimo flip-flop viene portata
indietro fino al primo. In questa situazione, si inizializzano tutti i flip-flop
mediante un reset a zero tranne uno, pilotato da un sistema di complementa-
zione. Dopo un certo numero di colpi di clock si torna al punto di partenza.
Di tanto in tanto si possono trovare circuiti di questo tipo associati ad un
encoder, anche se non si tratta di una scelta molto felice: un encoder intro-
duce grossi ritardi su un circuito cosı̀ veloce, dunque bisogna stare attenti
nell’inserire logiche che potrebbero rallentare il circuito.
Johnson counter
Il concetto del Johnson Counter è il seguente:
Si resettano contemporaneamente e assieme tutti i flip flop, dunque il
ritorno al primo, la retroazione, viene fatta con l’uscita Q anzichè Q, dell’ul-
timo flip-flop. Il circuito dunque concettualmente è molto simile a quello del
ring counter, se non per questa piccola differenza.
I ritardi del circuito sono sostanzialmente pari al tempo di setup e al
tempo compreso tra il colpo di clock e la propagazione dell’uscita: un’uscita
è sempre diversa dalle altre, e questa continua a variare a seconda del valore
dell’uscita attuale del contatore, in modo da variare continuamente il valore
delle uscite.
56
3. Semplificare gli stati e attribuire una codifica ai medesimi;
57
a questo punto introdurre è una migliore e più semplice schematizzazione,
in grado di contenere un maggior numero di informazioni e presentante un
maggior riscontro su quello che sarà il comportamento della macchina a stati
finale.
Questo tipo di rappresentazione è basata sostanzialmente sull’uso di tre
blocchi, più indicazioni sui segnali in esse contenute:
Sostanzialmente bisogna tenere presente il significato e la temporizzazione
legate a questi tre blocchi, in modo da poterli utilizzare in maniera corretta:
• State box (forma “rettangolo”): si tratta sostanzialmente di blocchi
contenenti indicazioni sull’evoluzione delle uscite secondo una logica
di Moore. Ciò significa che tutte le uscite e le indicazioni sui segnali
contenute nei “rettangoli”, al colpo di clock in cui si arriva nel suddetto
stato, variano. Si noti che solo al colpo di clock successivo, ossia in
prossimità del successivo “rettangolo”, le uscite saranno a disposizione
della macchina o dell’utenza. Il significato sotto il punto di vista della
temporizzazione è: per ogni rettangolo è associato un colpo di clock,
e solo al colpo di clock successivo a quello di un dato “rettangolo” si
avran a disposizione le uscite richieste nel rettangolo stesso.
• Decision box (forma “rombo”): si tratta di blocchi in grado di intro-
durre una “scelta”, a seconda dello stato in cui ci si trova. Entrati in
uno stato, dati i valori di diverse uscite, l’evoluzione della macchina
a stati può portare a uno stato piuttosto che a un altro; questa box
semplicemente, riferendosi al colpo di clock del rettangolo “appena pre-
cedente”, propone una biforcazione, inviando la macchina in uno stato
anzichè in un altro.
• Conditional output box (forma “ovale”) : si tratta sostanzialmente del-
la modellizzazione, in ASM Charts, delle “uscite di Mealy”: a seconda
dello stato in cui ci si trova e a seconda del valore di determinati ingres-
si, le uscite contenute nei rettangoli potranno essere o meno attivate
e/o portate a determinati valori. Queste uscite devono essere tenden-
zialmente introdotte dopo un “rettangolo”; il vantaggio di queste uscite
è che saranno già a disposizione, se attivate, al colpo di clock successivo
a quello del rettangolo: essendo uscite di Mealy esse saranno sincrone,
in quanto dipendenti comunque dal clock, ma potranno essere o meno
attivate nello stesso istante delle condizioni contenute nel “rettangolo”
appena precedente, dunque essere pronte per il colpo di clock seguente.
Tenendo bene a mente queste indicazioni, a partire da questi grafici è pos-
sibile ricavare con semplicità un’implementazione VHDL, ottenendo cosı̀ una
macchina a stati facilmente sintetizzabile mediante strumenti informatici.
58
5.5.3 Progetto di sistemi elettronici digitali complessi
In questa sottosezione si suggerirà sostanzialmente un metodo per progettare
un sistema elettronico digitale, a partire dagli strumenti per ora presentati. Il
fatto di aver introdotto gli ASM Chart fornisce sostanzialmente uno strumen-
to molto interessante: un ASM chart rappresenta, di fatto, una traduzione
di un algoritmo, pensato e proposto ad esempio in pseudocodice (piuttosto
che in un linguaggio particolarmente semplice quale un pseudo-C piuttosto
che pseudo-BASIC o pseudo-pascal, a seconda dei gusti).
La tattica da seguire quando si progettano sistemi di tipo complesso, è
quella di dividere il progetto in diverse sezioni:
• Progetto della parte puramente “hardware” del sistema, ossia del co-
siddetto “datapath”: si definiscono tutte le strutture fisiche (descritte a
diversi livelli, a seconda di ciò che il sistema e le specifiche richiedono),
e si collegano tra di loro (descrivendo il sistema graficamente, e poi in
seguito in VHDL utilizzando i costrutti del linguaggio di descrizione /
programmazione a seconda del livello di astrazione);
59
5.6 Pipelining
Per quanto breve, si vuole dedicare una sezione ad un concetto che sempre più
frequentemente torna utile nell’ambito della progettazione dei sistemi elet-
tronici digitali: il pipelining. Il pipelining è uno dei concetti più importanti
creati nell’ambito dell’elettronica digitale, ed è sempre più frequentemente
utilizzato al fine di incrementare le prestazioni di un sistema di questo tipo.
La normale architettura di un sistema elettronico è formata da blocchi di
vario tipo: blocchi computazionali quali ALU, e registri; si prelevano i dati dai
registri, si elaborano, si spostano in altri registri, si leggono, e cosı̀ via. Quello
che ci si può chiedere è: dati tutti gli studi sui ritardi, sulle elaborazioni, sui
tempi di memorizzazione, di mantenimento del segnale, quante operazioni al
secondo si possono fare con un certo circuito? Beh, molto semplice: una volta
fatti tutti i nostri calcoli, si ricavava una frequenza massima di lavoro, fmax .
Il “throughput”, ossia il numero di elaborazioni al secondo, sostanzialmente
coincide con la frequenza di lavoro: per ogni istante si estrae un numero di
prodotti pari alla frequenza di lavoro del sistema.
La domanda a questo punto è: come si può migliorare le prestazioni del
sistema? Beh, proviamo a proporre alcune strade:
• Introducendo nuovi registri, nuovi stati della macchina, “in mezzo tra
due stati”.
60
numero di stati, ma dunque continuando a prendere sempre più operazioni
per volta, portandole avanti indipendentemente.
61
Capitolo 6
6.1 Processi
Ciò che finora non è stato ancora spiegato, è come “mantenere” un’infor-
mazione. Nella fattispecie, il costrutto più utilizzato per la descrizione di
circuiti in VHDL è stato qualcosa del tipo:
A <= B AND C;
62
loro. Questo perchè le assegnazioni effettuate in questo modo rappresentano
processi impliciti, in cui l’elaborazione avviene ogni volta che qualcuno mo-
difica il valore degli ingressi, Si parla di “assegnazioni concorrenti” in quanto
non esiste una valutazione delle assegnazioni: non conta come e quando si
dichiarano, dal momento che, in questo tipo di funzionalità, il linguaggio non
opera in modo sequenziale. Si è parlato di “processi impliciti” ma, a questo
punto, ci si potrebbe chiedere: esistono tecniche per realizzare processi in
maniera “esplicita” ? La risposta ovviamente è sı̀, e su di essa si basa il più
potente metodo per la descrizione di circuiti di qualsiasi tipo, soprattutto
sequenziale.
Il concetto di base è il seguente: esiste (come si dirà tra breve) una lista
di elementi che, se toccati, fanno “scattare” il processo, introducendolo nella
ben nota event list. Come qualcuno tocca uno di questi “ingressi sensibi-
li”, il processo si avvia e tutte le istruzioni contenute nella sua descrizione
vengono effettuate. Questa lista di “ingressi sensibili” è detta “sensitivity
list”: tutti e soli i segnali contenuti in essa sono in grado di far “svegliare”
il processo. Si noti che in un processo fondamentale diventa l’ordine delle
istruzioni: all’interno della descrizione del processo, tutto viene eseguito in
ordine rigorosamente sequenziale. In esso si può usare una sintassi simile a
quella dei vari linguaggi di programmazione come C, introducendo la possibi-
lità di inserire assegnazioni condizionate, cicli, operazioni di tipo aritmetico
(se si utilizzano le librerie apposite), e cosı̀ via. Si noti che in questo ambito
VHDL diviene molto simile ad un linguaggio di programmazione, anche se
il sintetizzatore certo non va messo da parte: il ruolo del sintetizzatore sarà,
a questo punto, quello di identificare a partire dai costrutti utilizzati per il
processo un insieme di hardware atto a realizzare le funzioni in esso descritte,
e a collegarlo in maniera appropriata. Rimandando a un riferimento quale
VHDL Cookbook, si noti che esistono e sono utilizzabili i seguenti comandi
associati a relativi costrutti (e non solo):
• FOR;
• CASE;
• IF;
• LOOP;
63
elementi di questo genere possono essere anche realizzati mediante processi
espliciti, utilizzando i costrutti prima proposti.
Potrebbe essere utile, nel processo esplicito, utilizzare variabili; data una
variabile A alla quale si vuole assegnare ad esempio il valore “1”, si utilizza
un costrutto di questo genere:
A := 1;
2. Utilizzare il costrutto:
4. Body del processo, ossia insieme dei costrutti atti a descrivere il com-
portamento.
64
Una regola d’oro da utilizzare per i processi è la seguente: scrivere due
processi che pilotino la stessa uscita, forzandola magari a due diversi valori,
è brutto: si mettono infatti in conflitto le due uscite, provocando errori (che
però magari le librerie saranno in qualche modo in grado di risolvere). A meno
di casi specifici, ogni esame deve essere pilotato da uno e un solo processo.
Il processo deve considerare in modo esaustivo tutte le combinazioni del-
le uscite al variare degli ingressi, ossia ad esempio nel caso in cui si voglia
implementare una qualche tavola di verità, introdurre tutte le possibili com-
binazioni di ingressi, tutte le possibilità (a meno che non si voglia esplicita-
mente fare il contrario): se non si considerano possibili ingressi, il circuito
non cambia i valori, introducendo un errore del tipo “latch inferred”: poichè
il circuito non sa come comportarsi in questa situazione, dal momento che
non è stato definito un comportamento per l’ingresso, il circuito tende a non
cambiare niente, facendo introdurre al sintetizzatore dei latch (o comunque
elementi con memoria).
Come già detto, le assegnazioni nel process vanno eseguite sequenzial-
mente. Nel caso vengano assegnati più valori allo stesso segnale, ora, non
si ha concorrenza, bensı̀ “vince l’ultimo”: solo l’ultima istruzione relativa al
segnale verrà eseguita.
65
Nella sensitivity list si introducono due elementi, di cui uno fondamentale:
il Clock. Esso è un SIGNAL, un segnale, il collegamento a un pin. Il costrutto
presentato, basato su ’EVENT, fornisce il fatto che di tutto il segnale di clock
non si consideri il valore, bensı̀ esclusivamente il fronte, l’evento di variazione
e l’istante a esso relativo. Imponendo poi mediante AND che in fondo il clock
valga 1, permette di specificare il fatto che il fronte di campionamento sia
quello di salita. L’apice “ ’ ” indica l’attributo del segnale, in questo caso
il “fronte”, il fatto che il clock vari. Esistono nel VHDL altri attributi, che
però ora non ci riguarderanno.
Mediante una descrizione di questo genere è possibile definire non solo
blocchetti quali flip-flop ma circuiti complicati quali contatori o altro. Non
si analizzeranno nella trattazione esempi pratici, ma si esporrà in termi-
ni di linguaggio di descrizione l’implementazione di uno degli elementi più
importanti in un sistema digitale: il RESET.
Come visto, si è già introdotto un segnale “Reset” nella sensitivity list.
Ciò significa che, quando qualcuno “preme il pulsante del reset”, il processo
in questione sarà avviato. A questo punto, come ben noto, il reset si può
gestire in due maniere, ossia “sincrono” e “asincrono”; a partire da questa
idea si possono trovare due implementazioni ben differenti in VHDL, in grado
di implementare le idee precedentemente espresse.
• Per quanto riguarda il reset sincrono, esso deve essere per l’appunto
“sincronizzato al colpo di clock”, dunque la condizione sul clock prevale
su quella sul reset. Si dovrà utilizzare dunque un costrutto di questo
genere, in modo da “dare la priorità al clock”:
66
PROVA PROCESS(Clock, Reset)
BEGIN
IF Reset = ’1’ THEN .......... ;
ELSIF Clock’EVENT AND Clock = ’1’ THEN
BEGIN
...
...
END IF;
END PROCESS;
PROVA PROCESS()
BEGIN
WAIT UNTIL Clock = ’1’ AND Clock’EVENT;
...
...
...
END PROCESS;
67
Capitolo 7
Memorie
68
• Il parallelismo della memoria è piuttosto basso;
69
7.1.1 Static Random Access Memory
Le SRAM sono una categoria di RAM che si distingue per la propria capacità
di mantenere (se alimentate) anche per un tempo idealmente illimitato le
informazioni; questo fatto è dovuto alla robustezza dei componenti su cui
questa categoria di memorie si basa: l’elemento alla base di una SRAM è
un latch, elemento estremamente robusto e potente; si tratta di memorie
che richiedono una bassa alimentazione, ed estremamente veloci, ma con un
difetto che le rende inutilizzabili per molte applicazioni: il latch, per quanto
robusto, è un elemento che richiede una grossa area di integrazione, dunque
inutilizzabile per costruire, in poco spazio, grosse celle di memoria; vengono
spesso utilizzate come base per memorie di tipo cache (eventualmente dopo
introdotte).
Un esempio di realizzazione circuitale di una SRAM potrebbe essere il
seguente:
La logica combinatoria ha lo scopo di abilitare la memoria, per un’ope-
razione di lettura/scrittura. Introducendo logiche combinatorie aggiuntive, è
possibile selezionare il tipo di operazione da fare, ed effettuarla.
A questi tipi di logiche si può associare un decoder, in grado di, a partire
da una codifica di ingresso, selezionare una sola delle linee (abilitando uno
solo dei segnali di “select”), in modo da scrivere in una certa cella, indirizzata
dall’esterno.
Al fine di semplificare la logica di decodifica, è possibile utilizzare vari
stratagemmi, quale quello già citato di introdurre un’architettura di tipo
bidimensionale; sotto-stratagemma potrebbe essere quello di utilizzare due
decoder che puntino ad un certo indirizzo, uno per le righe e uno per le parole
(ossia per gli insiemi di colonne).
70
di un riempimento della bitline devono essere percepite, mediante un sense
amplifier, ossia un amplificatore in grado di “sentire” la variazione di tensio-
ne e renderla distinguibile, in modo da discriminare la presenza di un “1” o
di uno “0” presente nella cella di memoria all’istante di lettura.
La lettura di una cella di memoria dinamica è distruttiva; una volta letta
l’informazione, se si intende mantenerla, è necessario ripristinare il livello in
seguito alla lettura, e non solo: il transistore utilizzato come interruttore è
non-ideale, dunque anch’esso presenta perdite di vario genere: la memoria,
in altre parole, deve essere rinfrescata sia a ogni lettura sia dopo un certo
periodo.
Questa è la struttura di una memoria DRAM: mediante l’uso di due indici,
uno indicante la riga e uno indicante la colonna, è possibile selezionare la cella
di memoria interessata.
Questa memoria presenta più svantaggi che vantaggi, ma il suo vantag-
gio principale la rende cosı̀ appetibile da renderla la più utilizzata in ambito
commerciale: le dimensioni delle celle sono estremamente ridotte, quindi il
numero di celle realizzabili in un circuito integrato è estremamente elevato,
nell’ordine del miliardo. Parlando di questi ordini di grandezza, sarebbe ne-
cessario indirizzare su più di 30 linee di indirizzo, cosa che potrebbe provoca-
re limiti nella realizzazione; l’idea alla base della realizzazione di memorie di
questo tipo, dunque, è quello di selezionare prima una riga, poi una colonna,
in due istanti differenti.
Il problema enorme delle DRAM è il fatto che esse perdono, a causa dei
diversi elementi di non-idealità in esse presenti, informazione. In decine di
millisecondi infatti il contenuto del condensatore, per un motivo o per un
altro, si perde: essendo la capacità molto ridotta, la carica in esso contenuta
è molto piccola, quindi facile da perdersi. Ciò costringe il progettista a in-
trodurre un meccanismo molto scomodo: il refresh (rinfresco). Esso consiste
nel rinfrescare continuamente il contenuto della memoria, in modo da non
permettere mai che il contenuto sparisca, rendendo tuttavia la memoria non
utilizzabile durante il periodo di rinfresco. Ciò introduce inoltre un certo nu-
mero di segnali e blocchi di controllo, nonchè una logica di controllo, basata
su di un controllore del procedimento di rinfresco (refresh controller) e su di
un contatore (refresh counter); ciò che si fa nella pratica è una serie di letture
fittizie delle celle, in ordine, dove l’ordine viene controllato dal contatore che
contiene l’indice della riga di memoria in fase di rinfresco; ad ogni rinfresco
di riga, il contatore viene incrementato di un’unità, in modo da “tenere il
conto”, quindi si passa alla successiva lettura fittizia. Ad ogni colpo si rinfre-
sca una cella per volta, in modo da non bloccare per troppo tempo l’accesso
alla CPU.
Si osservi il seguente schema:
71
Si nota la presenza di due segnali non ancora discussi, RAS e CAS; si
tratta di segnali di temporizzazione per quanto concerne la riga e la colonna.
Come già detto, si usa la logica di decodifica applicata a righe e colonne in
due istanti differenti; al fine di utilizzare questo tipo di temporizzazione, si
ha una FSM che gestisce gli indirizzi e l’istante in cui devono essere acquisiti.
Una memoria può dunque essere utilizzata in modo sincrono; nella fatti-
specie, le più note tra le DRAM sono, per l’appunto, sincrone.
Analizziamo più nel dettaglio le più note di queste memorie.
Synchronous DRAM
Le SDRAM sono semplicemente delle DRAM in cui il trasferimento di dati
coinvolgente la memoria (in ingresso e/o in uscita) è dettato da un clock. Da
quando si fornisce il segnale di ingresso, dopo un certo tempo si ha un’uscita,
dettata dal clock, o viceversa: un clock forza la validazione delle operazioni,
in modo da rendere di fatto inutilizzabile, senza colpi di clock, le operazioni.
DDR
Aumentando la tecnologia si è andati verso una memoria in grado di elaborare
(nel senso di campionare o proporre in uscita), per ogni fronte, sia esso di
salita o discesa, due dati: le DDR (Double-Data Rate Synchronous DRAM).
Il concetto, di base, si può riassumere in due affermazioni:
72
mediante i segnali RAS/CAS. Aumentare la velocità delle memorie, a que-
sto stato, significa semplicemente ridurre i tempi morti; da qui, le attuali
evoluzioni delle memorie.
RAMBUS
Un tipo alternativo di memoria, che tuttavia non ha preso piede nelle archi-
tetture in uso, è il cosiddetto RAMBUS. Esso si basa sull’uso di un insieme
di tre linee di bit di indirizzo, cinque di riga e cinque di colonna, multiple-
xate; mediante un clock da 500 megahertz si fa viaggiare un pacchetti che
contiene informazioni di indirizzamento e di dato sul bus, dividendo in modo
da permettere accessi consecutivi a banchi differenti, aumentando l’efficienza
del sistema.
Il fatto che un sistema di questo tipo necessiti l’uso di una circuiteria
piuttosto complicata non ne ha permesso la commercializzazione, rendendolo
quindi inutilizzato.
73
ricerche in doppia chiave, ma ancor meglio di associare all’indirizzo un dato,
inventando cosı̀ le memorie tanto citate: le cache.
Le cache, di fatto, sono memorie CAM (Tag Memory) in cui si ha il dato,
e una parte che contiene l’indirizzo; la CAM verifica il fatto che l’indirizzo
sia presente in memoria, e se vi è un match conferma immediatamente la sua
presenza; la velocità di ricerca è enorme poichè le linee operano in parallelo,
fornendo dunque immediatamente un risultato.
• Memorizzare del codice da eseguire che, per certo, non dovrà più essere
cambiato;
74
PROM
Per programmare una ROM dunque si può semplicemente introdurre, in serie
al collegamento tra i source dei transistori e il potenziale di riferimento, un
fusibile: questa è l’idea alla base delle PROM, ossia delle Programmable
ROMs: si fonde in modo selettivo e irreversibile il collegamento.
Questo tipo di tecnologia presenta un vantaggio e uno svantaggio:
EPROM
Le EPROM (Erasable Programmable ROM) sono memorie basate su tec-
nologie di tipo differente, in grado di realizzare memorie programmabili e
cancellabili, in modo più o meno semplice, anche da un utente. L’idea alla
base di questo tipo di memorie è quella di usare particolari tipo di transistori,
detti FAMOS: si tratta di transistori MOS in cui si introduce una sorta di
schermo, in grado di inibire la creazione del canale di conduzione.
L’idea è la seguente: inserendo un gate aggiuntivo, detto “floating gate”,
tra il gate principale e il canale di conduzione di un normale MOSFET, in
condizioni normali il floating gate è neutro, di fatto, a meno di alcuni piccoli
effetti parassiti dettati dall’introduzione di capacità.
Se si alimentano il drain e il gate con una tensione molto alta, metten-
do il source a 0 V, gli elettroni tendono ad andare verso il drain, ma anche
verso il gate, spinti da un forte campo elettrico; essendo l’ossido di spessore
limitato, gli elettroni tendono a “schiantarsi” verso il floating gate, che si ca-
rica negativamente; l’ossido di fatto è ancora intatto, poichè la rottura è solo
elettronica, tuttavia l’energia degli elettroni non è sufficiente a permettere di
ri-superarlo, dunque il gate anche in stabilità rimane carico negativamente.
La tensione di soglia del transistore è cambiata: cambiando la tensione al
gate, non si riesce più a condurre, a differenza di prima, dunque, a meno che
non si mettano tensioni molto elevate, il transistore non reagisce più come
prima. Questo, ha dunque “programmato” il transistore.
Il fatto che si possa “eliminare” l’informazione dipende dal fatto che, se
si illumina il gate del transistore con una radiazione ultravioletta sufficiente-
mente intensa (la luce del sole per alcuni minuti è sufficiente), gli elettroni
75
nel gate flottante acqusiscono l’energia sufficiente per andarsene, e tornare
in situazione normale.
EEPROM
L’inconveniente delle memorie appena descritte consiste nel fatto che da pro-
grammare sono abbastanza balorde: sia la cancellazione che la scrittura,
di fatto, si basano su operazioni dannose, che dunque limitano la vita del-
la memoria, che non potrà essere riprogrammata per un numero infinito di
volte.
Le EEPROM (Electricaly Erasable PROM) sono memorie cancellabili
mediante i soli elettroni, mediante l’uso delle “leggi di Kirchhoff”: il campo
elettrico è tale da “cacciare” gli elettroni. Ciò si può in pratica realizzare in
due maniere:
Tutte quelle finora presentate sono memorie di diverso tipo, sotto il pun-
to di vista tecnologico; dal punto di vista dell’organizzazione, di fatto, non
importa più di tanto quale sia la tecnologia: la parte di selezione/decodifica
sarà sempre uguale, a meno di alcune eventuali aggiunte (a seconda delle pos-
sibilità di cancellazione o meno); ciò che cambia è il modo di trattare i segnali
internamente alle memorie, ma la logica “esterna” ad esse concettualmente
non dovrebbe cambiare particolarmente.
76
Capitolo 8
Introduzione ai circuiti
sequenziali asincroni
77
Ai fini della trattazione considereremo le seguenti ipotesi semplificative,
purtroppo non sempre presenti in un sistema:
78
fatto capitare di continuo, anzichè secondo una certa temporizzazione. Ciò
implica che, se da un lato una macchina sincrona ha bisogno di un’alimen-
tazione impulsiva, la cui ampiezza deve dipendere dal numero di porte che
commutano contemporaneamente, una macchina asincrona crea meno distur-
bi sull’alimentazione di rete. A causa di questi problemi di alimentazione le
piste ed i cavi vengono progettati di conseguenza, rendendo sia il progetto
sia la funzionalità del sistema molto meno efficiente.
Cercare tecniche per realizzare circuiti asincroni stabili è utile anche
dunque sotto questo punto di vista.
Può capitare (in realtà, capita di certo) di dover lavorare badando a dei
glitch. Si parla di “static hazard” quando un impulso fa de-stabilizzare uno
stato stabile. Si parla di “dynamic hazard” quando un glitch si forma durante
una transizione del segnale, provocando variazioni strane di stato.
Il problema sta nel fatto che nelle macchine asincrone hazard di questo
tipo, se non si previene in alcun modo, possono essere nefasti, in quanto
presenti con una certa frequenza.
Come si possono evitare i glitch in sistemi di tipo asincrono? Beh, in-
nanzitutto, cerchiamo di capire perchè si formano: essi si formano perchè si
passa da una configurazione ad un’altra, passando da un implicante ad un
altro (modellizzando il sistema mediante la mappa di Karnaugh) senza che
si abbia una contiguità tra un implicante e un altro. Per evitare ciò, spesso,
è sufficiente introdurre una certa ridondanza nel sistema: considerando più
implicanti di quelli che servono, creando però contiguità tra i vari implicanti,
si riesce ad evitare questo tipo di problema. In questo modo l’uscita non
si troverà mai in una condizione a rischio, perdendo qualcosa sotto il punto
di vista dei componenti presenti nel sistema ma guadagnando molto sotto il
punto di vista della stabilità.
Può capitare quindi molto frequentemente l’uso di macchine asincrone.
Ciò che può capitare è anche un qualcosa di tipo diverso: l’interazione tra in-
gressi (che potrebbero essere il mondo reale piuttosto che altro) asincroni con
macchine sincrone, o viceversa. Esistono quattro casistiche, che richiedono
tendenzialmente diversi tipi di trattamenti:
79
• Sincrono - sincrono : è necessario o che i due clock siano già sincroni,
o sincronizzare gli ingressi mediante il clock del circuito ricevente.
80