Sei sulla pagina 1di 75

Architettura

Degli
Elaboratori

Cimino M.
Minopoli L.

Università degli studi di Napoli Federico II


Corso di Laurea in informatica
INDICE
1. La Rappresentazione dell’informazione…………………………………..
Codifica delle Informazioni
Il Rumore
Rappresentazione numeri Interi Positivi
Rappresentazione numeri Reali
I caratteri ASCII
2. La Trasmissione dell’informazione………………………………………….
Rilevazione dell’Errore
3. L’algebra di Boole……………………………………………………………...
Introduzione
4. Reti Combinatorie………………………………………………………………
Codifica dei Simboli in Elettronica
Logica degli Interruttori
Rete Combinatoria
Rete Combinatoria Codificatore/Decodificatore
Rete Combinatoria Sommatore Binario
Rete Combinatoria Comparatore Binario
Decoder
5. Reti Sequenziali………………………………………………………………...
Rete Sequenziale
Flip-Flop Set-Reset con NOR
Flip-Flop Toggle (da conteggio)
Flip-Flop Data
Reti Sequenziali Sincrone
Flip-Flop JK
Flip-Flop Master-Slave
Shift Register a 5 bit
Sommatore Seriale a 16bit
6. Automi a Stati Finiti……………………………………………………………
Introduzione
Automa di Mealy ed Automa di Moore
Esempio di Progettazione e Realizzazione di una Rete Sequenziale
Riduzione degli stadi di un automa a funzionamento completamente specificato
Riduzione degli stadi di un automa a funzionamento non completamente specificato
7. Memorie………………………………………………………………………….
Static Random Access Memory
Espandere la capacità di ogni locazione di memoria
Espandere la capacità delle locazioni di memoria
Espandere la capacità delle locazioni di memoria e di ogni locazione di memoria
Pagina di Memoria
Selezione a coincidenza
Sintetizzare una funzione booleana attraverso una memoria (look-up table)
8. Sistemi Di Elaborazione…………………………………………………………
Interconnessione tra Registri
Linguaggio RTL(Register Transfer Language)
Somma tra il contenuto di due Registri
Differenza tra il contenuto di due Registri
Incremento del contenuto di un Registro
Rete Compelta
Arithmetic Logic Unit (ALU)
Sistema di Elaborazione
9. Macchina Di Mano………………………………………………………………
Introduzione
Registri della CPU
Repertorio di Istruzioni
Schema dei registri e collegamento attraverso dei bus
Set di Istruzioni
Temporizzazione e logica di controllo (I)
Cicli di Istruzioni
Istruzioni relative alla memoria
Istruzioni relative ai registri
Configurazione di Ingresso/Uscita
Interrupt di programma
Ciclo di Interrupt
Polling
Descrizione globale della macchina di mano
Logica di Controllo (II)
Rete di Controllo di AR
Rete di controllo dei Flip-Flop (Flag)
Logica di contorllo di AC
Alcuni programmi utili per la macchina di Mano
10. Memoria Cache………………………………………………………………...
Introduzione
Indirizzamento Diretto
Indirizzamento Associativo
Indirizzamento Set-Associativo
Algoritmi di sostituzione
Interlacciamento
Frequenza di accesso e penalità di fallimento
11. Memoria Virtuale………………………………………………………………
Introduzione
Funzionamento
MMU
Tabella di Pagina
La Rappresentazione dell’informazione
Codifica delle Informazioni:

La codifica delle informazioni è un’operazione atta alla rappresentazione delle informazioni stesse (es. Codice ASCII)
o per proteggere queste informazioni tramite appositi algoritmi; la codifica si dice: non ambigua quando ad ogni
elemento codificante può corrispondere un solo elemento codificato; non ridondante quando il numero degli elementi
prima e dopo la codifica coincide, ridondante altrimenti.

Se un numero è espresso in una base b1 e si vuole convertirlo in una base b2, basta dividere il numero e, poi, i
successivi quozienti presi ordinatamente dall'ultimo al primo. Per codificare un numero intero in una data base, si
necessita di ┌𝑙𝑜𝑔𝑏 |𝑁|┐ bit, mentre il massimo numero rappresentabile in una data base con un numero di cifre pari a
N è bN.

Il Rumore:

I sistemi di comunicazione sono costituiti da circuiti elettrici e per questo soggetti al cosiddetto rumore bianco, il rumore
bianco può essere ridotto ma non eliminato. Il rumore può essere di tipo deterministico o casuale. La presenza del
rumore comporta inevitabilmente la possibilità che un valore logico “0” possa essere letto come “1” da uno dei circuiti
elettrici. Questa possibilità è tanto più grande quanto maggiore è il livello di rumore e tanto minore quanto più alto è la
differenza di tensione tra “0” e “1”. Il Comparatore maggioritario ha 2 uscite, quella del risultato e quella per un possibile
bit di errore.

La lunghezza un numero decresce al crescere della base. Più piccola è la base e maggiore sarà il numero di cifra
necessario per esprimere un certo numero. La lunghezza di un numero naturale N in base b è dato da 𝑁 =
└𝑙𝑜𝑔𝑏 |𝑁|┘ + 1 . L’adozione di un numero fisso di cifre, comporta che nella rappresentazione di numeri naturali molto
più piccoli del massimo numero esprimibile con le cifre a disposizione, le cifra non utilizzate dovranno essere riempite
con “0”; E se il risultato di un’operazione supera il massimo numero esprimibile con I bit a disposizione si avrà un
overflow.

Rappresentazione numeri Interi Positivi:

 Rappresentazione con segno: Il primo bit a sinistra viene destinato a settare il segno del valore che dobbiamo prendere
in considerazione. 0 equivale a ‘+’, 1 equivale a ‘–‘. Con questa tecnica il valore massimo rappresentabile diventa 𝑏 𝑚−1 −
1.

 Rappresentazione alla base diminuita (in binario, complemento ad uno): Questa rappresentazione, consente di
𝑏𝑚 𝑏𝑚
rappresentare i numeri compresi tra [− + 1, + − 1], ogni cifra diventerà quindi |𝑏 − 1 − 𝑐𝑖 |, in binario per effettuare
2 2
questa rappresentazione basterà invertire il valore dei bit. Il valore zero sarà rappresentato da tutti i bit posti a 0, o posti a
1.

 Rappresentazione all’intervallo (in binario, complemento a due): Il primo bit a sinistra, indica il segno del numero; il
complemento a due si ottiene effettuando il complemento ad uno(vedi sopra) e addizionando uno al valore ricavato. Il valore
zero sarà rappresentato da tutti i bit posti a 0.

Rappresentazione numeri Reali:

 Rappresentazione in virgola fissa: In questo tipo di rappresentazione una parte dei bit viene impiegata per rappresentare
la parte intera, mentre un’altra parte viene impiegata per rappresentare la parte decimale. La quantità di bit da riservare è
arbitraria.

 Rappresentazione in virgola mobile: Con questa rappresentazione il nostro valore sarà uguale a 𝑁 = 𝑚𝑏 𝑒 , dove m è la
mantissa ed e l’esponente, la rappresentazione sarà del tipo (s,m,e). Un numero Sx,y sarà quindi espresso come
Sxy*10CifreX.

I caratteri ASCII:

La rappresentazione dei caratteri di tipo alfanumerico avviene secondo lo standard American Standard Code for
Information Interchange, la prima tabella ASCII è codificata da soli 8 bit; i primi 4 bit (hex) rappresentavano la riga e
i secondi 4 bit rappresentavano la colonna della tabella ASCII. Essendo la tabella codificata attraverso 8bit, vien
facile capire che il numero massimo di caratteri rappresentabili sono ben pochi (solo 256), dovendo implementare i
vari tipi di alfabeti non latini e i caratteri speciali si è arrivati a creare un’estensione della tabella ASCII che prevede la
codifica dell’informazione attraverso 16bit per un totale di 65536 caratteri codificabili. I valori appartenenti alla vecchia
tabella sono presenti, nelle medesime posizioni, anche nella nuova tabella ASCII estesa.

La trasmissione dell’informazione
La trasmissione dell’informazione avviene tra una sorgente e una destinazione per mezzo di un canale attraverso cui
l’informazione viene trasmessa codificata; La codifica serve in alcuni casi per la semplice rilevazione dell’errore, per
capire se c’è stata un'alterazione di qualche bit durante la trasmissione soprattutto quando si parla di canali wireless
(la statistica è di circa 1/1.000.000.000 di bit alterati durante la trasmissione), in altri casi si tratta di rilevazione e
correzione dell’errore.

Rilevazione dell’ Errore:

La rilevazione e correzione dell’errore non è certo una tecnica che avviene senza spese aggiuntive, infatti per potervi
fare ricorso non solo serve elaborazione del dato da sorgente e destinazione, ma serve anche una ridondanza del
codice; ovvero si aggiungono tanti bit quanti ne prevede il protocollo per poter svolgere l’algoritmo opportuno. Uno dei
primi algoritmi inventati per la rilevazione e la correzione dell’errore è stato quello di Hamming, il quale però
introduceva una ridondanza del 75% con un algoritmo non proprio velocissimo da eseguire visto che andava
applicato ad ogni Hex; In seguito ci sono stati alcuni algoritmi che si sono affermati molto poiché più veloci da
eseguire anche se senza correzione tra cui CRC, MD5, SHA1.

L’algebra di Boole
Introduzione:

L’algebra binaria di boole prevede un insieme A e le operazioni ⨁ (somma) e ⨂ (prodotto), che associano a coppie di
elementi di A un elemento dello stesso insieme. Le operazioni godono di quattro proprietà: commutativa, distributiva,
presenza di un elemento neutro, ogni elemento dell’insieme ammette un complemento. L’algebra delle porte logiche,
che appartiene all’algebra di boole, è l’algebra su cui si basa l’elettronica digitale; che si costruisce attraverso la
seguente tabella:

che produce la seguente tabella di verità:

Il Teorema di De Morgan asserisce che: ̅̅̅̅𝐴𝐵 = 𝐴̅ + 𝐵̅ ; ̅̅̅̅̅̅̅̅


𝐴 + 𝐵 = 𝐴̅ ∗ 𝐵̅ ; Se un elemento non appartiene ad AxB allora
non appartiene ad A o a B; se un elemento non appartiene ad A+B allora non appartiene né ad A né a B. Tramite il
Teorema di De Morgan è possibile capire che una delle due porte logiche fondamentali (OR, AND) non è
indispensabili se c’è la porta logica NOT.
Reti Combinatorie
Codifica dei simboli in elettronica:

Per codificare i simboli dell’algebra booleana nell’ambito dell’elettronica si utilizza una codifica che assegna dei valori
di tensione elettrica ai due simboli:

 Logica diretta: Al simbolo 0 viene associata la tensione 0V ed al simbolo 1 la tensione +5V;


 Logica invertita: Al simbolo 0 viene associata la tensione +5V ed al simbolo 1 la tensione 0V.

Nelle moderni apparecchiature elettroniche si è riuscito a calare il valore dei volt da attribuire ad un segnale per
ridurre la probabilità di andare incontro al rumore logico, cioè quelle interferenze che possono portare a cambiare un
simbolo da 0 ad 1 e viceversa. Le tensioni che si attribuiscono ai simboli sono diverse a seconda della logica di
progettazione che si decide di adottare:

 Transistor Transistor Logic: Tensioni dai 0V ai +0.8V oppure dai +2V ai +5V;
 CMOS: Alimentate a +5V.

Per controllare la logica all’interno di un circuito si fa uso di interruttori logici, che si dividono in due categorie:

 Normalmente aperti (NO): Si chiude quando riceve un 1 logico, rimane aperto se riceve uno 0 logico;
 Normalmente Chiuso (NC): Si chiude quando riceve uno 0 logico, rimane aperto se riceve un 1 logico.

Una delle componenti che realizza questa tecnologia è il relè, ma visto l’eccessivo consumo di energia si è deciso di
passare ad altro, come ad esempio i Metal Oxide Semiconductor Field Effect Transistor che sono composti da
silicio e realizzano perfettamente il funzionamento di interruttori NO ed NC. Le rappresentazioni di circuiti a seguire
faranno uso di generici interruttori, che se rappresentati aperti saranno NO e se rappresentati chiusi saranno NC.

Logica degli interruttori:

Con gli interruttori è possibile realizzare diverse funzioni booleane; i circuiti che fanno uso di due interruttori, uno NC
ed uno NO prendono il nome di CMOS (Complementary MOS). Tale tecnologia permette un basso consumo della
rete logica.

Inverter (Funzione logica NOT):


Quando da I viene immesso un segnale logico pari a
0, nel circuito passa la corrente che viene portata
dall’interruttore di sopra, quindi O riceve segnale
logico 0.

Quando da I viene immesso un segnale logico pari a


1, l’interruttore NO si chiude (quello di sopra) e
l’interruttore NC si apre (quello di sotto) così da
bloccare il flusso di corrente nel circuito ed avere,
quindi, uno 0 logico in uscita.
Funzione logica AND:
Quando, ad esempio, A=1 e B=1 gli interruttori di
sopra, che permettevano al circuito di alimentare
corrente nella parte sinistra, si chiudono così da
bloccare il flusso di corrente della parte sinistra;
così facendo la parte destra del circuito non riceve
più corrente in entrata, quindi uno 0 logico, che
immesso nell’inverter produce uscita di corrente,
quindi 1 logico.

Corto circuito: Si può verificare corto circuito quando non si sa quale segnale si avrà in uscita dal circuito; una delle
cause potrebbe essere collegare le uscite di due porte logiche direttamente, che è una operazione da evitare sempre.
Il corto circuito danneggerebbe le componenti elettroniche e provocherebbe il malfunzionamento del sistema.

Nella precedente figura, quando da A=B=0 facciamo diventare A=0 e B=1 (sinistra) si verficia un corto circuito
perchè nella parte sinistra la corrente continua a passare, ma nella parte destra viene aperto l’interruttore che
conduce la corrente direttamente verso la massa provoca il corto circuito.

Dato che non tutte le reti logiche devono per forza fare uso di una struttura CMOS si introduce un nuovo componente
che prende il nome di resistenza:
Nella parte destra si verifica lo stesso problema che c’era prima, cioè la corrente arriva alla massa. La differenza è
che con la resistenza viene limitato il passaggio di corrente che evita i danni all’interruttore chiuso.

Nell’ultimo circuito non era presente nessun interruttore NC e tutte le uscite confluivano su un unica linea, un circuito
del genere prende il nome di open drain che aumenta il consumo di energia del circuito ed aumenta i tempi di
commutazione (cioè il tempo che la corrente venga interpretata come segnale logico 0/1).

A seguire c’è un esempio di come sia possibile realizzare una stessa funzione logica attraverso una rete logica
differente:

Questo schema prende il nome di wired OR. Quando, ad esempio, A=B=1 si chiudono ambedue gli interruttori del
circuito di sinistra; la corrente arriva quindi a massa e si scarica (non ci sono danni perchè una resistenza limita la
tensione della corrente) facendo arrivare al punto O il segnale logico 0; successivamente ci sarà un inverter che
trasformerà il segnale logico 0 in 1 al punto Y.

Se si elimina la parte destra del circuito e si nega l’entrata del segnale di A e B (ottenendo NOT A e NOT B in
ingresso) si ottiene un wired AND.

Dato che nel wired OR e wired AND vi sono solo interruttori NO, anch’essi sono stati progettati con la metodologia
open drain. (nel wired OR prendiamo in considerazione solo la parte sinistra del circuito come open drain).

Rete combinatoria:

Un insieme di AND od OR in cui ci sono delle linee di ingresso, linee che collegano le uscite di porte logiche agli
ingressi di altre porte logiche o invertitori e linee di uscita prende il nome di rete combinatoria. (La funzione NOT
non è considerata una porta logica perchè, per definizione, una porta logica ha almeno 2 ingressi).

La realizzazione di una funzione logica è ben diversa dalla sua progettazione; quando la si progetta si rimane in
ambito matematico e non si tengono conto dei fattori temporali.
Quando si mette in pratica il tutto, invece, bisogna tenere conto dei fattori di tempo di risposta e propagazione.
Ogni componente ha un tempo di reazione ben differente, quindi bisognerà sempre assicurarsi che l’utilizzo di un
uscita di una rete combinatoria deve avvenire soltanto se si ha la certezza che tutte le uscite sono aggiornate ai valori
corrispondenti alla configurazione corrente delle variabili d'ingresso.

Rete combinatoria codificatore/decodificatore:


Per codifica si intende la rappresentazione di un simbolo in codice binario, in modo tale che questo venga poi
elaborato attraverso una determinata funzione. Il decoficatore ha la funzione inversa, prende come input il codice
binario e restituisce il simbolo corrispettivo.

Un codificatore è molto importante per la rappresentazione dell’informazione all’interno di un circuito. Si pensi ad


una tastiera che ha i tasti A, B, C e D; vogliamo fare in modo che se il tasto A riceve una pressione, a prescindere da
qualsiasi tasto venga premuto insieme, si voglia generare il risultato 0; la codifica permette di fare questa operazione:

Le X nella tabella di verità vogliono significare che a prescindere da quale sia il valore delle altre variabili booleane
(quindi a prescindere da quale tasto venga premuto), se la variabile A (se il tasto A viene premuto) assume valore 1,
la funzione x2 vale 0 e la funzione x1 altrettanto (per scelta arbitraria).

Il decodificatore fa il procedimento inverso, prende un insieme di simboli in codice binario e restituisce il relativo
simbolo che era stato codificato attraverso quel codice.

Ma cosa avviene una volta restituito il risultato? Di solito ad un circuito come questo vengono associati dei LED che
rappresentano il risultato ottenuto dalla codifica/decodifica, cosicchè anche l’operatore umano possa controllarne il
risultato. Se non si vuole che una volta ricavato un risultato questo rimanga sempre come configurazione del
dispositivo bisogna: prendere uno degli stati di ingresso e decidere che sarà la configurazione di “default” del
dispositivo e aggiungere una nuova variabile di ingresso al circuito chiamata “abilitazione” (ENABLE). Un
codificatore con queste caratteristiche prende il nome di Multiplexer ed un decodificatore il nome di DeMultiplexer.

Un multiplexer (analogamente vale anche per il demultiplexer) dispone di ingressi per i dati, un uscita di essi ed un
nuovo spazio denominato ingresso di abilitazione o di selezione:

Quello di sopra può essere un esempio: quando l’ingresso di abilitazione E assume valore 0, a prescindere da quale
dato vi sia in ingresso (da qualsiasi tasto A,..,D venga premuto) la rappresentazione di tale situazione è quella
composta da dieci 0. Se E assume valore 1, per ogni particolare configurazione di variabili di ingresso spetterà una
specifica codifica (es quando premo il tasto A questo viene codificato con la sequenza 0100000000).
Ogni multi/demulti avrà quindi un ingresso di abilitazione; convenzionalmente se vi sono n ingressi di abilitazione
allora ci sarà spazio per 2𝑛 ingressi.

Di solito un multi/demulti viene denominato “multi/demulti da n a m” dove n è il numero di ingressi dati disponibili ed
m il numero di uscite.

Alla sinistra è rappresentato un multiplexer da 4 a 1. Un demultiplexer


relativo sarà da 1 a 4. Come anticipato, avendo 2 ingressi di selezione
avrà 22 ingressi d’entrata.

Volendone rappresentare la relativa tavola di verità e rete combinatoria SOP:

Il demultiplexer può essere realizzato analogamente:


Rete combinatoria sommatore binario:

Attraverso questa rete logica è possibile effettuare somme tra codici binari. Ci sono due tipi di sommatori; quello più
semplice realizza una semplice somma tra 2 bit e prende il nome di
half-adder:

Dato che la somma in binario può generare un riporto (1+1 = 0 con riporto di 1) vi è la variabile logica Cn (carry) che
assume appunto tale valore di riporto. Il circuito di realizzazione è altrettanto semplice. (In realtà per realizzare la
funzione somma S si poteva utilizzare una porta logica OR esclusiva, anche denominata XOR, che ha la tavola di
verità di S).

Per ampliare il discorso possiamo considerare A e B non come singoli bit ma come parole di bit (quindi, ad esempio,
4 bit entrambi); così facendo un half-adder non andrebbe più bene per realizzare tale somma. Il circuito che realizza
somme del genere prende il nome di full-adder ed oltre ad avere due ingressi dedicati alle parole di bit da sommare
ne ha un terzo dedito al riporto del bit della somma precedente. Questo cosa significa? Quando vogliamo sommare
due parole da più bit, es 101 + 001, sommiamo bit per bit e se c’è riporto lo sommiamo con il risultato della somma
successiva, il terzo ingresso serve proprio a mentenere questo riporto. Le uscite rimangono sempre due, l’uscita S
che è il risultato della somma e l’uscita C che è il riporto complessivo di tutta la somma.

La realizzazione di questo circuito viene omessa ma è relativamente semplice costruirlo, basta guardare la tavola di
verità (ci saranno 7 AND perchè entrambe hanno uno stesso prodotto e due OR, uno che prende gli AND risultati per
S ed uno per C).

Ovviamente combinando più full-adder insieme è possibile effettuare somme ad n bit:


Si prende un bit del primo numero ed uno del secondo, li si somma insieme, il risultato viene dato in uscita dal primo
full-adder ed il riporto di questa somma viene passato al riporto in entrata del secondo sommatore, e così via. (Sn
restituità la somma di quei bit in uscita ed ovviamente c0 sarà 0 perchè anora doveva cominciare la somma).

Rete combinatoria comparatore binario:

E’ possibile realizzare una rete logica che effettua il confronto tra due bit per segnalarne una possibile disuguaglianza
oppure uguaglianza:

Il funzionamento è molto semplice ed è impelementabile attraverso un semplice XOR di cui neghiamo poi il risultato
(XNOR). Questo perchè la tavola di verità di una porta logica XOR è il duale di quella XNOR.

Il discorso, come per la somma, si può estendere a confronti tra due parole di bit. Ad esempio il caso di due parole da
4 bit:

Si confronta un bit della prima parola con un bit della seconda parola tramite la porta logica XNOR e si fa un AND di
tutti i risultati, così A=B se e soltanto se tutte le cifre erano uguali (le porte XNOR hanno restituito valore 1).

Per entrare più nello specifico è anche possibile realizzare confronti completi tra due bit, segnalando anche una
possibile minoranza/maggioranza del primo rispetto al secondo:

A seconda del risultato un uscita avrà valore 1.


Decoder:

Un decoder permette di implementare funzioni booleane senza doverle prima minimizzare, utilizzando la loro forma
canonica, se queste hanno un numero di ingressi relativamente piccolo (5-6), altrimenti è sempre necessario
minimizzare la funzione; ma la cosa interessante è che il decoder permette di realizzare qualsiasi tipo di funzione
booleana.

Qualunque funzione logica ad n variabili può essere sintetizzata con un decoder ad n ingressi ed una funzione OR ad
un numero di ingressi pari (o superiore) al numero di "mintermini" della tabella di verità.

Es se sulla riga A=0 B=0 C=1 D=1 la funzione che stiamo realizzando assume valore 1, si traccia una linea che da
questa riga entra direttamente all’interno dell’OR.
Reti Sequenziali
Rete sequenziale:

Quando una variabile di uscita da una rete viene collegata nell’ingresso di una stessa rete si parla di rete sequenziale
(es l’uscita di una porta viene collegata all’entrata di un’altra porta).

Tale collegamento costituisce una ricircolazione (o feedback) che rende la rete non combinatoria e ne introduce cicli
temporali.

Questo tende ad aumentare la complessità generale della rete che ma permette di risolvere problemi più complessi
che altrimenti sarebbero risolvibili con reti combinatorie enormi.

Flip-Flop Set-Reset con NOR:

Per capirne il funzionamento basta tenere a mente la tavola di verità della NOR (si considera il valore ottenuto dalla
porta OR e lo si nega); suddividiamo il circuito in vari casi:

 S=0 , R=1
Se R=1 allora 1 NOR B (qualsiasi cosa sia B) è 0, quindi Q=0 e di conseguenza A=0, otteniamo che 0 NOR
A=0 NOR 0=1=Q*.
S=0, R=1, Q=0, Q*=1

E’ qui la parte interessante di questo circuito, notiamo che gli stati Q e Q* sono uno il duale dell’altro, e lo si
può dimostrare per ogni specifico caso su R ed S.
Questo circuito è un primo approccio di memoria, lo si può capire dal seguente esempio:

Supponiamo che dopo la configurazione calcolata (R=1 e S=0) vogliamo azzerare gli ingressi, ricordando
che le uscite valgono Q=0 e Q*=1:

S=0, R=0, Q=0, Q*=1


Partiamo da R, abbiamo R=0 NOR B, ma B=Q*=1, quindi 0 NOR 1 = 0, di conseguenza Q=0; adesso
calcoliamo quello di sopra: Q*=S NOR Q=0 NOR 0=1
Gli ingressi sono stati azzerati, ma Q e Q* hanno mantenuto il valore che avevano precedentemente S ed R
(cioè 0 ed 1).

 S=1, R=0
Se S=1 allora 1 NOR B=0, quindi Q*=0 e di conseguenza B=0, otteniamo che 0 NOR B=0 NOR 0=1=Q.
S=1, R=0, Q=1, Q*=0

Azzerando S ed R:

S=0, R=0, Q=1, Q*=0


Partiamo da R, abbiamo R=0 NOR B ma B=Q*=0, quindi 0 NOR 0 = 1, di conseguenza Q=1; adesso
calcoliamo quello di sopra: Q*=S NOR Q=0 NOR 1=0
Ancora una volta Q e Q* hanno mantenuto i valori che avevano S ed R prima di essere azzerati.

 S=1, R=1
Q=R NOR B=0 (1 NOR qualsiasi cosa è sempre 0)
A=Q=0 => Q*=S NOR A=1 NOR 1=0
Quindi Q=Q*=0 , già qui si verifica un errore: come fanno Q e Q* ad essere uguali se sono duali? Inoltre si
noti che:

Proviamo a resettare S ed R:

S=0, R=0, Q=0, Q*=0


Q=R NOR A=R NOR Q*=0 NOR 0=1, ora Q=1:
Q*=S NOR B=S NOR Q=0 NOR 1=0
Ma S=R=0 e Q=1 e Q*=1, quindi non si è mantenuta neppure l’informazione precedente.

Ecco perchè il terzo caso non è utilizzato, è da evitare: non si considera mai la configurazione R=S=1.

Anche di una rete sequenziale è possibile tracciare la relativa tabella, che prende il nome di tabella di transizione.
Quella del Flip-Flop RS è la seguente:

Da cui è sempre possibile ricavare la forma canonica e minimizzarla (immagine di destra) per calcolare quale sarà il
prossimo stato di Q dati R ed S.

Nella tabella è omesso Q* perchè, come mostrato in precedenza, basta negare Q. La tabella si legge così, es: nella
prima riga, se ho che Q=0 e R=S=0 allora il prossimo stato in cui andrà Q è 0, questo stato è denominato Q’. (Infatti
Q=S NOR A=S NOR Q*=0 NOR 1=0).
Nella seconda riga se Q=1 ed ho negli ingressi R=S=0, allora Q avrà come prossimo stato 1.

Flip-Flop Toggle (da conteggio):

E’ un flip-flop molto semplice, ciò che fa è semplicemente cambiare stato quando riceve un “1” logico in ingresso:

Flip-Flop Data:

Il flip-flop data dispone di un solo ingresso e permette di memorizzare nell’uscita Q il valore che è stato
passato dall’ingresso D (si compone di due ingressi perchè utilizza un flip-flop RS, così facendo copre
entrambe le entrate, anche se il dato in ingresso viene memorizzato in Q):
Inserire nell’ingresso R la negazione del valore inserito in D permette anche di evitare il caso di input “1:1” che
porterebbe ad uno scorretto funzionamento del flip-flop RS.

Tutte le reti sequenziali che sono state presentate fino ad ora funzionano in maniera asincrona, cioè ogni
componente della rete lavora con i suoi tempi di funzionamento.

Un primo approccio per sincronizzare il funzionamento di una rete sequenziale è il flip-flop Data con un ulteriore
ingresso “enable”:

Il funzionamento è analogo al precedente, con l’aggiunta che è possibile decidere se memeorizzare un determinato
dato in input oppure lasciare il precedente memorizzato.
Quando all’ingresso ENABLE viene passato il valore logico “1” vorrà significare che il valore di ingresso inserito in D
dovrà essere memorizzato in Q (questo avviene attraverso la porta logica AND, se D=EN=1 => 1 AND 1 = 1 = S che
viene memorizzato in Q). Se il valore di ingresso di ENABLE è basso, il valore memorizzato in Q rimarrà invariato.

Una sequenza di flip-flop data collegati tra loro formano ciò che si chiama registro, cioè una memoria che memorizza
un numero di bit pari al numero di flip-flop data di cui si compone.

Reti sequenziali sincrone:

Quando c’è la necessità di sincronizzare il lavoro che deve svolgere un intera rete sequenziale c’è bisogno di un
“segnale” che venga collegato contemporaneamente ad ogni componente della rete. Un esempio di rete incrona è
la seguente:

Identifichiamo i componenti presenti:


 C1 e C2 sono due reti combinatorie generiche con n ingressi ed n uscite;
 Per ogni uscita delle reti combinatorie c’è un flip-flop data con ingresso ENABLE che memorizza il valore e
lo passa alla rete combinatoria successiva;
 Per scegliere di memorizzare o meno il valore di un uscita della rete combinatoria si è scelto di utilizzare un
componente chiamato monostabile (M). Il monostabile è una componente che sincronizza la rete a
comando: quando assume valore 1 (lo si può vedere dal simbolo che è presente sulle sue uscite) significa
che alla rete viene inviato un impulso che sincronizza il funzionamento delle varie componenti attivandne il
loro funzionamento; dopo un tempo fissato il monostabile ritorna a 0.
 D1 e D2 sono delle componenti che permettono di ritardare il segnale.

Per sincronizzare una rete in modo del tutto automatico vi sono diverse metodologie; una delle più semplici da
realizzare è questo oscillatore che funziona all’infinito:

E’ abbastanza evidente che, non appena il segnale di controllo DSTM1 diventa alto, il circuito
oscilla, nel senso che cambia stato da 0 ad 1 e viceversa perché il segnale d’ingresso viene invertito e re-immesso
nell’altro ingresso del NAND facendone, quindi, commutare l’uscita. Questo avviene in continuazione in un tempo che
dipende dal ritardo della porta utilizzata.

In generale, se un circuito è “simmetrico” anche il suo segnale elettrico è simmetrico e prende il nome di onda
quadra (si parla del segnale che produce in uscita un circuito).
Se un circuito non è simmetrico, per ciscuno dei livelli logici che lo compongono si definisce un parametro di nome
quota del ciclo e si esprime in % che di solito si riferisce al livello alto; ad esempio: dire che un certo segnale ha
quota del ciclo del 40% significa che il segnale elettrico che genera è il 40% delle volte alto, ed il 60% delle volte
basso.

In tali circuiti andiamo ad identificare la durata del loro ciclo di oscillazione e la chiamiamo periodo; il segnale da essi
generato prende il nome di clock.

Flip-Flop JK:

Il flip-flop JK è una rete sequenziale sincrona:


Un flip-flop JK può essere “configurato” come ogni tipo di flip-flop visto in precedenza, ma ha caretteristiche
definitivamente migliori.

La versione standard prevede due ingressi (J e K) ed il suo funzionamento è analogo al flip-flop RS, completamente
uguale, solo che prevede un terzo ingresso che è dedito a ricevere dei segnali di clock che ne permettono la
sincronizzazione con possibili altre reti.

Come già detto, il funzionamento del flip-flop JK è analogo al funzionamento del flip-flop RS, anzi, è meglio dire che
la sua tabella di transizione è la stessa di quella del flip-flop RS (lo si può anche osservare dalla figura; se si hanno
dubbi si effettui un confronto con questa e quella riportata nel paragrafo del flip-flop RS tenendo conto che L=0 e
H=1). Quindi in cosa è migliore? La struttura interna di questo flip-flop, come mostrato dalla tabella di transizione,
permette anche di ricevere l’input J=K=1 e funzionare correttamente! (Se J=K=1 lo stato di uscita sarà la negazione
dello stato che si trovava in Q prima dell’input di J=K=1).

Sono presentate due diverse tabelle di transizione perchè viene mostrato come il circuito può sincronizzarsi con il
resto della rete in modi differenti, attraverso dei segnali di clock.

Un clock può agire in due modi:

 A livello: il circuito funziona solamente se il clock è “attivo alto” oppure “attivo basso” (es: il circuito è a
livello alto-attivo alto se funziona solo quando il clock è settato ad alto)
 Sulla transizione (edge triggered): il circuito funziona solamente se il clock “passa da basso ad alto”
oppure “passa da alto a basso”.

Nella tabella di sinistra è mostrato un flip-flop JK che funziona con un segnale di clock a livello attivo alto (quindi il
circuito funziona fin quando il clock emette il segnale 1); nella tabella di destra è mostrato un flip-flop JK che funziona
sulla transizione “da basso ad alto” (anche detto positive edge triggered; cioè quando il segnale del clock passa da
0 ad 1, fai funzionare il circuito).

Come detto in precedenza, il flip-flop JK può anche essere configurato come toggle o come data:

 Toggle: Basta inserire negli ingressi J=K=1 e lo stato di Q commuterà nel suo duale (basta osservare la
tabella di transizione)
 Data: Basta porre che l’ingresso D=J e K=J* (cioè basta collegare l’ingresso D all’ingresso J ed il duale
dell’ingresso D a K).

Flip-Flop Master-Slave:

Questo flip-flop è un ulteriore miglioramento del flip-flop JK; è composto, all’interno, da due flip-flop JK, quello a
sinistra prende il nome di master e quello a destra il nome di slave.

Si nota subito che il segnale di clock viene rievuto in modo duale dai due JK interni. Questo permette di scegliere
quale operazione ci interessa fare.

Se ad esempio voglio prendere dei valori in input, allora (considerando che il flip-flop funziona con clock positive edge
triggered) setto il clock da 0 ad 1 ed attivo il funzionamento del master, il flip-flop si comporta normalmente ed
all’uscita del master troviamo il solito valore dipendente da quale input si è immesso. Adesso fin quando non setto il
clock da 1 a 0 il flip-flop slave non potrà ricevere in alcun modo l’output del master e dare in uscita l’ingresso inserito
in J e K. Questo permette, ad esempio, di scegliere quale input vogliamo passare ad un’altra rete (se l’ingresso ci
interessa allora lo passiamo al secondo flip-flop che lo trasferirà ad un altra rete, altrimenti non lo passiamo allo slave
e attendiamo l’input desiderato, tanto in uscita Q non avremo mai l’input immesso se non siamo noi a decidere che
sia così).

Questo tipo di flip-flop vengono utilizzati su reti più complesse di nome “shift-register” che permettono di scambiare
il contenuto tra due registri.

Shift-Register a 5 bit:

Tramite lo shift-register è possibile memorizzare una parola di bit all’interno dei flip-flop master slave di cui è
composto (come anticipato, questi flip-flop sono stati progettati per scambiarsi il contenuto in maniera ottimale).

 Input/Output Seriale: Questo shift-register è composto da un input seriale, cioè significa che se ad esempio
voglio memorizzare la sequenza 11111 dovrò inserire un “1” logico attraverso l’ingresso “serial input” ad ogni
periodo di clock; una volta inserito un 1 logico, al prossimo periodo di clock, il contenuto del primo flip-flop
verrà spostato nel secondo e verrà preso il secondo input nel primo flip-flop, e così via per gli altri fin quando
non ho inserito la parola da 5 bit. L’output seriale funziona allo stesso modo: per visualizzare l’intera
sequenza di bit in output dovrei effettuare 4 ulteriori shift per spingere tutti gli 1 nell’output QE.
 Input/Output Parallelo: L’input parallelo avviene su “PRESET A, ..., PRESET E” e permette di inserire
contemporaneamente tutti i bit all’interno dei registri evitando che il circuito effettui uno shift e ne prenda uno
ad ogni periodo di clock. L’output parallelo funziona alla stessa maniera, se volessi visualizzare tutta la parola
di bit potrei farlo senza ulteriori shift, in qualunque momento, dato che per ogni flip-flop è possibile
visualizzarne l’uscita su “OUTPUT QA, ..., OUTPUT QE”.
 Clear: E’ un ulteriore funzionalità che permette semplicemente di azzerare il contenuto dei flip-flop.

La tabella che mostra le funzioni del circuito, e in base a quali periodi del clock opera, è la seguente:
Sommatore seriale a 16 bit:

E’ un altro esempio di rete sequenziale:

Lo scopo è quello di sommare il contenuto dei registri A e B (che possono essere visti come shift-registers) e
memorizzare il risultato nel registro S.

Il funzionamento è molto semplice: l’input dei registri A e B avviene in modo parallelo; entrambi i registri sono
sincronizzati dallo stesso clock. Una volta memorizzate entrambe le parole di bit, queste vengono passate alla rete
combinatoria full-adder (FA) che ne fa la somma e trasferisce il suo risultato al registro S. Si può notare che il full-
adder, per ogni somma, memorizza il contenuto del possibile riporto (COUT) all’interno di un flip-flop master slave,
che successivamente lo passa al CIN (cioè: “alla prossima somma tieni conto che nella precedente ho avuto questo
riporto”). Inoltre, questo circuito permette di azzerare il contenuto del flip-flop master-slave attraverso un entrata di
clear.
Automi a stati finiti
Introduzione:

Data una rete sequenziale, indicheremo con:

 X = {x1, x2, ... } il vettore delle variabili d’ingresso della rete;


 Y = {y1, y2, ...} il vettore delle variabili interne della rete, che permettono di descriverne un suo stato.
 Z = {z1, z2, ...} il vettore delle variabili d’uscita dalla rete.

Quando è possibile rappresentare un sistema si può parlare di “automa”: dati un numero finito di ingressi, di uscite e
di stati interni, un automa non fa altro che descrivere la rappresentazione di una rete sequenziale.

Generalmente, in ogni rete sequenziale è possibile descrivere due funzioni:

 G(X,Y) : E’ la funzione che produce il vettore di uscita Z, quindi Z = G(X,Y)


 F(X,Y) : E’ la funzione che produce il prossimo stato (indicato con Y’), quindi Y’=F(X,Y)

E’ inoltre buona norma codificare gli stati interni della rete a partire da uno stato iniziale scelto opportunatamente per
fare in modo che all’accensione, la rete si trovi in quello stato. Questa fase è chiamata di inizializzazione.

Per descrivere un automa ci sono svariate metodologie, due di queste sono: la tabella di flusso (anche detta di
transizione, vista nel paragrafo delle reti sequenziali) e il diagramma a bolle.

Un esempio è il seguente automa, che descrive l’addizione in binario tra 2 bit:

Fin quando addiziono 0+0, 1+0 e 0+1, e non avevo riporti (infatti sono nello stato in cui non ho alcun riporto), rimano
in questo stato, perchè la somma produce 1 e non ottengo riporti, rimanendo nello stato attuale. Ma se ad esempio
sommassi 1+1 otterrei come risultato 0 con riporto di 1, allora devo transitare dallo stato A allo stato B, il quale indica
che vi è attualmente un riporto nella somma effettuata. 1+1 produrrà 0, ma avevo 1 di riporto, quindi 1 con nuovo
riporto di 1, quindi rimarrò in B; 1+0 farà 1, ma avevo 1 di riporto, quindi 1+1 = 0 con ancora riporto di 1, e rimango in
B; l’unico caso che mi permette di scaricare il riporto e passare allo stato in cui non ne ho (stato A) è 0+0, infatti
0+0=0 ma con riporto di 1 precedente si ottiene 1+0=1 con riporto di 0.

Si noti la notazione indicata all’interno del diagramma a bolle dell’automa: i valori che si trovano a sinistra dello slash /
sono i valori di input, i valori alla sua destra quelli di output; quindi, ad esempio, 10/1 significa che il mio input è 10,
facendone la somma ottengo 1 che rappresenta proprio il valore di output.

La rappresentazione di questo automa attraverso la tabella di flusso è la seguente:


A sinistra vi sono gli stati ed a destra vi sono i valori di input che è possibile passare all’automa; per leggere la tabella
si procede così: ad esempio, la prima cella, “se mi trovo nello stato A e viene passato come input 00, transito nello
stato A e restituisco output 0”.

Un altro esempio molto semplice potrebbe essere il prescaler (divisore di frequenza):

Che permette di dividere (in questo caso in 4) la frequenza di un segnale di clock.

Automa di Mealy ed Automa di Moore:

Un automa di Mealy lo si può descrivere attraverso questo schema di rete sequenziale:

Ci sono un determinato numero di ingressi che entrano sia nella funzione logica F (prossimo stato), che nella
funzione logica G (uscita). Le variabili d’ingresso che entrato nella rete F diventano variabili interne Y, che vengono
sincronizzate attraverso l’utilizzo dei ritardi (che di solito sono dei flip-flop Data) e ricircolano all’interno della funzione
F, oltre che ad entrare nella funzione logica G.

Questo schema non fa altro che descrivere ciò che abbiamo introdotto nel paragrafo precedente: la funzione G
prende come argomenti ingressi e variabili interne, la funzione del prossimo stato F fa altrettanto. C’è quindi una
dipendenza doppia, sia dalle variabili interne che da quelle date in ingresso.

E’ stata proposta da Moore una nuova versione di questo schema, che a primo colpo d’occhio sembra semplificarlo
sul piano concettuale:
La differenza da quello di Mealy è che le variabili di ingresso non vengono più direttamente passate alla funzione G,
ma soltanto quelle che sono state rielaborate dalla funzione F, cioè quelle interne.

Di conseguenza la dipendenza di queste funzione è diversa, avremo che G dipenderà soltanto dalle variabili
interne , Z=G(Y); mentre la funzione F rimane analoga alla precedente, e per calcolare il prossimo stato sarà sempre
necessario dipendere dalle variabili d’ingresso e quelle interne.

Entrambi questi schemi possono rappresentare una rete sequenziale che viene sincronizzata attraverso l’uso di flip-
flop Data:

A sinistra una rete sequenziale descritta con la metodologia di Mealy ed a destra con quella di Moore.

Per rappresentare una rete sequenziale è possibile utilizzare entrambi questi modelli, a volte, però, sarà più laborioso
utilizzare un modello di Moore anzichè uno di Mealy.

Dati due automi che descrivono la stessa funzionalità, uno descritto dal modello di Mealy ed uno dal modello di
Moore, non è sempre possibile effettuare un confronto tra questi due; tale confronto è possibile soltanto se gli
automi sono tra loro equivalenti:

Dati due stati S1 ed S2, di uno stesso automa, questi si dicono equivalenti se qualunque sequenza di valori di
ingresso applicata ad S1 ed S2 produce, in entrambi, la stessa sequenza di valori di uscita.

Dati due automi A1 ed A2, questi si dicono equivalenti se per ogni stato in A1, esiste uno stato in A2 che è il suo
equivalente.

Sostanzialmente si parte dalla definizione di equivalenza che vale tra stati: presi due stati, se entrambi questi stati
danno gli stessi valori di uscita quando gli vengono passati gli stessi valori di ingresso, questi si dicono equivalenti.
Allora due automi saranno equivalenti se ogni stato del primo ha uno stato equivalente nel secondo.

Un automa di Mealy si dirà equivalente ad un automa di Moore se, ignorando le combinazioni di uscita associate
allo stato iniziale dell’automa di Mealy, per ogni stato dell’uno esiste uno stato equivalente nell’altro, e viceversa.

Se è possibile effettuare un confronto tra questi due è anche possibile passare da un modello all’altro.
Passare da Moore a Mealy è sicuramente la trasformazione più semplice:

Ma, prima di tutto, si noti che l’automa di sinistra è rappresentato attraverso il modello di Moore; infatti l’output che
viene prodotto si trova all’interno degli stati e non sulle transizioni da uno stato all’altro (come avviene nell’automa di
Mealy; in questo caso l’output è rappresentato da lettere in stampatello mentre l’input da lettere in corsivo).

La traduzione è praticamente immediata, basta passare il valore di uscita dello stato all’esterno, sulla transizione.

Passare da Mealy a Moore è una trasformazione più complessa anche perchè sfavorevole:

Dato che in Moore (sinistra) l’output è riportato all’interno degli stati, può capitare che in uno stato vi entri una
transizione con output A ed un altra con output B, di conseguenza uno stato non può dare due output separati; cioè
che deve succedere è sdoppiare quello stato in modo tale da garantiere entrambi gli output (uno per stato).

Ad esempio, nello stato S3 entrano due transizioni, una con output A ed una con output B; allora lo stato S3 si
dividerà in due stati: S3/A ed S3/B, e in ognuno di essi entrerà l’arco corretto.

Si noti che, da ogni nuovo nodo introdotto dovranno uscire gli stessi archi che uscivano dal singolo nodo nel modello
di Mealy. Ad esempio: se da S3 uscivano due archi, uno a/B ed uno b/B, sia da S3/A che da S3/B dovranno uscire gli
stessi archi che dovranno essere collegati ai relativi stati corretti (che nell’esempio saranno S2/B e S1/B).

Inoltre, nel diagramma di Moore è stato introdotto uno stato iniziale S/-, chiamato anche di parcheggio, che non ha
combinazione di uscita e non può essere raggiunto da nessuno stato; sarà il famoso stato di inizializzazione.

Quindi, per concludere, tradurre un modello da Mealy a Moore può aumentare il numero degli stati dell’automa.

Esempio di progettazione e realizzazione di una rete sequenziale:

Si vuole progettare, e realizzare, un riconoscitore di sequenza; data una sequenza di bit, bisognerà segnalare
quando vi sono tre “1” logici contigui nella sequenza; esempio: 0010111 darà un output, ma anche 00101111, mentre
invece 010011011 no.
L’automa relativo è molto semplice ed è il seguente:

E’ stato realizzato attraverso il modello di Mealy.

Si procede a scrivere la relativa tabella di flusso per poi codificarla (immagine a destra):

Si è scelto di codificare A come 00, B come 01 e C come 11. Di conseguenza, indichiamo con y1’ il bit più a sinistra e
con y2’ il bit più a destra, invece la nostra funzione di uscita z sarà il valore dopo la virgola; esempio: 00,0 ->
0(y1)0(y2), 0(z). Ricordo che y1’ ed y2’ sono le variabili interne che rappresentano il prossimo stato all’interno della
rete, mentre y1 ed y2 i 2 bit che ci hanno permesso di codificare gli stati A, B, C.

A questo punto è possibile scrivere la nostra tabella di verità per rappresentare le tre funzioni specifiche (y1’, y2’ e z):

Si nota che y1’ assume valore 1 soltanto sulla riga B/X=1 (codificato sarebbe 011) e sulla riga C/X=1 (codificato
sarebbe 111). Lo stasso ragionamento si fa per rappresentare y2’ e z.

Ora possiamo rappresentare le tre funzioni prendendo i mintermini e scrivendo le relative SOP, semplificandole (per
chi non ha occhio basta disegnre le relative mappe di Karnaugh):

y1’ = y1* y2 x + y1 y2 x = y2 x

y2’ = y1* y2* x + y1* y2 x + y1 y2 x = x

z = y1 y2 x = y1 x

Ora possiamo realizzare la rete sequenziale, per realizzare y1’ utilizzeremo una AND e per realizzare z un’altra AND:
Come anticipato negli schemi in precedenza, si utilizzano due flip-flop D per sincronizzare le variabili interne y1’ ed
y2’.

Riduzione degli stati di un automa a funzionamento completamente specificato:

Dato un automa di cui la sua tabella di flusso è completamente specificata per ogni stato, è possibile procedere a due
metodologie che permettono di ridurre, se possibile, il numero di stati dell’automa semplificandolo ulteriormente.

Il lavoro che si vuole fare, in etrambi i casi, è raggruppare in classi di equivalenza gli stati dell’automa che tra loro
sono effettivamente equivalenti.

L'equivalenza di due automi comporta, evidentemente, che il numero di classi di equivalenza dei
loro stati deve essere uguale e, poiché tutti gli stati di una classe di equivalenza possono essere
sostituiti da uno solo di essi, ogni automa ammette un automa minimo ed esso è unico.

La prima metodologia è affidata al “buon senso” del progettista, cioè attraverso regole euristiche si può procedere
“ad occhio” ed identificare una classe a cui appartengono più stati; ad esempio:

Quando l’automa è semplice, come in questo caso, si può facilmente notare come lo stato A ed E siano praticamente
la stessa cosa, appartengono ad una stessa classe di equivalenza, le uscite vanno verso gli stessi stati con lo stesso
input ed hanno archi all’ingresso con lo stesso input/output.

Ciò che si fa è eliminare uno dei due stati, esempio E, e chiamare lo stato A come AE;
Si può continuare, lo stesso discorso vale per gli stati G e C, che si possono unire e formare lo stato GC, ed ancora,
lo stato AE può unirsi a B per formare AEB ottenendo:
un automa equivalente a quello iniziale ma molto semplificato.

Un metodo più rigoroso è chiamato criterio di equivalenza tra stati :

Gli stati Si e Sj sono fra loro equivalenti se, per ogni combinazione possibile degli ingressi Xh
per i due stati, sono uguali le combinazione delle variabili d'uscita (condizione necessaria):
G (Xh , Yi) = G (Xh , Yj)
ed i prossimi stati di entrambi sono fra loro equivalenti. Ciò si esprime simbolicamente con:
F(Xh , Yi) ~ F(Xh , Yj).

Se le combinazioni delle variabili d’uscita relative a due stati messi a confronto non sono uguali,
questo è sufficiente per concludere che gli stati non sono equivalenti, ma se, invece, l'eguaglianza delle uscite è
verificata, il controllo di equivalenza deve essere proseguito sul prossimo stato di ciascuno dei due nodi e poi,
eventualmente, sulla successiva coppia.

Per esempio:

Data la tabella di flusso vogliamo applicare il criterio dell’equivalenza tra stati. Ciò che si fa è tracciare quel
diagramma a scaletta (le diagonali sono eliminate perchè non serve dimostrare i simmetrici degli stati sono
equivalenti) e riportare, per ogni gradino, se i due stati sono equivalenti, se non lo sono e se dipendono da un’altra
equivalenza.

Esempio, consideriamo A e B:

Su ingresso 0, A da output 0 e B da output 0; su ingresso 1, A da output 1 e B da output 1. Sembrerebbe che A e B


siano analoghi, se non fosse che A, con ingresso 0, transita in G e B in C, lo stesso discorso vale quando c’è
ingresso 1, A transita in E e B transita in A; dunque, se GC e AE fossero equivalenti, lo sarebbero anche AB, quindi
nel gradino dell’incrocio AB segnamo quali stati dovranno essere equivalenti per far si che lo siano anche A e B.
A ed E, invece, sono banalmente equivalenti, come si può osservare dalla tabella di flusso; in questo caso, il gradino
si lascia vuoto.

A e C, invece, non sono equivalenti (basta guardare che con ingresso 0 A da output 0 e C 1, condizione sufficente e
necessaria a dire che non sono equivalenti); il gradino si barra.

Si procede fino a riempire tutti i gradini della scaletta.

Una volta riempiti tutti, possiamo renderci conto e controllare dove ci conducono gli stati che per essere equivalenti
dipendono dall’equivalenza di altri stati:

Esempio, controlliamo se A e B sono equivalenti: A e B sono equivalenti se lo sono C-G e A-E. Controlliamo C-G: C-
G sono equivalenti solo se lo sono A-E, ma A-E sono equivalenti, quindi C-G è equivalente, di conseguenza anche A
e B saranno equivalenti. Facendo questo tipo di controlli per ogni gradino giungiamo alla scaletta finale:

Quindi, come risultato finale avremo che:

A equivalente B
A equivalente E
B equivalente E
C equivalente G

Per transitività riusciamo a creare un unica classe di equivalenza: ABE, mentre uniamo in un’altra classe CG.

Per semplicità chiameremo tutte le classi identificate nell’automa in un altro modo:

ABE sarà alfa


CG sarà beta
D sarà gamma
F sarà delta

Adesso scriviamo la nuova tabella di flusso semplificata, ed il relativo diagramma a bolle:


Abbiamo così ottenuto l’automa minimo.

Riduzione degli stati di un automa a funzionamento non completamente specificato:

Può capitare che la tabella di flusso di un automa non sia completamente specificata, dove la funzione di transizione
non è definita; ad esempio:

In questi casi non si può più parlare di equivalenza tra stati, ma bisogna introdurre il concetto di compatibilità tra
stati:

Lo stato S1 dell’automa A1 si dice compatibile con lo stato S2 dell’automa A2 se per qualsiasi


sequenza d’ingresso applicata ad A1 nello stato S1 ed ad A2 nello stato S2 si ottengono due
sequenze d’uscita che coincidono ovunque entrambe sono specificate. In parole povere se in
una delle sequenze d’uscita appare il segno “-“ che significa “non definito” esso è, ovviamente,
compatibile sia con uno “0” che con un “1” nell’altra sequenza.

La definizione è simile a quella di equivalenza, ma meno forte; ad esempio prendiamo la seguente sequenza di bit:

-11111, questa sequenza si dirà compatibile con la sequenza 11111 oppure la sequenza 011111, perchè tutti i bit
specificati coincidono tra loro, mentre quelli non specificati sono associabili a qualsiasi bit.

Si parla non più di classi di equivalenza, ma di classi di compatibilità, che godono della proprietà simmetrica e
riflessiva, ma non di quella transitiva.

Questa mancanza di proprietà darà più liberta nella selezione degli stati che potranno appartenere ad una
determinata classe, ma allo stesso tempo complicheranno l’individuazione dell’automa minimo; sarà a scapito del
progettista capire se la suddivisione in classi effettuata porta alla condizione ottimale, oppure se ne dovrà scegliere
un’altra.

Si introduce un nuovo concetto, quello di copertura:


Si dice allora che un automa A2 copre un automa A1 se per ogni stato Si di A1 esiste uno stato
Sj di A2 tale che per qualsiasi sequenza di combinazioni delle variabili d’ingresso, applicata ad
A1 in Si ed ad A2 in Sj si generano sequenze d’uscita uguali ovunque la sequenza generata da
A1 è specificata.

Che sta a significare che dati due automi, se per ogni stato del primo esiste uno stato compatibile nel secondo, si dirà
che il primo copre il secondo.

Dato un automa non specificato si potrà utilizzare sempre il metodo “a scaletta” per trovare quali stati saranno tra loro
compatibili, con la facilitazione che dove non specificato, si potrà dare qualsiasi valore; ad esempio:

A e B sono tra loro compatibili.

Un’ultima proprietà interessante che dovrebbe avere un automa minimo è la chiusura, si prenda ad esempio:

Che è la riduzione dell’automa presentato all’immagine di sopra.

Chiusura: Questa caratteristica fa riferimento al fatto che per ciascuna combinazione d'ingresso i "prossimi stati" di
tutti gli stati di una classe di compatibilità, se specificati, appartengono tutti ad una stessa classe. Infatti, con
riferimento alla tabella di flusso originaria, si può constatare, ad esempio, che da A, B, e C, per ingresso "0", si va a,
D, -, E e gli stati D ed E sono entrambi della classe di compatibilità indicata con g ed analogamente per le altre due
classi.
Memorie
Static Random Access Memory (SRAM):

I primi dispositivi che hanno avuto la funzione di memoria sono stati proprio i flip-flop, come quello S/R oppure quello
Data. Tali dispositivi non possono essere considerati delle vere e proprie memorie perchè non si può avere la
capacità di leggere/scrivere a comando al loro interno.

Un esempio più avanzato che potrebbe avvicinarsi ancor più al concetto di memoria lo si potrebbe avere con un flip-
flop D sincrono, così da poter controllare quando memorizzare un determinato valore attraverso un segnale di clock.

Una delle strutture che assume appieno la funzione di memoria è la SRAM. Questa memoria è strutturata come se
fosse una matrice: la sua funzione è quella di memorizzare parole di bit; ogni bit è memorizzato all’interno di una
cella di memoria (che si compone, solitamente, di un flip-flop con qualche aggiunta che verrà specificata
successivamente); una sequenza di celle di memoria contigue prende il nome di locazione di memoria. La
particolarità di questa struttura è la logica di selezione: ogni locazione di questa struttura è identificata attraverso un
indirizzo di memoria, che ne permette l’accesso per una scrittura/lettura. Attraverso le locazioni è possibile
consultare solo la locazione di memoria desiderata.

Notare che: se una locazione contenete altri dati viene indicata per un’operazione di scrittura, i vecchi dati verranno
ovviamente sovrascritti uno per uno con i nuovi bit.

Capacità della memoria: Indica quanti bit può memorizzare complessivamente la memoria. Si calcola attraverso
questa formula: Cm = #L * #P ; cioè la capacità totale della memoria si ottiene moltiplicando il numero di locazioni
della memoria per il numero di bit che ogni locazione può contenere; ad esempio: se ho 8 locazioni di memoria e ogni
locazione può memorizzare 4 bit,
C = 8 * 4 = 32, che sarà la capacità di bit della memoria.

Capacità degli indirizzi: Indica il numero di bit di cui è composto un indirizzo in una determinata memoria. Si calcola
attraverso questa formula: Ci = [log_2(#L)]; cioè la capacità degli indirizzi si ottiene calcolando il logaritmo in base
due del numero totale di locazioni, arrotondato per eccesso al numero intero successivo; ad esempio: se ho 8
locazioni di memoria, gli indirizzi delle locazioni avranno capacità pari a 3 bit, una memoria da 4096 locazioni
richiederà una capacita degli indirizzi pari a 12 bit. Questo è il motivo per cui il numero di locazioni della memoria è
sempre una potenza di 2.

Un primo approccio di memoria lo si potrebbe schematizzare come segue:


Come si può osservare, ci sono un determinato numero di locazioni (nell’esempio n); ogni locazione è composta da
una sequenza contigua di celle di memoria (nell’esempio la capacità di ogni locazione è 32 bit).

Quello che si può notare è che per l’input e per l’output vi è un unico canale che viene collegato ad ogni cella di
memoria (che, di solito, prende il nome di Input/Output Register). Ciò significa che sarà necessario abilitare, per volta,
solo le celle contenute in una delle tante locazioni di memoria, in modo tale da trasferire il contenuto presente sul
canale di input al suo interno.
Le uscite di ogni cella si dicono logicamente connesse, cioè ogni uscita dei flip-flop confluisce attraverso un OR
logico, in modo tale che solo la locazione attivata venga resa disponibilie sul canale di uscita, altrimenti si
riceverebbero tutti i bit di tutte le locazioni, il che sarebbe un informazione priva di senso.

Ciò che è necessario aggiungere ad un flip-flop per poterne abilitare la lettura/scrittura a comando è una semplice
variabile logica, come si vede nell’immagine successiva:

Un esempio di memoria più specifico lo si può osservare dalla seguente immagine:

Sulla sinistra si nota un decodificatore (“Selezione”) che prende un indirizzo ed associa, all’interno della memoria, la
locazione corrispondente.

Ogni locazione di memoria è composta da k bit, per un totale di 2^n-1 locazioni.


E’ stato introdotto il canale R/W che permette l’abilitazione di un’operazione di scrittura oppure di lettura; si noti,
infatti, che questo canale è collegato agli ingressi dei flip-flop riservati al loro tipo di abilitazione. Per convenzione “1”
abilita la lettura e “0” la scrittura.

L’uscita del sistema di memoria funziona in logica invertita (come dire che se un bit di una certa locazione è ad “1”
logico, dopo la lettura c’è in quella posizione della parola d’uscita, un livello “basso”). Questa è una vecchia tradizione
che favoriva l’espansione di una memoria attraverso la combinazione di più chip, questo metodo veniva chiamato
open collector. Adesso si utilizza una nuova metodologia (spiegata successivamente), ma per tradizione rimane la
logica invertita.

L’illustrazione precedente prende il nome di chip di memoria, che potremmo indicare “all’esterno” come segue:

Dal punto di vista dell’utilizzatore il chip si presenta come una scatola nera alla quale si invia
un indirizzo ed un bit di funzione. Se il bit è “1” la scatola presenta in uscita il contenuto della
locazione interessata, se invece esso è “0” i valori booleani presenti ad un certo momento sulle
linee di ingresso dati vengono memorizzati in quella locazione.

Per capire meglio il funzionamento di un chip di memoria si può osservare i seguenti diagrammi temporali:

Praticamente tutti i sistemi di memoria sono “sincroni”, nel senso che i loro cicli di “lettura” e
“scrittura” sono guidati da un “segnale di cadenza” o “clock” a frequenza fissa e la durata dei cicli
è espressa in numero di periodi del clock. I cicli del diagramma temporale della figura sopra durano 4 periodi di clock.

Da notare che nel ciclo di scrittura il sistema che utilizza la memoria deve rendere disponibili i dati da memorizzare
non oltre l’inizio di T2 ma, ovviamente, i dati saranno effettivamente memorizzati nella locazione prescelta quando il
segnale di abilitazione alla scrittura si sarà propagato attraverso il sistema di memoria. Per evitare il rischio che
possano essere scritte nella locazione di memoria indirizzata dei dati errati, l’abilitazione alla scrittura viene tolta con
un mezzo periodo di clock di anticipo rispetto al limite di disponibilità dei dati.

Nel ciclo di lettura, la effettiva disponibilità dei dati per il sistema che ha chiesto la lettura in
memoria arriva con un ritardo asincrono rispetto al clock perché esso dipende dai tempi di
propagazione dei bit attraverso le linee ed i circuiti d’uscita della memoria. In ogni caso
l’abilitazione al registro del sistema che utilizza i dati deve essere generato con un congruo anticipo rispetto all’istante
in cui essi perdono validità (fine di T4).

Espandere la capacità di ogni locazione di memoria:

Siamo nel caso in cui si dispone di un chip di memoria che contiene un giusto numero di locazioni, ma l’informazione
che vogliamo memorizzare in ogni locazione è più grande della sua capacità. Ad esempio, abbiamo 16K locazioni ma
ognuna di queste può memorizzare solamente 4 bit, invece a noi serve memorizzarne 16.

Questo problema può essere risolto molto semplicemente collegando in parallelo più chip di memoria, fin quando non
si ottiene che ogni locazione abbia la capacità cercata:

Dato che ogni locazione nel chip aveva la capacità di 4 bit, mettendo 4 chip in parallelo otteniamo che ogni locazione
acquista la capacità di ben 16 bit. Ovviamente ci sarà da fare gli opportuni collegamenti con il canale di abilitazione;
inoltre per accedere ad ogni locazione sarà necessario che l’indirizzo venga passato ad ogni chip in modo tale da
estrarre complessivamente tutti i bit di ogni locazione per chip, ottenendo la parola da 16 bit.
Sembra una tecnica assurda, ma, purtroppo non ha alternative, perché la matrice deve necessariamente essere
interna al chip, essa, infatti, riduce il numero di pin del contenitore del chip per l’indirizzamento, in ragione del
logaritmo in base 2 del numero di locazioni. Per esempio per indirizzare 4096 locazioni bastano 12 pin invece di
4096.

Espandere la capacità delle locazioni di memoria:

Siamo nel caso in cui ogni locazione del nostro chip di memoria può contenere il giusto numero di bit che ci serve
memorizzare, ma contiene un numero di locazioni non sufficiente; ad esempio, abbiamo che il chip ha una capienza
di 2K locazioni, a noi serve memorizzare 16K parole di bit, di conseguenza bisognerà espandere il numero di
locazioni da 2K a 16K (servono 8 chip).

Nell’esempio che abbiamo introdotto bisognerà utilizzare degli indirizzi a 14 bit (Ci = [log_2(16K)] = 14).

Per risolvere questo problema di espansione si dividerà l’indirizzo in due parti (i dati dipendono dall’esempio preso in
considerazione):
 Gli 11 bit meno significativi (quindi 11 a partire da destra, anche detti Last Significative Byte) dell’indirizzo di
ogni chip saranno collegati ad un selettore di indirizzi esterno che permetterà di selezionare un indirizzo e
passarlo ad ognuno dei chip per prelevare l’informazione. Questo ovviamente è scorretto, perchè noi
vogliamo accedere ad un indirizzo che si trova in un determinato chip e non in tutti i chip; ci viene in aiuto il
punto 2;
 I 3 bit più significativi (quindi 3 a partire da sinistra, anche detti Most Significative Byte) saranno riservati ad
una decodifica che indicherà quale dei chip bisognerà abilitare per poter effettuare un operazione all’indirizzo
specificato. La tabella sottostante mostra che 3 bit sono necessari per indicare quale tipo di chip si tratta degli
8 che abbiamo:
Lo schema che ne viene fuori è il seguente:

Precedentemente si era anticipato che per gestire l’abilitazione delle uscite dei vari chip si utilizzava la metodologia
dell’open collector, cioè quello che funzionava a logica invertita; ciò che si è fatto successivamente è di introdurre una
logica come quella utilizzata nell’esempio precedente di espansione delle locazioni:

Questa metodologia prende il nome di driver tristate, cioè su ciascun pin dei dati di uscita si collega un bit di
abilitazione.

Questo pin di abilitazione prende il nome di Chip Select (CS).


Esso spesso viene duplicato o triplicato, nel senso che viene inserito all'ingresso del chip una funzione logica AND a
due o tre ingressi in modo che il segnale di CS venga generato solo quando tutti i pin di ingresso dell’AND sono ad
"1". Questo semplice artificio logico consente di attuare una strategia di selezione del chip di memoria che si
definisce, come vedremo più avanti, "selezione a coincidenza".

Espandere la capacità delle locazioni di memoria e di ogni locazione di memoria:

Ci troviamo nel caso in cui non basta ne la capacità di ogni locazione, ne il numero di locazioni.
La soluzione è unire le soluzioni dei due casi precedenti; prendiamo come esempio il seguente caso: si disponde di
chip che hanno 64 locazioni (6 bit di indirizzo) e la capacità di ogni locazione è pari a 4 bit. Ciò che si vuole costruire
è una memoria che abbia 256 locazioni e la capacità di ogni locazioni deve essere 1 byte.

Passo 1: Il numero di chip di cui abbiamo bisogno è 2, infatti con due chip raggiungiamo la giusta capacità di ogni
locazione e risolviamo il problema numero uno; ciò che otteniamo con 2 chip di questo tipo è un collegamento di
queste due memorie. In totale avremo 128 locazioni che hanno la capienza di 4 bit, ma collegando ogni locazione del
primo al secondo, otteniamo 64 locazioni da 1 byte ciascuna.

Passo 2: Creato un chip di questo tipo bisognerà risolvere anche il problema numero 2, cioè passare da 64 locazioni
a 256; per ottenere questo numero di locazioni ci serviranno 4 dei nuovi chip che abbiamo formato al passo 1. Quindi,
in totale avremo 512 locazioni da 4 bit (8 chip totali, 4 di quelli formati al punto 1) che collegate tra loro per risolvere il
problema diventeranno logicamente 256 locazioni da 1 byte di capienza.

Nell’esempio è mostrata la soluzione descritta:

I fili di collegamento saranno 6 perchè essendo 64 locazioni a chip, l’indirizzo sarà di 6 bit.

Pagina di memoria:
Il metodo generale di gestione dell'indirizzo di un sistema di memoria prevede due matrici di
selezione, una interna ai chip, che utilizza i bit meno significativi dell'indirizzo ed un'altra, esplicita, che usa i bit più
significativi per selezionare il gruppo di locazioni a cui corrisponde l'indirizzo completo, attraverso il CS (come visto
nel caso dell’espansione delle locazioni di memoria).

Questo meccanismo di ricerca può essere assimilato a quello da usare in un libro, in cui ciascuna informazione
occupi sempre un rigo (e non più di un rigo) di una pagina e ciascuna pagina contiene sempre e comunque un certo
numero di righi.
Il gruppo di bit meno significativi dell'indirizzo, che viene distribuito identicamente ai blocchi di locazioni (banchi o
chip) individuano la "parola" della memoria (il rigo nelle pagine del libro); gli altri selezionano la "pagina" giusta.

Selezione a coincidenza:
Si intende qualsiasi dispositivo che per funzionare ha bisogno del contemporaneo verificarsi di
due distinte condizioni, può essere oggetto di una selezione a coincidenza.

Nel nostro caso potrebbe essere la selezione di una locazione di memoria; per accedervi è necessario conoscere il
suo indirizzo e che il CS abliti tale chip.

Sintetizzare una funzione booleana attraverso una memoria (look-up table):


Per sintetizzare una funzione booleana avevamo precedentemente introdotto delle reti combinatorie come il
multiplexer oppure il decoder.

Un metodo più avanzato sarebbe quello di utilizzare una ROM (Read Only Memory), oppure una PROM
(Programmable Read Only Memory); all’interno di ogni locazione (da 1 bit di capacità) si memorizza il valore
booleano della funzione. Ovviamente per indicare a quale particolare configurazione di variabili appartiene quel
valore si tiene conto dell’indirizzo a cui è stato memorizzato tale bit, l’esempio che segue chiarirà le idee:
Se volessi conoscere il valore della funzione f quando le variabili di ingresso hanno la configurazione 1001, basta
richiedere il contenuto della locazione che si trova all’indirizzo 1001 per averlo in uscita.
Sistemi di Elaborazione
Interconnessione tra registri:

Esistono due soluzioni per trasferire il contenuto da un registro ad un altro:

 Rete Mesh (utilizzare dei multiplexer):

In questo esempio sono stati utilizzati 4 multiplexer per instaurare dei collegamenti con tutti i registri presenti.
Se, ad esempio, voglio trasferire il contenuto del registro R3 in R1, attivo gli ingressi S0=S1=1 ed il contenuto
potrà essere trasferito da R3 ad R1. Sempre in questo esempio è possibile effettuare più trasferimenti alla
volta per ogni registro.

Tale rete diventa svantagiosa quando si ha un elevato numero di registri, il che aumenterebbe di molto il
numero di funzioni logiche per realizzarla. Esistono soluzioni più economiche, ad esempio quella riportata
qua in basso, che limita, però, il numero di trasferimento ad uno per volta:

Una volta che il trasferimento in corso (per esempio, R1 ← R0, che si effettua ponendo S0=S1=0 ed
abilitando in registrazione R1) ha impegnato il multiplexer non è possibile effettuare altre operazioni che
coinvolgano la rete a valle del multiplexer ma rimane possibile utilizzare il contenuto dei registri, anche di
quello che è la destinazione del trasferimento in corso, se i registri sono del tipo Master/Slave.
 Bus dei dati:
E’ una interconnessione più economica che permette di collegare su uno stesso “canale” tutti i registri
attraverso connessioni che sono bidirezionali. Le uscite dei registri dovranno essere di tipo open collector
oppure tristate:
Linguaggio RTL (Register Transfer Language):

Gli esempi di sigle letterali usate nella tabella per indicare alcuni registri non sono scelte a caso, perché PC sta per
“Program Counter”, ACC sta per “Accumulatore” che, come vedremo in seguito sono registri importanti di un sistema
di elaborazione. Molto importanti sono anche le notazioni usate per indicare parti (1 byte) di registri a molti più bit,
infatti, come si vede in tabella la parte che contiene il byte meno significativo di in registro a 16 o a 32 bit può essere
indicata con un indice (1) o facendo esplicito riferimento ai bit (0:7), oppure usando (L) che sta appunto per “Lower”
che in inglese significa “il più basso”. La freccia verso sinistra, indica in maniera trasparente il trasferimento dati. Nella
tabella sono indicate le notazioni per le operazioni logiche ed aritmetiche possibili tra i contenuti di due registri.

Somma tra il contenuto di due registri:

Vogliamo descrivere l’istruzione RTL: R3 ← R1 + R2

Abbiamo due registri R1 ed R2 da 4 bit che vengono trasferiti agli ingressi di sommatori binari che sono interconnessi
tra di loro formando una struttura modulare; le uscite dei sommatori verranno trasferite all’interno del registro R3.

Differenza tra il contenuto di due registri:

Vogliamo descrivere l’istruzione RTL: R3 ← R1 - R2

Basta considerare che ponendo M=1 si ottiene che attraverso gli XOR arriva alla batteria di sommatori completi il
“complemento ad 1” del contenuto di R1 e l’inserimento di un riporto “1” nel sommatore dei bit meno significativi lo
trasforma nel “complemento a 2” (aggiungendo il complemento a due del sottraendo al minuendo).

Incremento del contenuto di un registro:

Vogliamo descrivere l’istruzione RTL: R1 ← R1 + 1

Il criterio è come quello dei precedenti, se non più semplice. Si prende il contenuto del registro R1, lo si somma con
1, il contenuto viene messo in un registro di appoggio RP che ne trasferirà il suo contenuto ad R1.

Il decremento è completamente analogo con la differenza che si effettuerà un complemento a 2 tra il contenuto del
registro R1 ed il bit 1 in ingresso.

Rete completa:

E’ possibile unire in un unica rete la possibilità di eseguire tutte le operazioni fondamentali presentate sopra:

L’uso dei multiplexer permette di selezionare il tipo di operazione da effettuare. Tutte le operazioni che questa rete
svolge, con le relative configurazioni, è descritta nella tabella seguente:
Arithmetic Logic Unit (ALU):

Per realizzare una rete che svolge qualsiasi tipo di operazione è necessario ancora introdurre due particolari
operazioni isolate; la prima di questa permette di realizzare operazioni logiche tra due operandi (AND, OR, XOR,
NOT):

(S0=S1=1 -> E = A*)


L’ultime operazioni che mancano sono gli shift che un registro può effettuare:

Le tre strutture booleane sintetizzate risolvono ciascuna uno dei compiti di una cosiddetta Unità Aritmetica e Logica
(ALU), cioè della parte di un sistema di elaborazione che materialmente esegue le operazioni logiche ed aritmetiche.
Perché tutte e tre le funzionalità siano presenti in un'unica struttura bisogna combinarle in maniera efficiente:

A e B sono i registri di ingresso, è possibile shiftare a sx oppure a dx il registro A (output in ingressi 2-3 del
multiplexer), è possibile calcolare un operazione logica tra A e B (output in ingresso 1 del multiplexer), è possibile
calcolare un operazione aritmetica tra A e B (output in ingresso 0 del multiplexer); per abilitare gli ingressi del
multiplexer e dare in output il risultato di una delle operazioni possibili si utilizzano S3 ed S1, collegati agli ingressi di
abilitazione (Sel) del multiplexer.

Sistema di elaborazione:

Un “sistema di elaborazione”, è una struttura logica in grado di eseguire su dei “dati” in ingresso operazioni logiche
od aritmetiche ottenendo dei “risultati”.

Le operazioni da effettuare sono individuate attraverso codici numerici detti “istruzioni”.

Una “istruzione” è una operazione del sistema esprimibile in una sequenza di microoperazioni (µoperazioni) che per
questo motivo viene detta “µsequenza”. Ogni µoperazione può impegnare diverse parti del sistema ed essere quindi
costituita di un insieme di operazioni singole da eseguire in un certo intervallo di tempo.

Per realizzare il sistema in questione lo si può suddividere in due unità:

 Unità operativa: esegue le sequenze di operazioni previste per trasformare i “dati” X nei“risultati” Z.
 Unità di controllo: interpreta le “istruzioni” trasformandole in “comandi” (alfa) che sono funzione anche
delle “condizioni” (beta) attraverso le quali la rete operativa comunica a quella di controllo lo stato di
avanzamento della elaborazione.

Entrambe le parti del sistema sono reti sequenziali sincrone il cui funzionamento è cadenzato dallo stesso “clock”.

In linea di massima una µsequenza esprime la successione delle azioni elementari della parte “operativa” del sistema
in cui la parte di “controllo” traduce ciascuna istruzione.

I “comandi” non sono altro che i codici numerici che abbiamo visto associati a ciascuna operazione logica, aritmetica
e di trasferimento nei vari esempi di reti di interconnessione tra registri e blocchi logici combinatori, considerate per
introdurre il linguaggio RTL.
Macchina di mano
Introduzione:

Un computer è composto da tre componenti fondamentali: una memoria, un processore di


ingresso/uscita ed un processore centrale. Quest’ultimo è quello che si occupa di trasferire ed
eseguire qualsiasi tipo di operazione; per motivi didattici si presenterà un processore ideale ed
astratto.

Il computer che viene presentato prende il nome di “macchina di mano”. L’interazione tra utente e
processore avviene attraverso il “programma”. Il programma è una lista di istruzioni che
specificano le operazioni, gli operandi e l’ordine in cui operazioni stesse vanno eseguite. Una
istruzione è un codice numerico binario che specifica la sequenza di μistruzioni che bisogna
eseguire su un dato. Istruzioni e dati sono registrati in memoria. La CPU legge ciascuna
istruzione dalla memoria e la trasferisce nel registro di controllo.

Ogni CPU ha un suo esclusivo “repertorio di istruzioni” (instruction set) che rappresenta per
l’utente il risultato delle scelte elettroniche del progettista della struttura. La CPU di un computer di
uso generale (general pourpose computer) è in grado, per definizione, di eseguire sui dati
qualsiasi operazione logico-matematica che sia stata correttamente tradotta in una lista ordinata
di istruzioni prese dal suo repertorio.

Il codice numerico di una istruzione è, di solito, diviso in due parti, ciascuna con un preciso
compito. La parte fondamentale di un codice di istruzione è quella “operativa”. Il codice
operativo deve essere composto da un numero di bit n, sufficiente a codificare le diverse distinte
operazioni che si vogliono eseguire (2^n); Se supponiamo, ad esempio, che si voglia un
repertorio di 64 distinte operazioni allora il codice operativo deve essere di almeno 6 bit.

Nel sistema ipotizzato, allora, possiamo stabilire che all’operazione ADD corrisponde, ad
esempio, la combinazione binaria “1 1 0 0 1 0”. Quando questo codice viene presentato alla
logica di controllo, che come abbiamo visto è sostanzialmente costituita da una ROM, esso viene
“decodificato” per poter essere trasformato in una successione di comandi.

Registri della CPU:

All’interno della CPU sono previsti diversi registri, ognuno dei quali viene utilizzato per una
funzione ben precisa; nella macchina di mano troviamo i seguenti registri:
La memoria che si ipotizza di usare contiene 4096 locazioni da 16 bit.

Repertorio di istruzioni:

E’ possibile catalogare le istruzioni in tre macro categorie: istruzioni relative alla memoria,
istruzioni relative ai registri ed istruzioni relative i registri di input/output.

Ognuna di queste istruzioni è identificata attraverso un indirizzo che si struttura in maniera


differente; generalmente un indirizzo all’interno della macchina di mano è composto così:

La divisione di un indirizzo “generico” è composta da una parte relativa all’indirizzamento (cioè


indica se all’indirizzo specificato ad un istruzione si trova direttamente il valore da utilizzare,
indirizzamento diretto, oppure la locazione in cui è contenuto il valore da utilizzare,
indirizzamento indiretto). L’indirizzamento indiretto potrebbe essere utile, ad esempio, quando
da due programmi diversi vogliamo accedere allo stesso dato. L’indirizzamento occupa solo 1 bit
dell’indirizzo e vale 0 se l’indirizzamento è diretto, 1 se l’indirizzamento è indiretto.

La seconda parte dell’indirizzo occupa 3 bit ed è relative al codice operativo dell’istruzione. I


restanti 12 bit identificano tutto ciò di cui ha bisogno l’istruzione che si sta chiamando in causa.

Andando più nello specifico, per ognuna della macrocategorie riportare all’inizio del paragrafo vi è
una struttura specifica d’indirizzo che è la seguente:

Le istruzioni relative alla memoria utilizzano i 12 bit meno significativi per specificare l’indirizzo
della locazione a cui accedere, il bit più significativo per identificare il tipo di indirizzamento ed i
restanti 3 bit (14..12) per identificare il codice operativo che per la memoria può assumere valori
da 000 a 110.

Le istruzioni relative ai registri utilizzano i 12 bit meno significativi per specificare il tipo di
operazione oppure un test sul contenuto dell’accumulatore (AC) o su altri registri (es. Flip flop che
vedremo dopo), il bit più significativo riguarda sempre l’indirizzamento (che è diretto) ed i 3 bit di
codice operativo hanno valore fissato ad 111.

Le istruzioni relative ai registri di input/output utilizzano i 12 bit meno significativi per specificare il
tipo di operazione o il test da effettuare, il bit più significativo riguarda l’indirizzamento (che è
indiretto) ed i 3 bit di codice operativo hanno valore fissato ad 111.

Il tipo d’istruzione è riconosciuto dalla rete sequenziale di controllo del processore esaminando i
quattro bit dalla posizione 12 alla 15. Se i tre bit da 12 a 14 non sono tutti ad 1 l’istruzione è del
tipo “relativo alla memoria” ed allora si passa ad esaminare il bit in posizione 15 per stabilire il
“modo” in cui bisogna usare i 12 bit di indirizzo. Se l’opcode è invece 1 1 1, allora il valore del bit
15 deciderà se si tratta di una istruzione “relativa al registro” (bit 15 a “0”) od una istruzione di
ingresso/uscita (bit 15 a 1). Il bit 15 si indica con I anche in questi casi in cui non indica il “modo”
di indirizzamento.

Schema dei registri e collegamento attraverso dei bus:

La memoria è composta da un ingresso per l’indirizzo (A), un ingresso per l’uscita


dell’informazione (D) e due ingressi che specificano se l’operazione da fare è di lettura/scrittura.
La memoria riceve i dati dal bus quando è attiva la sua linea di scrittura W. Essa metterà sul bus i
suoi 16 bit d’uscita quando è attiva la linea di lettura, R ed è contemporaneamente selezionato
l’indirizzo S2S1S0 = 1 1 1.

Ognuno dei registri (tranne INPR) è composto dell’ingresso LD (Load Data); tale ingresso
riguarda l’abilitazione per un caricamento parallelo dei dati. Praticamente serve ad abilitare il
registro a ricevere dati in ingresso. Quello dei registri che ha in un certo istante attivato l’ingresso
di LD riceverà alla prossima transizione attiva del clock la combinazione di valori logici che era sul
bus.
Ognuno dei registri (tranne INPR e OUTR) è composto dall’ingresso INR (Increment); tale
ingresso abilita il registro ad incrementare di un unità il suo contenuto.

Ognuno dei registri (tranne INPR e OUTR) è composto dall’ingresso CLR (Clear); tale ingresso
abilita il registro ad azzerarne il contenuto.

Ogni registro (tranne INPR) è sincronizzato attraverso un clock.

Le considerazioni sul registro INPR sono abbastanza ovvie, essendo il registro che permette di
prendere in ingresso dei dati forniti dall’utente, sarà utilizzabile solo quando richiesto e non
necessita di nessun ingresso come i precedenti o clock.

Una volta preso un dato in ingresso è ovviamente necessario che questo venga elaborato
attraverso l’ALU che comunica soltanto con l’Accumulatore, registro fatto apposta per dare
supporto a trasferimenti ed operazioni.

L’ALU è anche collegata al flip-flop E che è un estensione dell’ALU, nel caso un riporto generi un
bit in più.

Gli ingressi s0, s1, s2 riguardano la selezione del registro per abilitarne l’emissione del dati di
uscita sul bus. Si utilizza la logica tristate praticamente. Se ad esempio, S2, S1, S0 sono 011, i
valori booleani dei 16 bit del registro DR si propagano sulle linee dati del bus. Ogni registro ha un
determinato codice, si noti che in ogni ingresso delle porte AND vi sono valori di ingresso
negati/non negati, infatti a DR corrisponde 011 perchè nell’AND relativo S2 è negato e gli altri due
(S1 ed S0 no).

Gli ingressi e le uscite dati della memoria sono connessi al bus ma gli ingressi per l’indirizzo della
memoria sono collegati al registro AR. L’unico modo per indirizzare la memoria è, quindi, quello di
trasferire l’indirizzo desiderato in AR.

Il caricamento dei 16 bit dell’accumulatore avviene attraverso l’unità aritmetica e logica, ALU che
ha tre diversi gruppi di ingressi. Un gruppo di 16 ingressi viene dalle uscite dello stesso AC ed è
usato per ri-introdurre nell’accumulatore un dato sottoposto nella ALU ad una operazione logica
od aritmetica ad un solo operando, come la complementazione od uno scorrimento (divisione o
moltiplicazione per 2). Il secondo gruppo di ingressi, sempre da 16 bit, viene dal registro dati DR.

Tutti i registri sono costituiti da flip-flop del tipo master/slave.

Set di istruzioni:

Le istruzioni della macchina di mano sono 25 e si dividono in 4 macro categorie:

1. Istruzioni aritmetiche, logiche e di scorrimento.


2. Istruzioni per spostare informazioni dai registri e la memoria e viceversa.
3. Istruzioni per dirigere l’esecuzione del calcolo e verificarne lo stato.
4. Istruzioni per l’ingresso e l’uscita delle informazioni.
Le istruzioni del terzo tipo sono assolutamente necessarie per poter prendere decisionialternative
in funzione del valore di un parametro o del confronto di due parametri. Le istruzioni di
“alternativa” (branch) servono a guidare l’elaborazione seguendo una precisastrategia. Senza
questo tipo di istruzioni, per esempio, non si possono programmare cicli di elaborazione.

Le istruzioni di ingresso/uscita garantiscono i collegamenti tra l’utente e la macchina. Solo


attraverso queste istruzioni il programma può essere inserito in memoria ed i risultati resi noti
all’utente.

Temporizzazione e logica di controllo (I):

La sincronizzazione di tutti i registri ed i flip-flop, sia della parte operativa, che di quella di controllo
è effettuata dal segnale di orologio generato da un unico oscillatore.

Di seguito è riportato lo schema di controllo del computer:


Una istruzione appena prelevata dalla memoria viene caricata nel registro istruzione (IR) che è
diviso in tre parti: Il bit 15 viene trasferiti nel flip-flop I, i bit 12, 13 e 14 (opcode) selezionano una
delle 8 uscite di un decoder. L’attivazione della linea D7 contraddistingue le istruzioni che non
sono relative alla memoria; l’attivazione di una qualsiasi delle altre D0, ….D6 indica una istruzione
del tipo memory-reference.

Alla logica di controllo vanno anche le 16 uscite di una decodifica a quattro linee di ingresso che
opera sul contenuto di un “contatore di sequenza” sincrono con un ingresso di “clear” sincrono
ed uno di “incremento”.

La prima transizione attiva del clock dopo che è stato reso inattivo il segnale di “clear” del
contatore di sequenza, trova il contenuto del contatore a 0 0 0 0 e, pertanto, per l’intero periodo
del segnale di cadenza risulterà attiva l’uscita T0 del decoder. Alla successiva transizione il
contatore andrà a 0 0 0 1 e sarà attiva l’uscita T1 e così successivamente quella T2 e poi quella
T3 e poi, ancora, T4, ma, se durante quest’ultimo periodo di clock viene attivato l’ingresso di
controllo di “clear” del contatore, la successiva uscita attiva non sarà T5 ma di nuovo T0. ed il
ciclo ricomincia per arrestarsi al nuovo segnale di CLR del contatore.

Questo permette di temporizzare le operazioni. Nel nostro computer si assume che i cicli di
memoria sono di durata inferiore al periodo di clock, così da far calzare le operazioni in modo
corretto. Per ogni tempo T possono ovviamente avvenire più operazioni, come si vedrà tra poco.

Cicli di istruzione:

Un programma residente nella memoria di un computer è costituito da una sequenza di istruzioni.


Nel computer elementare che stiamo analizzando, ciascun ciclo è composto dalle seguenti fasi:

1. Prelievo di una istruzione dalla memoria.


2. Decodifica l’istruzione.
3. Lettura l’indirizzo vero dalla memoria, se l’istruzione usa un indirizzo indiretto.
4. Esecuzione dell’istruzione.

Completato il passo 4, il controllo ritorna al punto 1 per prelevare, decodificare ed eseguire


laprossima istruzione. Questo processo continua indefinitamente fino a quando nel programma
non viene incontrata una istruzione di HALT.

La prima operazione che viene eseguita è quella di caricare nel PC l’indirizzo della prima
istruzione del programma. Il contatore di sequenza viene azzerato e, questo, sappiamo che
genererà un segnale di timing T0. Dopo ciascun impulso di clock SC è incrementato di una unità
e questo produce una sequenza ordinata di segnali temporali T0, T1, T2, .. e così via. Le
μoperazioni per le fasi di prelelievo e decodifica (fetch and decode) possono essere specificate
dalla seguente sequenza di μoperazioni:
Start : Il Sequence Counter viene azzerato, può cominciare il nuovo ciclo d’istruzione;

T0: Nel PC è presente l’indirizzo della prima istruzione del programma da eseguire, questo viene
immesso nell’AR per andarlo a prelevare successivamente dalla memoria;

T1: Si va alla locazione contenuta in AR nella memoria per prelevare l’ istruzione, che viene
immessa nell’IR per essere decodificata successivamente;

T2: Vengono presi i bit 12,13,14 dell’IR per decodificare il codice operativo e capire di che tipo di
istruzione si tratta (memoria, i/o oppure registri); viene decodificato il bit più significativo
trasferendolo nel flip-flop I (collegato alla logica di controllo) per capire il tipo di indirizzamento di
questa istruzione; infine, i 12 bit meno significatvi vengono immessi nell’AR per recuperare in
memoria le informazioni dell’effettiva operazione da effettuare.

Come anticipato, nella logica di controllo, se il bit D7 è 0 significa che l’istruzione è di tipo
memory-reference: andiamo quindi a consultare il valore immesso nel flip-flop I (bit più
significativo) per capire se l’indirizzamento è diretto oppure indiretto (praticamente, se alla
locazione di memoria da cui andiamo a leggere si trova direttamente l’informazione che ci
interessa o c’è l’indirizzo della locazione che ci interessa):

 T3: Se l’indirizzamento è diretto abbiamo trovato l’informazione che cercavamo, questa si


trova già nel registro AR; se l’indirizzamento è indiretto andiamo alla locazione in AR, ne
preleviamo il contenuto che sarà quindi l’indirizzo a cui è contenuto ciò che ci serve e lo
trasferiamo direttamente in AR.
 T4, T5, T6: In entrambi i casi si procederà ad eseguire l’istruzione relativa alla memoria
(che può impiegare fino a 3 tempi) e si procederà ad inviare un segnale di CLR al SC per
cominciare un nuovo ciclo d’istruzione.
Se il bit D7 è 1 significa che l’istruzione è di tipo input/output register oppure di tipo register; come
anticipato in precedenza, per capire se si tratta dell’una o dell’altra si va a controllare il bit più
significativo che contraddistingue i due tipi di istruzioni (1 I/O, 0 register):

 T3: A seconda del tipo di istruzione si procede ad eseguirla e ad azzerare il SC per


predisporre un nuovo ciclo di istruzione.

Si noti che ad ogni periodo di clock (in ogni “T”), alla fine, vi è sempre un incremento di
SC <- SC + 1 che permette di passare al T+1.

Le fasi T0,T1,T2 prendono il nome di fetch/decode.

Istruzioni relative alla memoria:

Questo gruppo di istruzioni, come abbiamo già visto, non si esauriscono col tempo T3 ma, anzi,
cominciano l’esecuzione al tempo T4 e, talvolta, utilizzano anche il periodo di clock successivo T5
ed in un caso anche T6.

Ciò è dovuto al fatto che per queste istruzioni è necessario prelevare in memoria uno degli
operandi per trasferirlo in un registro prima di eseguire l’operazione richiesta.

L’istruzione di “trasferimento” tipica è BUN che significa: Branch Unconditionally. Manda in


esecuzione l’istruzione indicata dal suo “indirizzo vero”. La corrispondente microperazione è:
D4 T4: PC <- AR, SC <- 0

L’istruzione BSA che è la sigla mnemonica dell’istruzione Branch and Save Return Address è
l’istruzione che consente di inserire nel programma un sottoprogramma che esegue una specifica
operazione complessa. Questi sottoprogrammi si dicono spesso “subrutine” o “procedure”.
L’esecuzione di questa istruzione deposita in memoria l’indirizzo della prossima istruzione, che è
disponibile nel PC, in una locazione di memoria specificata dall’indirizzo vero dell’istruzione. Nel
PC viene, poi, inserito lo stesso indirizzo vero, incrementato di una unità. In sintesi:
D5 T4: M[AR] <- PC, AR <- AR + 1
D5 T5: PC <- AR, SC <- 0
Sopra è riportato un esempio di cosa sucede quando si utilizzano le istruzioni BUN/BSA.

Mi trovo all’istruzione 20 e trovo BSA con indirizzamento diretto, l’argomento di tale istruzione è
l’indirizzo 135, ciò che faccio è salvare il prossimo indirizzo a cui mi trovo ora (21) nella locazione
specificata nell’istruzione (135), dopodichè passo alla locazione 136 per eseguire il flusso di
istruzioni della subroutine ed alla fine troverò un istruzione BUN con argomento 135 e
indirizzamento indiretto; ciò significa che mi recherò nella locazione 135, preleverò il suo
contenuto che sarà a sua volta un indirizzo (21) che si procederà ad inserire in PC per
ripristinare il flusso normale del programma “principale”.

Un’altra istruzione interessante è: ISZ che è la contrazione di Increment and Skip if Zero.
L’istruzione si usa memorizzando un numero negativo (in complemento a 2) in una locazione di
memoria, si incrementa di una unità la parola specificata dall’indirizzo vero e se dopo l’incremento
essa risulta 0, non viene eseguita la prossima istruzione. Dopo il prescritto numero di cicli,
l’iscruzione seguente, che rimandava il processore ad eseguire il ciclo viene saltata e
l’elaborazione riprende da quella successiva.
D6 T4: DR <- M[AR]
D6 T5: DR <- DR + 1
D6 T6: M[AR] <- DR, if (DR =0) then (PC <- PC + 1), SC <- 0

Di seguito viene riportato uno schema riassuntivo:


(*La seconda istruzione non è AND ma ADD).

Istruzioni relative ai registri:

Queste operazioni riescono ad eseguirsi tutte entro il periodo T3.

r = D7 I* T3 è la “selezione a coincidenza” che permette di identificare questo tipo di operazione,


infatti quando D7=1,I=0 e siamo nel tempo T3 si può trattare solo di una istruzione relativa ai
registri.

Bi = IR(i) rappresenta la decodifica dell’operazione dell’istruzione che viene specificata ai 12 bit


meno significativi dell’istruzione. Esempio, come si può notare dallo schema, se volessimo
costruire l’indirizzo dell’istruzione CLA sareppe il seguente: 0 111 10000000000 ; infatti I=0, il
codice operativo è 111 e CLA corrisponde a B11 = IR(100000000000), cioè B11 significa bit 11
alto e gli altri bassi.
Queste istruzioni finiscono di operare a tempo T3 perchè non hanno bisogno di recuperare
nessun’altra istruzione da altri registri, come ad esempio può avvenire nelle istruzioni relative alla
memoria.

HTL setta ad 1 un flip-flop di nome S che blocca l’incremento del SC.

Configurazione di ingresso/uscita:

Come abbiamo già detto il sistema comunica con l’esterno attraverso idue registri INPR ed OUTR
che comunicano attraverso due “interfacce seriali “ rispettivamente con una tastiera ed una
stampante. I due registri comunicano invece in parallelo con l’Accumulatore all’interno del
sistema. L’AC ha 16 bit, i registri utilizzano gli 8 bit meno significativi.

Si definisce genericamente “interfaccia” un circuito che assicura la compatibilità logica tra due
sistemi. L’interfaccia si fa carico di tutti i problemi di interconnessione, da quelli di filosofia
strutturale a quelli di compatibilità elettrica. In tempi ormai remoti, quando i livelli di alimentazione
elettrica dei circuiti erano spesso diversi l’interfaccia doveva perfino adattare le codifiche elettriche
dei due simboli booleani.

Il flip-flop FGI svolge la funzione di “flag” (bandiera). Il suo passaggio ad “1” significa che il dato è
pronto e può cominciare il trasferimento seriale. Dopo che FGI è stato “attivato” il contenuto del
registro non può più essere cambiato fino a quando non verà “azzerato” dalla esecuzione della
istruzione INP (paragrafo successivo). Il reset di FGI è il segno che può partire il successivo
trasferimento. L’interfaccia tra OUTR e la stampante funziona in maniera perfettamente
speculare.
Il ragionamento per le condizioni che identificano che l’istruzione è input/output, specificato in p, è
praticamente analogo al ragionamento fatto per il paragrafo delle istruzioni di tipo register.

Istruzioni SKI/SKO: vanno a controllare lo stato logico della corrispondente “flag” se essa è ad 1,
il dato in ingresso od in uscita è pronto ed allora si salta la prossima istruzione e si va ad eseguire
la successiva che, per esempio potrebbe essere una operazione di registrazione in memoria del
byte. L’operazione saltata è, di solito, una operazione di “trasferimento” che rimanda il processore
a controllare di nuovo lo stato della “flag”.

Il difetto di questi trasferimenti programmati è che finché il dato atteso non arriva il processore è
bloccato ad eseguire “un ciclo di attesa”(loop). Esiste una diversa modalità di ingresso/uscita dei
dati dal sistema che non costringe il processore ad una continua improduttiva attesa. Questa
procedura utilizza le istruzioni ION ed IOF.

Interrupt di programma:

In questo caso il sistema è normalmente impegnato ad eseguire un programma nel quale non è
inserita nessuna istruzione di controllo sulle “flag”. Il sistema è dotato, però, di un circuito (si tratta
di qualcosa di fisico) che avverte automaticamente il processore quando una flag è “attivata”, il
che significa che un dato è pronto per essere acquisito o trasmesso. In questo caso il processore
interrompe l’esecuzione del programma per effettuare l’operazione di I/O, per poi riprendere
l’elaborazione esattamente dal punto di interruzione.

Le istruzioni ION ed IOF non fanno altro che attivare/disattivare un flip-flop che si chiama IEN
(Interrupt Enable) che se è attivo permette di fermare l’elaborazione del programma per spostarsi
sui canali di input, ad esempio.

Nella CPU esiste anche un flip-flop che prendo il nome di R (Request) che se attivo procederà, al
prossimo ciclo di istruzione, ad effettuare il processo di interrupt.

Tale processo lo si può riassumere attraverso il seguente flow-chart:

Il ciclo di interruzione del programma non è altro che una implementazione hardware delle
operazioni connesse all’istruzione di BSA (Branch and Save return Address). L’indirizzo di ritorno
che non è altro che l’indirizzo della prossima istruzione del programma che era in esecuzione e
che è disponibile nel PC. Questo indirizzo deve essere salvato in un registro od in una locazione
di memoria per essere ripreso al momento opportuno.

Le CPU più sofisticate hanno apposite strutture di registri per questa esigenza, ma, per semplicità
supporremo che la locazione della memoria all’indirizzo 0 sia destinata ad ospitare l’indirizzo di
ritorno dopo l’interruzione. Dopo questa operazione il controllo manda in esecuzione l’istruzione
che è stata preventivamente registrata all’indirizzo 1 della memoria, scrivendo 1 nel PC ed azzera
i flip-flop IEN ed R, in modo che non ci possa essere nessuna altra interruzione finché quella
accettata non sia terminata. Un esempio che mostra cosa accade durante un ciclo di interruzione
è graficamente riportato di seguito:

L’azione mostrata comincia con l’attivazione ad 1 di R, mentre il processore sta eseguendo


l’istruzione che si trova alla locazione 255 ed il PC punta alla successiva istruzione all’indirizzo
256 della memoria. Il programmatore ha preventivamente registrato in memoria, a partire dalla
locazione 1120, un programma per gestire il collegamento con i periferici, ed ha registrato alla
locazione di indirizzo 1 una istruzione di “Branch Unconditionally” (BUN) alla locazione 1120.
Quando il controllo, durante l’intervallo di tempo T0, trova R = 1, avvia il ciclo di interruzione. Il
contenuto del PC (256) viene memorizzato alla locazione 0. Nel PC viene scritto 1 ed R viene
azzerato. L’esecuzione dell’istruzione di BUN porta in esecuzione il programma di I/O che andrà
per prima cosa a leggere le “flag” d’ingresso (FGI) e d’uscita (FGO) ed a trasferire i dati da INPR
ad AC e, poi, in memoria o, viceversa, dalla memoria all’AC e da questo all’OUTR. Il programma
di I/O terminerà con la scrittura di 1 nell’IEN per riabilitare l’interrupt ed una istruzione di BUN
indiretto, IR(15) = 1, alla locazione 0 che riporterà nel PC l’indirizzo 256.

Ciclo di interrupt:

Il ciclo comincia se IEN=1 ed il flip-flop R è stato attivato durante la fase di esecuzione di una
istruzione precedente; questo implica che non è possibile seguire l’operazione R <- 1 durante le
fasi di fetch/decode; per essere formali potremmo scrivere che:
T0* T1* T2* (IEN) (FGI + FGO): R <- 1
Il controllo più completo che si possa effettuare per impedire il set della flag R ad 1 durante le fasi
di fetch/decode è identificabile attraverso la condizione: R* T0, R* T1, e R* T2.

Dunque, un ciclo di interrupt si compone delle seguenti operazioni in 3 distinti periodi:

R T0: AR <- 0, TR <- PC


R T1: M[AR] <- TR, PC <- 0
R T2: PC <- PC + 1, IEN <- 0, R <- 0, SC <- 0

T0: Salvo in AR l’indirizzo 0 e il l’istruzione successiva a quella che stò eseguendo in TR (registro
temporaneo).

T1: Mi reco all’indirizzo 0 e salvo l’indirizzo della prossima istruzione che avrei dovuto eseguire da
“programma”, successivamente azzero il PC.

T2: Mi posiziono sulla prossima istruzione (indirizzo 1) , setto a 0 IEN, R (perchè sto eseguendo
l’interrupt, al termine quindi potrò eseguire un altra) e SC (in modo tale da eseguire il ciclo di
istruzione per eseguire le istruzioni specificate nell’interrupt).

Polling:

In alternativa al meccanismo di INTERRUPT il programmatore può scegliere una diversa modalità


di gestione dell’I/O meno efficiente ma altrettanto valida; questa consiste nell’eseguire
normalmente i compiti della Macchina e di tanto in tanto verificare se uno dei canali di
comunicazione Input o Output o entrambe non sia pronto a ricevere o trasmettere un dato.
Questa strategia, detta di polling si può realizzare chiamando ad intervalli di tempo opportuni una
routine, che è riportata nella sezione dei programmi nel paragrafo finale. In tal caso non bisogna
riabilitare l’interrupt prima di uscire, perché si è in un regime in cui l’interrupt è disabilitato.

Descrizione globale della macchina di mano:

E’ possibile tracciare un flow-chart finale che riassume l’intero funzionamento di un ciclo di


istruzioni nella macchina di mano:
Tutte le istruzioni (D7 I T3, D7 I* T3, D7* I T3, D7* I* T3) sono riassunte nello schema di massima
delle funzioni offerte dalla macchina di mano, divise per macrotipologia:

Infine, i componenti hardware del sistema sono descritti di seguito:

1. Una unità di memoria da 4096 parole da 16 bit.


2. Nove registri: AR, PC, DR, AC, IR, TR, OUTR, INPR, ed SC.
3. Sette flip-flop: I, S, E, R, IEN, FGI ed FGO.
4. Due decodifiche, una 3x8 per la decodifica del codice operativo ed una 4x16 per il timing.
5. Un bus a 16 linee dati.
6. La logica combinatoria di controllo
7. Un sommatore ed i circuiti logici per gestire gli ingressi nell’AC.
Logica di controllo (II):

Adesso è possibile specificare al meglio la logica di controllo, in questa nuova immagine sono
stati specificati gli “altri ingressi” nell’immagine precedente.

Essi sono, il contenuto dei 16 bit dell’accumulatore per stabilire se AC = 0 ed il bit segno dello
stesso AC(15), i 16 bit del registro DR per stabilire se DR = 0 e lo stato degli altri 6 flip-flop del
sistema, visto che il settimo, I era già in ingresso alla logica di controllo.

Le uscite che la rete combinatoria di controllo deve produrre sono:


1. I segnali di controllo dei nove registri.
2. I segnali di Read e Write della memoria.
3. I segnali per attivare, azzerare o complementare i sette flip-flop.
4. I segnali S2 S1 S0 per la selezione dei registri sul bus.
5. I segnali necessari per gestire la ALU ed i circuiti annessi

Rete di controllo di AR:

Per la maggior parte dei registri presenti nella CPU è anche possibile specificare quando è
possibile abilitare i 3 ingressi LD, CLR, INC; se si osserva la tabella si noterà che tutte le
operazioni che riguardano l’accumulatore sono le seguenti:

R* T0: AR <- PC
R* T2: AR <- IR(0-11)
D7* I T3: AR <- M[AR]
R T0: AR <- 0
D5 T4: AR <- AR + 1

Allora possiamo ricavare le equazioni booleane che descrivono i 3 ingressi di abilitazione:

LD(AR) = R* T0 + R* T2 + D7* I T3
CLR(AR) = R T0
INR(AR) = D5 T4

Progettare la rete combinatoria relativa è semplice adesso:


Rete di controllo dei flip-flop (Flags):

Si fa l’esempio del solo flip-flop IEN; cercando le istruzioni relative si ottengono le seguenti
equazioni booleane:

p B7: IEN <- 1


p B6: IEN <- 0

Dove p = D7 I T3 e B7 e B6 sono i bit 7 e 6 dell’IR rispettivamente.

Inoltre alla fine del ciclo di “interrupt” IEN viene azzerato.

R T2: IEN <- 0

Se si usa un flip-flop J/K la logica di controllo si presenta come in figura:

Logica di controllo di AC:


Per ricavare il circuito combinatorio si procede sempre a ricavare le equazioni booleane che
coinvolgono l’AC come fatto per le altre logiche di controllo.

Alcuni programmi utili per la macchina di mano:

Addizione (SX) e sottrazione (DX) tra due numeri:

Esempio ciclo FOR:

Passaggio parametri che richiama la subroutine (DX):


Routine di Interrupt:

Routine di Polling:
Memoria Cache
Introduzione:

La memoria cache si interpone tra la CPU e la memoria centrale per velocizzare le operazioni.
L’esigenza nasce da una proprietà denominata località dei riferimenti: all’interno di un
programma ci sono un insieme di istruzioni che vengono ripetute ciclicamente in un determinato
periodo. Tale proprietà si manifesta più specificatamente quando è una sola l’istruzione che,
eseguita di recente, venga eseguita nuovamente in breve tempo (località temporale), oppure
quando istruzioni vicine ad un istruzione eseguita recentemente siano anch’esse eseguite nel
prossimo futuro (località spaziale).

L’utilizzo di una cache permetterebbe di velocizzare di molto i trasferimenti tra la memoria


centrale e la CPU perchè la maggior parte delle operazioni richieste dalla CPU sarebbero già
caricate in cache e trasferite con un tempo molto minore (infatti la cache è una memoria molto più
piccola rispetto a quella centrale, e proprio per questo garantisce una velocità superiore).

La località temporale e quella spaziale suggeriscono diversi modi su come si potrebbe progettare
una cache; la prima suggerisce di trasferire all’interno solo le istruzioni più richieste, la seconda di
trasferire un intero blocco di istruzioni adiacenti a quelle richieste spesso.

La corrispondenza tra i blocchi della memoria principale e quelli della cache è specificata
mediante un'apposita funzione di posizionamento (mapping). Quando la cache è piena e si fa
riferimento a una parola di memoria (istruzione o dato) che non è presente nella cache,
l'hardware di controllo della cache deve decidere quale blocco della cache debba essere rimosso
per far spazio al nuovo blocco che contiene la parola a cui si fa riferimento. L’insieme di regole in
base alle quali viene fatta questa scelta costituisce l'algoritmo di sostituzione.

La logica di controllo della cache si fa carico di determinare se la parola richiesta è presente o


meno nella cache. Se è presente, viene effettuata l'operazione di lettura o scrittura della locazione
di memoria appropriata. In questo caso si dice che l'accesso in lettura o in scrittura ha avuto
successo (read hit o write hit). Nel caso di un'operazione di lettura, la memoria principale non
viene coinvolta, mentre per un'operazione di scrittura il sistema può procedere in due modi. Nella
prima tecnica, chiamata write-through, la locazione della cache e quella della memoria principale
vengono aggiornate contemporaneamente. La seconda tecnica consiste nell'aggiornare soltanto
la locazione della memoria cache, segnandola come aggiornata rispetto alla memoria principale
con un apposito bit, chiamato spesso bit di modifica o dirty. In questo caso, la locazione della
memoria principale viene aggiornata in seguito quando il blocco contenente la parola marcata
deve essere rimosso dalla memoria cache per far posto a un nuovo blocco. Tale tecnica viene
chiamata spesso write-back, o copy back.

Il protocollo write-through è più semplice, ma implica inutili operazioni di scrittura nella memoria
principale quando una parola viene aggiornata più volte durante il periodo in cui risiede nella
cache. Si noti, però, che anche il protocollo write-back può causare inutili scritture nella memoria
principale, visto che, quando si procede con la scrittura nella memoria principale di un blocco,
tutte le parole del blocco vengono scritte, anche se solo una delle parole del blocco della cache, è
stata modificata. Quando la parola indirizzata durante un'operazione di lettura non è presente
nella cache si dice che l'accesso in lettura è fallito (read miss). Il blocco di parole contenente la
parola richiesta viene copiato dalla memoria principale nella memoria cache. Dopo aver caricato
l'intero blocco nella memoria cache, la parola richiesta viene inviata alla CPU. In alternativa, è
possibile inviare immediatamente la parola alla CPU, non appena la si legge dalla memoria
principale. Quest'ultimo approccio, chiamato load-through, o anche early restart, riduce in
qualche modo il tempo di attesa della CPU, a discapito di una maggiore complessità del circuito di
controllo.

Durante un'operazione di scrittura, se la parola indirizzata non è nella cache si dice che l'accesso
in scrittura è fallito (write miss). Quindi, se si utilizza un protocollo write-through, le informazioni
vengono scritte direttamente nella memoria principale, nel caso invece di un protocollo write-back,
il blocco contenente la parola indirizzata viene prima caricato nella cache, poi viene soprascritto
con le nuove informazioni.

Indirizzamento diretto:

E’ una tecnica di mapping tra la memoria centrale e la mamoria cache:

Si consideri una memoria cache costituita da 128 blocchi contenenti 16 locazioni di memoria.
Si consideri una memoria centrale che abbia una capacità di 64K locazioni di memoria.

Con tale tecnica si immagini di suddividere la memoria centrale in 4K blocchi da 16 locazioni


ciascuno. Ora bisogna associare i blocchi della memoria cache a quelli della memoria centrale, e
si procede in questo modo:

Al blocco 0 della cache si associano i seguenti blocchi della memoria centrale: 0, 128, 256, ...,
3967
Al blocco 1 della cache si associano i seguenti blocchi della memoria centrale: 1, 129, 257, ...,
3968
..........
Al blocco i-simo della cache si associano i seguenti blocchi della memoria centrale: i+n128, dove
n=0, ..., 32
Così facendo si coprono tutte e 64K locazioni della memoria centrale (4K blocchi da 16 locazioni).
In questa tecnica ogni blocco della memoria centrale è predestinato ad un determinato blocco
della cache.

Dunque, la memoria cache ha 128 blocchi contenenti 16 locazioni, quindi in totale contiene 2048
locazioni, sarà quindi composta di indirizzi da 11 bit. La memoria centrale contiene 64K locazioni,
quindi gli indirizzi saranno da 16 bit.

Gli indirizzi presenti in memoria centrale sono suddivisi in 3 parti che identificano una specifica
funzione: i 5 bit più significativi (detti tag, sono dei “contenitori” di blocchi) sono il valore
dell’indice n che stabilisce quale dei 32 blocchi di memoria associabili ad un certo blocco della
cache è effettivamente presente nella stessa, i 7 bit centrali identificano in quale blocco della
cache è associato il blocco della memoria centrale considerato, infine i 4 bit servono ad indicare
in quale delle 16 locazioni si trova l’informazione da prelevare.

Comunque, come indicato dall’immagine stessa, attraverso queste semplici formula è possibile
ricavarsi tutte le informazioni desiderate:

In quale blocco della cache si troverebbe un blocco della RAM: MOD(bloccoRAM, 128)
Calcolare il tag dato un blocco nella cache e nella RAM: int[(bloccoRAM - bloccoCache)/128]

Una possibile implementazione di una logica di controllo sull’indirizzo che utilizza dei BUS per i
collegamenti è il seguente:

Ovviamente un blocco della cache corrisponde a più blocchi nella memoria centrale, questo
potrebbe dar luogo a collisioni quando si tenta di occupare lo stesso blocco in cache da più
blocchi nella RAM; tali collisioni vengono risolte da algoritmi di sostituzione, che in questo caso
risulta banale: i dati nel blocco vengono sovrascritti con i dati nel nuovo blocco, dato che
l’associazione tra blocchi è data da una formula matematica la posizione del nuovo blocco può
essere soltanto una.

Uno schema a blocchi di una memoria cache ad indirizzamento diretto è mostrato nella figura:
Indirizzamento associativo:

Esiste un modo molto più flessibile di posizionamento, in cui un blocco della memoria principale
può essere posizionato in un qualsiasi punto della cache.

In questo caso sono necessari 12 bit di etichetta per identificare uno dei 4096 blocchi della
memoria principale quando questo risiede nella cache. I bit di etichetta di un indirizzo provenienti
dalla CPU sono confrontati con l'etichetta di ogni blocco della memoria cache per vedere se il
blocco cercato è presente. Si tratta della cosiddetta tecnica di indirizzamento completamente
associativo; essa consente la massima libertà nella scelta della locazione della cache in cui
posizionare il blocco di memoria, quindi lo spazio della cache può essere utilizzato in modo molto
più efficiente.

Un nuovo blocco che deve essere copiato nella cache ne fa uscire un altro già residente solo se
la cache è già piena. In tal caso, è però necessario utilizzare un algoritmo per selezionare il
blocco che deve essere sostituito. Come discuteremopiù avanti, ci sono numerosi algoritmi di
sostituzione che si possono usare.

Il costo di una memoria cache completamente associativa è maggiore rispetto a quello di una
cache a indirizzamento diretto, poiché nel caso numerico proposto è necessario disporre di ben
128 comparatori per determinare la presenza o meno di un blocco in memoria. Con un numero
elevato di confronti da effettuare è sicuramente preferibile avere più segmenti di bus in parallelo
per ridurre i tempi di propagazione sulle linee. Una ricerca di questo tipo si chiama ricerca
associativa o per contenuto, in quanto corrisponde all’operazione che si fa quando si vuole
sapere se un oggetto od un cognome sono presenti in un elenco. Se si adoperasse una logica
seriale, il tempo di ricerca sarebbe moltiplicato per il numero di confronti da effettuare e ciò
porterebbe a tempi di accesso inammissibili.

Le cache di questo tipo si chiamano anche “memorie indirizzabili per contenuto” ed infatti sono in
gergo dette C.A.M. (Content Addressable Memory). Sono ormai disponibili anche come
componenti di sistemi non di calcolo.

Di seguito due realizzazioni, uno con CAM ed uno senza:

Indirizzamento set-associativo:

E’ anche possibile utilizzare una combinazione delle due tecniche di indirizzamento analizzate. I
blocchi della cache sono raggruppati in insiemi (set), ed il meccanismo di associazione è
congegnato in modo che ciascun blocco della memoria principale è associato ad un particolare
insieme della cache ma può risiedere in una qualsiasi posizione all’interno di esso.
Per sottolineare la parentela con le due tecniche basilari, il meccanismo di indirizzamento che
stiamo per illustrare è chiamato set-associativo: Avere più possibilità di posizionamento di un
blocco in un insieme riduce la possibilità di dover attivare meccanismi di sostituzione di blocchi
nella cache, anche quando essa è non è completa, e riduce il numero di etichette tra cui
effettuare la ricerca associativa.

Rimanendo agganciati ai termini numerici degli esempi precedenti, con una cache da 2048
parole, suddivisa in 128 blocchi, da 16 locazioni ciascuna, ed una memoria principale di 64k
locazioni, se si sceglie un insieme di 4 blocchi per insieme, si hanno 32 insiemi nella cache ed i
soliti 4096 blocchi nella memoria principale, individuabili attraverso i 12 bit più significativi di
indirizzo comuni alle 16 parole. Ad ogni insieme della cache corrispondono, allora, 128 blocchi
della memoria principale ma solo fino ad un massimo di quattro di essi possono trovare
effettivamente posto nella cache.

In questo caso, i 128 blocchi della memoria 0, 32, 64, 96, 128, ..., 4064 corrispondono all'insieme
0 della cache, e possono occupare una qualsiasi delle quattro posizioni dei blocchi all'interno
dell'insieme. I blocchi 1, 33, 65, 97, 129, 4065, sono associati all’insieme 1 della cache e così via
per gli insiemi 2, 3 4 e fino a quello 31. Quando un blocco viene caricato nella cache, i 5 bit meno
significativi dei 12 bit d’indirizzo individuano l’insieme della cache dove esso deve essere
posizionato; se c’è un blocco vuoto. I successivi 7 bit più significativi dell’indirizzo vengono
trascritti nel registro associato al blocco nella cache e le 16 parole di programma memorizzate
nelle locazioni.

Se per esempio si vuole trasferire il blocco 2323 della memoria, il suo indirizzo è:1001000 10011
XXXX. Esso andrà nell’insieme 19 della cache con l’etichetta 72.
La condizione limite, di 128 blocchi per insieme, non richiede alcun bit per il campo set e
corrisponde alla tecnica completamente associativa, con 12 bit di etichetta. L'altra condizione
limite è costituita dalla presenza di un blocco per insieme, che corrisponde alla cache a
indirizzamento diretto. Un ulteriore bit di controllo, chiamato bit di validità, è necessario per ogni
blocco. Questo bit indica se il blocco contiene o meno dati validi. Non deve però essere confuso
con il bit di modifica, menzionato in precedenza.

I bit di validità vengono tutti posti a 0 nell'istante iniziale di accensione del sistema e, in seguito,
ogni volta che nella memoria principale vengono caricati programmi e dati nuovi dal disco. Il bit di
validità di un certo blocco della cache viene posto a 1 la prima volta che il blocco viene caricato
dalla memoria principale; poi, ogni volta che un blocco della memoria principale viene aggiornato
con codice sorgente che non è passato attraverso la cache, viene effettuato un controllo per
determinare se il blocco che sta per essere caricato sia presente o meno nella cache. Se lo è, il
suo bit di validità viene posto a 0; in tal modo, si garantisce che nella cache non ci siano dati
obsoleti.

I trasferimenti dal disco alla memoria principale vengono effettuati mediante un meccanismo di
DMA (Direct Memory Access). Normalmente, questi programmi e dati nuovi non passano dalla
memoria cache per motivi sia di costo sia di prestazioni.

Lo stesso schema di associazione iniziale viene proposto nel caso realistico in cui i quattro
insiemi della cache sono realizzati con quattro moduli distinti; questo consente l’accesso in
parallelo ai 4 moduli:
Algoritmi di sostituzione:

In una cache ad indirizzamento diretto, la posizione di ogni blocco è predefinita, quindi non esiste
alcuna strategia di sostituzione. Nelle memorie cache associative e set-associative esiste invece
una certa flessibilità. Quando un nuovo blocco deve essere portato nella cache, e tutte le
posizioni che potrebbe occupare contengono dati validi, il controllore della cache deve decidere
quale blocco, tra quelli vecchi, soprascrivere. Questa è una decisione importante, perché questa
scelta potrebbe essere un fattore fortemente determinante per le prestazioni del sistema. In
generale, l'obiettivo è quello di mantenere nella cache quei blocchi che hanno una maggior
possibilità di essere nuovamente utilizzati nel prossimo futuro. Tuttavia, non è facile determinare i
blocchi a cui si farà riferimento.

Quando bisogna eliminare dalla cache un blocco, è sensato soprascrivere quello a cui non si
accede da più tempo. Tale blocco prende il nome di blocco utilizzato meno di recente (Least
Recently Used, LRU), e la tecnica si chiama algoritmo di sostituzione LRU. Per utilizzare
l'algoritmo LRU, il controllore della cache deve mantenere traccia di tutti gli accessi ai blocchi
mentre l'elaborazione prosegue.

Quando si ha un successo nell'accesso al blocco (hit), il contatore di quel blocco viene posto a 0.
I contatori con i valori originariamente inferiori a quelli del blocco a cui si accede vengono
incrementati di uno, mentre tutti gli altri rimangono invariati. Quando invece l'accesso fallisce
(miss) e l'insieme non è pieno, il contatore associato al nuovo blocco caricato dalla memoria
principale viene posto a 0 e il valore di tutti gli altri contatori viene incrementato di l. Quando
invece l'accesso fallisce e l'insieme è pieno, si rimuove il blocco il cui contatore ha valore 3 e si
pone il nuovo blocco al suo posto, mettendo il contatore a 0. Gli altri tre contatori dell'insieme
vengono incrementati di un'unità.

Le prestazioni dell'algoritmo LRU possono essere migliorate introducendo una piccola dose di
casualità nella scelta del blocco da sostituire. Sono stati proposti molti altri algoritmi di
sostituzione più o meno complessi, che richiedono talvolta anche notevoli complicazioni
hardware, ma l’algoritmo più semplice, e spesso anche piuttosto efficace, consiste nello scegliere
in modo completamente casuale il blocco da sostituire.

Interlacciamento:

Un miglioramento dell’organizzazione della memoria sta nell’interlacciamento; attraverso questa


tecnica si ha una facilità maggiore nell’accedere ai dati e quindi si guadagna molto più tempo:

Si può, inoltre, garantire un accesso in parallelo se la memoria RAM è suddivisa in moduli, con
l’interlacciamento si raggiunge una velocità ancora superiore:
Si osservino le seguenti immagini:

Nel primo caso, l'indirizzo di memoria generato dalla CPU viene decodificato come nella Figura
(prima figura relativa al paragrafo). I k bit più significativi indicano uno degli n moduli, e gli m bit
meno significativi indicano una particolare parola all'interno del modulo. Quando si accede a
locazioni consecutive, come accade quando si copia un blocco di dati nella cache, viene coinvolto
soltanto un modulo. Nello stesso tempo, tuttavia, dispositivi con possibilità di accesso diretto alla
memoria (DMA) possono aver accesso alle informazioni contenute in altri moduli della memoria.
Il secondo e più efficiente modo di indirizzare i moduli, mostrato nella figura iniziale del paragrafo,
è chiamato interallacciamento della memoria. I k bit meno significativi dell'indirizzo di memoria
selezionano un modulo, mentre gli m bit più significativi indicano una locazione all'interno del
modulo. In questo modo, indirizzi consecutivi sono posizionati in moduli successivi; così facendo,
ogni componente del sistema che faccia richiesta di accesso a locazioni di memoria consecutive
può tenere occupati vari moduli in un qualsiasi istante. Ciò consente di ottenere sia accessi a un
blocco di dati più veloci, sia una più elevata media complessiva di utilizzo della memoria. Per
realizzare la struttura interallacciata, devono esserci 2^k moduli. In caso contrario, ci sono degli
stati vuoti associati a locazioni inesistenti nello spazio di indirizzamento della memoria.

Frequenza di accesso e penalità di fallimento:

Frequenza di accesso: Numero di successi indicati come frazione di tutti gli accessi provati;
Frequenza di fallimento: Numero di fallimenti in rapporto al numero totale di accessi effettuati
(fallimento è inteso come un qualcosa che non ho trovato nella cache).
Penalità di fallimento: Tempo addizionale necessario per portare le informazioni desiderate
nella cache. Oppure: tempo richiesto per portare il blocco di dati desiderato da un'unità più lenta
a una più veloce nella gerarchia di memoria.

Il numero medio di cicli di clock che ci impiega una CPU per accedere ad una cache è indicato
dalla seguente formula:

t = hC + (1 - h)M

t -> Tempo medio


h -> Frequenza di accesso
C -> Tempo per accedere alla memoria cache
M -> Tempo per accedere alla memoria centrale, cioè la penalità di fallimento.

Se h è il numero di accessi alla memoria cache, tutti i restanti accessi saranno quelli alla memoria
centrale, stiamo parlando del complemento di h, cioè 1-h (tutto il resto).

Una sola cache per istruzioni e dati tendenzialmente dovrebbe avere una frequenza di successo
in qualche modo superiore, poiché offre una maggiore flessibilità nella memorizzazione di nuove
informazioni. Tuttavia, se si utilizzano cache separate, è possibile accedere contemporaneamente
a entrambe le memorie cache, aumentando così il parallelismo e, di conseguenza, le prestazioni
della CPU.

Lo svantaggio delle cache separate è che l'incremento del grado di parallelismo è accompagnato
da circuiti molto più complessi.

Poiché le dimensioni della memoria cache sul chip della CPU sono limitate da vincoli di spazio,
una buona strategia per progettare un sistema con prestazioni elevate consiste nell'utilizzare tale
cache come cache primaria. Una cache secondaria esterna, costruita con chip SRAM, viene poi
aggiunta per ottenere la capacità desiderata.

Un modo pratico di accelerare l'accesso alla cache è quello di consentire l'accesso a più di una
parola contemporaneamente, lasciando poi che la CPU ne utilizzi una per volta.

La cache secondaria può essere anche notevolmente più lenta, ma dovrebbe essere molto più
grande di quella primaria in modo tale da garantire una frequenza di successo elevata negli
accessi. La velocità di questa cache è meno critica perché influenza soltanto la penalità di
fallimento della cache primaria. Una workstation può avere una cache primaria con una capacità
di decine di kilobyte e una cache secondaria di diversi megabyte. La presenza di una cache
secondaria riduce ulteriormente l'impatto della velocità della memoria principale sulle prestazioni
del calcolatore. Il tempo medio di accesso sperimentato dalla CPU in un sistema dotato di due
livelli di cache è:

t = h1C1 + (1 – h1) h2 C2 + (1 – h1) (1- h2) M

h1 = frequenza di successo nella cache primaria;


h2 = frequenza di successo nella cache secondaria;
C1 = tempo di accesso alle informazioni nella cache primaria;
C2= tempo di accesso alle informazioni nella cache secondaria;
M = tempo di accesso alle informazioni nella memoria principale.
Memoria Virtuale
Introduzione:

Agli albori dell’informatica i programmatori dovevano progettare software prevedendo


l’ammontare di Ram richiesto e dovendo conoscere anche il quantitativo di Ram disponibile sulla
macchina che avrebbe eseguito il programma; Oggigiorno invece queste informazioni non
importano agli sviluppatori (tranne rari casi) poiché anche un computer con memoria Ram non
necessaria ad eseguire il programma può eseguirlo tramite l’utilizzo (nativo) della memoria
virtuale.

Funzionamento:

La memoria virtuale è una tecnica che consente di utilizzare la memoria del disco rigido (supporto
su cui è installato il sistema operativo) come se fosse memoria Ram, ovviamente non mancano
gli svantaggi; Se da un punto di vista è possibile eseguire software che hanno bisogno di un
quantitativo di memoria maggiore, dall’altro punto di vista c’è un calo enorme delle performance
per quanto riguarda l’accesso alla memoria (la memoria Ram oltre ad avere un accesso
privilegiato alla CPU, ha velocità di lettura/scrittura 1000 volte superiore a quelle dei tradizionali
hard disk). Gli indirizzi assegnati alla memoria virtuale, sono il continuo di quelli della memoria
centrale che è terminata, quindi quando il processore tenterà di accedere a quelle informazioni e
noterà che non si tratta di un indirizzo esistente della Ram, allora tramite opportuno algoritmo di
sostituzione. La parte di programma presente su disco verrà trasmessa tramite DMA, e verrà
prelevata in blocchi più grandi rispetto alla Ram poiché la penalità di fallimento rappresenta un
ritardo temporale ben più grande sul disco.

Memory Management Unit:

La gestione della MMU è affidata al sistema operativo e nessun programma può eccedere i limiti
dell’indirizzamento virtuale (massimo campo di indirizzamento del processore (32/64bit)), la MMU
viene utilizzato anche quando c’è spazio disponibile in memoria Ram ma ad esempio il
posizionamento degli indirizzi di un programma è incompatibile con il campo degli indirizzi del
processore. La MMU quando riceve un indirizzo virtuale(Ram) lo traduce in un indirizzo
fisico(disco) e poi lo invia alla cache, dando inizio alla ricerca della locazione:

 Se la locazione fa parte di un blocco che risiede nella cache, il contenuto viene inviato al
processore e la ricerca termina.
 Altrimenti si cerca nella memoria Ram, dove se il programma è carico interamente
l’indirizzo sarà sicuramente contenuto lì.
 Nel caso in cui il programma sia scritto anche su disco, la locazione potrebbe non trovarsi
in Ram e la pagina viene trascritta dal disco alla memoria sostituendo eventualmente una
pagina precedentemente scritta.

La MMU è una parte fisica all’interno della CPU e pertanto, una parte della Tabella della TLB è
contenuta nel chip stesso della MMU, il contenuto del registro della TLB è l’indirizzo della
corrispondente pagina fisica con alcuni bit di controllo. Al contrario della Cache l’evento miss
viene denominato page fault, ma le operazioni svolte (dal sistema operativo) sono le stesse

.
Tabella dei Numeri di Pagina:

La tabella dei numeri di pagina è una zona della memoria Ram formata da tante locazioni quante
sono le pagine virtuali, ogni tabella contiene il numero della pagina fisica corrispondente e alcuni
bit di controllo. Questa struttura dati permette di associare ad un alto numero di pagine virtuali un
ridotto numero di pagine fisiche. Il Registro base della tabella delle pagine indicizza all’inizio
della tabella. Il numero della pagina virtuale viene sommato al Registro base della tabella delle
pagine per avere l’indirizzo effettivo in cui cercare la pagina del programma. Utilizzando questo
registro è possibile avere una tabella per ogni programma in esecuzione.