Sei sulla pagina 1di 22

Università degli studi di Roma

SAPIENZA

Tesina di

Architettura di Sistemi integrati

Prof. Mauro Olivieri

Perticaroli Stefano

Patrizi Roberto

Di Liberto Alessio

Barbieri Stefano

1
2
Specifiche di base
Il processore ha una memoria interna da 32 locazioni da 32 bit ognuna numerate da 0 a 31. Le
prime 4 locazioni sono particolari, sono infatti collegate a dei piedini esterni del processore e
permettono la comunicazione tra più processori identici. Le locazioni di memoria per le
comunicazioni sono:
0 = port N
1 = port S
2 = port E
3 = port W

Il processore è in grado di eseguire istruzioni in virgola fissa con formati binari in complemento a
due. L’instruction set del μ-transputer è dotato delle seguenti istruzioni di base:
Istruzione Campi
ADD MODE DEST REG MODE OP_1 MODE OP_2
SUB MODE DEST REG MODE OP_1 MODE OP_2
MUL MODE DEST REG MODE OP_1 MODE OP_2
AND MODE DEST REG MODE R1
XOR MODE DEST REG MODE R1
Bit 31÷29 28 27÷23 22 21÷17 16 15÷11
MOV MODE DEST REG MODE R1
Bit 31÷29 28 27÷23 22 21÷17
BRANCH COND CODE TARGET MODE R1
Bit 31÷29 28 27÷19 18 17÷13
IMOV MODE DEST REG IMMEDIATE DATA
Bit 31÷29 28 27÷23 22÷13

In cui:
OP_1, OP_2 Rappresentano gli operandi delle istruzioni a 2 operandi, R1 nel caso di istruzioni con
un solo ingresso. Sono lunghi ciascuno 5bit.
DEST REG indica in quale locazione di memoria verranno posti i risultati dell’istruzione.
MODE Rappresenta il modo di indirizzamento, diretto o indiretto. Se è posto ad 1 il processore
preleva il dato da uno dei suoi 32 registri (2 5 = 32), in particolare dal registro indirizzato dai 5 bit
OP. Se è posto a 0, i 32 bit del registro OP rappresentano l’indirizzo dell’istruzione nella memoria
esterna.
Le prime 5 istruzioni a due operandi sono autoesplicative così come MOVE, che prende il
contenuto del registro R1 e lo sposta in DEST_REG. Qualche parola sulle altre 2.
BRANCH aggiorna il program counter spostandosi di un numero di locazioni pari a TARGET, un
intero di 9 bit con segno che permette di saltare in avanti di 255 posizioni oppure indietro di 256
se è verificata la condizione COND CODE su registro R1. Se COND CODE = 0 il salto si ha solo se il
registro R1 contiene tutti bit nulli, altrimenti se COND CODE = 1 il salto si ha solo se R1 è positivo
(bit 31 = 0).
IMOVE Copia un operando immediato (IMMEDIATE DATA) in un registro di destinazione (DEST REG)

3
L'instruction set è stato parzialmente modificato rispetto alle specifiche, per via dell'elevato
numero di bit ancora disponibili. Sono state aggiunte altre istruzioni e per alcune istruzioni sono
stati utilizzati più bit di quelli richiesti. Istruzioni come la imove o come il branch, utilizzano
operandi binari a 22 bit invece dei precedenti 9 o 10. Inoltre sono state aggiunte le istruzioni di
Shift, Or, Not, Bit clear, Bit set ed un codice per una No operation (NOP).
Lo shift legge il contenuto di un registro sorgente e ne trasla tutti i bit di una posizione a destra o
a sinistra in base al valore di un bit di controllo, memorizzando il risultato nel registro di
destinazione.
Il comando OR esegue l'or logico, bit a bit tra due registri, il NOT inverte tutti i bit di un
registro.
Bit clear (BCLR) e Bit set (BSET) impostano il valore di un bit rispettivamente ad 0 ed a 1. Il bit
impostabile è selezionato da un indice (5 bit) che punta ad uno tra i 32 bit del dato, numerati in
ordine crescente da sinistra verso destra.

Formato istruzioni
Conservando l'impostazione data nelle specifiche il più possibile anche con l'aggiunta delle nuove
istruzioni, risulta un formato regolare, sebbene talvolta un campo debba essere splittato in
posizioni non adiacenti, come è avvenuto ad esempio per il codice istruzioni.
Le istruzioni in totale sono 13, per cui sono richiesti 4 bit di codice a fronte dei tre previsti
inizialmente dalle specifiche. Il quarto bit è stato aggiunto perciò in decima posizione, lasciando
immutati gli altri bit come da specifiche. I codici di 4 bit per ciascuna istruzione sono elencati
nella seguente tabella:

Istruzione Opcode Istruzione

somma ADD 0000

differenza SUB 0010

prodotto MUL 0100

no operation NOP 0101

and logico AND 0110

mov MOV 0111

xor logico XOR 1000

shift SHIFT 1001

or logico OR 1010

imov IMOV 1011

bit clear BCLR 1100

4
bit set BSET 1101

branch BRANCH 1110

not logico NOT 1111

Istruzioni che richiedono gli stessi campi (fino a tre operandi, una costante oppure un offset in
cui saltare, un indice oppure qualche bit di controllo che specifica il comportamento delle
istruzioni), utilizzano gli stessi bit dell'istruzione per lo stesso scopo: ad esempio il codice
istruzione è sempre posto nei tre bit più a destra (dal 29 al 31), e nel 10 bit per ciascuna
istruzione.
Campi diversi in istruzioni diverse sono sovrapposti sugli stessi bit in modo da non creare
conflitti, l'utilizzo corretto dei bit dell'istruzione è affidato a segnali di controllo che stabiliscono
quale parte della microarchitettura deve essere attivata coerentemente con lo scopo ed il reale
utilizzo dei campi dell'istruzione. In questo modo, come risulta chiaro osservando il
funzionamento dell'unità di controllo, la struttura stessa della CU risulta semplificata, rendendo
più agevole l'esecuzione delle istruzioni.
Esplicitiamo quanto detto, cominciando proprio a vedere quali sono i campi delle istruzioni.
Abbiamo quattro bit di opcode, che occupano i bit dal 29 alla 31 e nel bit 10, per ciascuna
istruzione. Lo schema seguente indica la loro posizione all'interno della stringa dei 32 bit di
un'istruzione. I bit interessati sono evidenziato con O, il numero sopra di essi indica la posizione a
partire dal bit più a destra (il bit 0) in ordine crescente man mano che ci si sposta a sinistra:
31 30 29 10 1 0

O O O O

Possono esserci fino a tre campi di registro di 5 bit ciascuno. Due campi (A, B ) indicano proprio
due operandi sui quali eseguire le istruzioni, il terzo campo (D ) indica il registro di destinazione
nel quale memorizzare il risultato dell'operazione. A questi si affiancano tre bit per il modo (M )
di indirizzamento che indicano se leggere il dato direttamente da uno dei 32 registri (indirizzato
con 5 bit), o se utilizzare i 32 bit del registro come indirizzo per la memoria (che può raggiungere
232 = 4 G locazioni di memoria). Ciascun campo registro segue il proprio bit di modo formando
tre blocchi da 6 bit posizionati a partire dal bit 28 in cui si ha l'operando in letura a, segue
l'operando in scrittura b, infine l'ultimo campo è per il risultato in scrittura.
28 27 23 22 21 17 16 15 11

M A A A A A M B B B B B M D D D D D

I campi descritti sono sufficienti per scrivere istruzioni a due operandi come una somma.
Ad esempio per sommare il quinto (00101) ed il sesto (00110) registro e memorizzare il risultato
nel settimo registro (00111) con tecnica di indirizzamento diretta il codice istruzione da utilizzare
è il seguente:
000 100101 100110 100111 0 0000000000
Gli ultimi 10 bit sono inutilizzati e nell'istruzione sono stati posti a zero, and, or, xor, differenza e
prodotto utilizzano istruzioni della stessa forma.

5
Per le operazioni che necessitano di costanti (C ) il campo utilizzato può essere di 22 bit, in tal caso
copre le posizioni da 0 a 10 e da 17 a 28, oppure può essere da 15 bit, quelli compresi tra 0 e 10 e
tra 17 e 21. Un opportuno controllo interno al processore determina se i bit più significativi
appartengono o meno all'istruzione in base all'opcode, come mostrato nella descrizione della CU.
28 22 21 17 10 0

C C C C C C C C C C C C C C C C C C C C C C C

Ad esempio il codice per eseguire una imov che memorizza la costante 2 (...10) nel quinto (00101)
registro, sempre indirizzato direttamente:
101 000000000000 1001011 0000000010 (nessun bit inutilizzato);

Se invece avessi considerato un'istruzione di branch che avanza di 3 posizioni (...011) se il sesto
registro (00110) è maggiore di zero il codice corretto sarebbe stato:
111 100110 0 00000 000000 0 0000000011
In questo caso 10 bit non sono utilizzati, nell'esempio sono stati riempiti con degli zeri.
Gli ultimi due campi sono l'indice del bit da settare ad uno oppure a zero, e la direzione di shift.
L'indice (I ) utilizza 5 bit, dal 22 al 18, mentre lo shift (S ) necessita di un solo bit posto in
ventiduesima posizione.
28 27 23 22 21 18 17 16 15 11

S/I I I I I

Ad esempio per eseguire il bit clear del quinto (00101) registro, memorizzando il risultato nel terzo
(00011) registro il codice corretto è:
100 100101 10110 0 100011 1 0000000000

con 11 bit inutilizzati evidenziati in grigio. Stessa forma per bit set. Volendo invece eseguire lo
shift del quinto (00101) registro verso sinistra con risultato nel settimo (00111) registro (anche in
questo caso in modo diretto), il codi corretto è:
100 100101 1 00000 100111 1 0000000000
in cui sono 15 i bit inutilizzati.
Il massimo numero di operandi facenti riferimento a registri di link sono due, uno in lettura, uno
in scrittura.

Microarchitettura
Le istuzioni utilizzano un opcode con 5 bit per operando. I 5 bit sono utilizzati per indirizzare un
registro tra i 32 disponibili, che fornisce una parola da 32 bit. Questa può essere un operando,
oppure un registro di una memoria (che può raggiungere al massimo 4G linee) a sua volta a 32 bit
per parola.
I blocchi registri e memoria sono connessi in cascata. Le tre uscite dati dei registri costituiscono
altrettanti ingressi per la memoria.
Nel caso in cui il modo di indirizzamento è diretto (quindi il relativo bit di modo è posto ad 1
nell'opcode) e quindi il contenuto dei registri deve essere utilizzato come operando, la memoria

6
farà semplicemente passare il dato dall'ingresso all'uscita, proprio in base al valore dei bit di
modo. Al contrario nel caso in cui il modo di indirizzamento e indiretto, nell'opcode avrò il bit di
modo pari a 0, ed i 5 bit di indirizzo nei registri saranno espansi dai registri a 32 bit di indirizzo
che la memoria utilizzerà per prendere un operando in uno spazio di indirizzamento di 2^32 =
4G.
La memoria prende tre ingressi a 32 bit dai registri, dei quali solamente due funzionano nel modo
descritto, il terzo ingresso (c) infatti serve esclusivamente come indirizzo per la scrittura di dati
provenienti dalla porta data_c. Le due uscite data_a, data_b collegate agli ingressi a, b invece
sono collegate ai bus operandi dell'ALU, bus_a, bus_b. Il risultato calcolato dall'ALU (bus_c)
viene riportato in ingresso nella memoria, nei registri, nell'unità di controllo e nel PC. Il risultato
viene memorizzato nei registri o nella memoria in base al bit di modo, può essere utilizzato dalla
CU per realizzare il branch, oppure può essere memorizzato nel PC nel caso in cui l'ultima
operazione è stata svolta sul PC.
Nello schema della microarchitettura si nota inoltre l'ALU completamente combinatoria con due
bus di ingresso che possono essere scritti dalla memoria oppure dai blocchi PC e Bit expander.
PC è il registro utilizzato per memorizzare il program counter, mentre il bit expander serve per
riportare al numero corretto di bit una costante presa dall'opcode di un'istruzione o comunque
imposta dalla CU:
L'unità di controllo infine è il blocco che si occupa di coordinare le parti descritte al fine di
svolgere le operazioni previste dalle specifiche del processore. Contiene il registro istruzioni (IR)
nel quale viene memorizzato l'opcode dell'istruzione corrente. L'istruzione proviene da una porta
apposita detta fetched pilotata in scrittura dalla memoria che vi pone il contenuto della parola
indirizzato dai 32 bit presenti in ingresso su data_c.
Nello schema alla pagina seguente è riportato uno schema dell'architettura descritta. Le
connessioni in blu indicano un bus di 32 bit, le linee sottili in nero indicano semplici collegamenti
ad un bit, infine i collegamenti in nero più spessi indicano altri segnali a più bit.
I segnali utilizzati dal link manager sono esterni al processore e non sono riportati, così come
sono assenti i segnali di clock o reset!

7
exp_en
exp_bitnumeber
data_c exp_constant
G Control Unit PC_enable
ovflow PC_update PC Bit expander

O G IR
ctrl_ALU
indice_reg BUS_A BUS_B
shift_type

mem_out_en
mem_write
lmngr_ack
lmngr_err

fetched
CMP
reset
Pluto

sel_b
sel_a

sel_c
clk

mb
ma

mc

f
sel_a

ma
err

m
ack
sel_c

mc
w
sel_b

fetched

mb

f
out_enable
write_enable

data_a
data_b

data_in

segnali lnkmngr data_a a Me mory


data_b b
data_c c ALU
Re g_w ith_link

data_c BUS_C
ck ck
ALU
L’ALU, blocco completamente combinatorio, prende gli operandi direttamente dai 2 bus in
ingresso, bus_a e bus_b, ai quali sono collegati tutti i blocchi che realizzano le operazioni
specifiche. Le operazioni ALU a due operandi sono add, sub, mul, and, or, xor, mentre shift, bit
clear, bit set necessitano di un solo operando.

Il risultato posto in uscita sul bus_c è selezionato dal multiplexer pilotato tramite un codice di
controllo binario a 4 bit. Normalmente tale codice proviene da quattro bit del codice istruzione,
altrimenti può essere impostato dalla CU che può anche selezionare direttamente uno dei due
operandi a, o b.
Nella seguente tabella sono elencati i codici per l'ALU e la relativa funzione svolta. Come si può
notare sono tutti identici agli opcode delle istruzioni, in più compaiono due codici per passare
uno dei due operandi a, b, dal bus d'ingresso al bus in uscita, che non possono essere
programmati dall'esterno ma sono impostati esclusivamente dalla CU.

a 0001

b 0011

ADD 0000

SUB 0010

MUL 0100

AND 0110

XOR 1000

SHIFT 1001

OR 1010

BCR 1100

BSR 1101

9
Registri
I registri sono costituiti da un array di 32
sel_a

err

m
ack
parole da 32 bit ciascuna, i primi 4 registri

sel_c
sel_b

write_enable
sono particolari, poiché sono utilizzati
come link per interfacciare altri
rpocessore dello stesso tipo e saranno
considerati nel paragrafo seguente.

data_in Ogni elemento è indirizzabile con 5 bit,


contenuti direttamente nell'istruzione.
segnali lnkmngr data_a a Poiché le istruzioni possono gestire fino a
data_b b tre operandi dei quali due in lettura, due in
data_c c scrittura, ci sono tre ingressi a 5 bit per tre
indirizzi simultanei, cioè sel_a e sel_b e
Re g_w ith_link sel_c. Ad ogni fronte di salita del clock
sulle uscite data_a, data_b saranno presenti
ck i 32 bit indirizzati rispettivamente da sel_a,
sel_b.

Diverso il comportamento di sel_c e rispettivo data_c per via delle differenze operative tra modo
diretto ed indiretto. La lettura dai registri infatti, deve avvenire sempre e comunque allo stesso
modo. Sarà poi la memoria a discriminare tra indirizzamento diretto, nel qual caso i bit in uscita
dai registri sono proprio quelli richiesti dall'istruzione che pertanto saranno passati ai bus
operandi, o tra indirizzamento indiretto, in cui la memoria utilizza i bit provenienti dai registri
(che sono comunque necessari) come indirizzo al quale prelevare il dato richiesto dall'istruzione!
Quindi se l'operando c e indirizzato in modo diretto allora l'uscita data_c non conterrà alcun dato
utile, il segnale di sel è utilizzato come indirizzo in cui memorizzare il segnale data_in. Se invece
l'indirizzamento è indiretto allora si procede analogamente a quanto fatto per gli operandi a, b,
passando il contenuto dei registri attraverso data_c alla memoria, che utilizzerà tale valore come
indirizzo in cui scrivere. La scrittura ovviamente è abilitata solamente se viene attivato il segnale
write_enable (attivo alto), inoltre il bit di modo m in ingresso indica ai registri come comportarsi.

I restanti controlli ack ed err sono utilizzati dal link manager che andiamo ora ad esaminare.

Link manager
È l’unità che gestisce le comunicazioni tra il processore e le altre cpu, funziona in modo
bloccante per permettere di sincronizzare l’elaborazione, e si trova all’interno dei registri.
Utilizza due segnali di controllo in ingresso e due in uscita per ogni link. Il primo segnale è di
request, viene attivato dal microtransputer quando deve eseguire un'operazione su un link. Il
secondo segnale è un selettore lettura scrittura, ed è:
1 = Scrittura
0 = Lettura
L’idea di fondo è che lo scambio di dati tra processori deve essere coerente, cioè un risultato
parziale di un’elaborazione viene passato ad un’altra CPU quando questo risultato è richiesto ed è
stato calcolato. La comunicazione quindi, avviene solo se contemporaneamente un processore
scrive un dato in uno dei registri speciali della memoria ed il processore collegato a quella porta

10
richiede la lettura del dato. Fino a quando non si verifica questa condizione (cioè un processore
pronto a leggere ed un processore pronto a scrivere) il programma non prosegue!
Si distinguono fondamentalmente 2 casi, in un primo caso la scrittura precede la lettura, nel
secondo caso si ha l’inverso.
Dal punto di vista fisico per ogni link il processore ha 32 linee per i dati, 2 segnali di controllo di
uscita, dunque i 2 segnali simmetrici in ingresso. Saranno identificati r/w_in, ack/req_in e gli
omonimi _out riferendoci ad un processore

Req_out Req_in
Rw_out Rw_in
CPU1 Link (32) Link (32) CPU2
Rw_in Rw_out
Req_in Req_out

Consideriamo per un solo link il caso in cui la scrittura preceda la lettura. In primo luogo il dato
da scrivere viene memorizzato all'interno dei registri, contemporaneamente inizia la procedura
per la gestione dei link. La scrittura sarà la fase finale di una qualche istruzione che adopera uno
dei 4 registri di link come destinazione del risultato. L’esecuzione del programma viene arrestata e
vengono alzati i segnali richiesta scrittura (req/ack = 1, r/w = 1) relativi al link attivato.
Al fronte successivo del clock il contenuto del registro viene posto sul link corrispondente se
questo è disponibile per la scrittura, cioè se l'altro processore non sta già tentando di scrivere sul
link. Il processore permane poi in questo stato fino a quando non legge che req/ack = 1 e r/w =
0, cioè fino a quando l'altro processore invia una richiesta di lettura sul link. Se req/ack fosse pari
ad uno si avrebbe un’errore, entrambi i processori scrivono sullo stesso link.
Se il link è usato correttamente, al fronte successivo del clock l’altro processore scrive il dato,
infine un ciclo dopo vengono ripristinate le impostazioni di base: il link è posto in alta impedenza
e tutti i controlli sono posti a zero. Un segnale di ack interno al processore indica alla CU che
l’operazione è conclusa.
Nell'immagine seguente è illustrato lo schema di principio del funzionamento

Ciclo scrittura -> lettura

Req_out

1=lettura
Rw_out

Link (32) ZZZZZ REG DATA ZZZZZ

Req_in <-letto!

Rw_in

Se invece consideriamo il caso duale in cui è la lettura di un dato a precedere la scrittura, mi


troverò nella fase iniziale dell'istruzione a dover inviare su uno dei due bus operandi un dato che
non è ancora presente all’interno del processore. I selettori del registro indicheranno una delle
prime 4 locazioni particolari.

11
Anche in questo caso l’unità di controllo dovrà attendere che la procedura di gestione dei link
completi il trasferimento, deve attendere cioè che il segnale di ack che viene inviato in
concomitanza con la presenza del dato sul bus sia pari ad uno. Gli altri segnali di controllo (tipo
read) vengono ignorati in questa fase, così come indifferente è il bit di modo del registro.
Anche in questo caso se si verificano errori dovuti alla simultanea lettura o scrittura di un link,
viene inviato un segnale di errore (ponendo err = 1) alla CU, che invia un analogo segnale
all'esterno del processore.
Il seguente diagramma temporale è stato ottenuto simulando il comportamento di due link e
mostra anche altri segnali che non sono stati considerati nella precedente descrizione!

Memoria
La memoria è un array di parole da 32 bit ciascuna,
ma

mc
w
mb

f
out_enable
fetched

implementabile in diverse capacità ma fino ad un


data_a massimo di 4G linee, corrispondenti ad indirizzi a 32
data_b bit. Dispone di tre ingressi a 32 bit indicati con a, b e
c, che possono contenere degli operandi oppure
degli indirizzi, due uscite a 32 bit per i bus chiamate
data_a, data_b, un'uscita utilizzata per il fetch delle
istruzioni verso la CU ed un ingresso dal bus_c dei
a Me mory risultati.
b
c Consideriamo in primo luogo un'operazione di
lettura. La lettura può essere diretta o indiretta, nel
caso in cui sia diretta la memoria riceve agli ingressi
degli operandi che deve semplicemente passare sui
data_c bus istruzioni dell'ALU, altrimenti utilizza gli ingressi
ck
a, b come indirizzi, il contenuto della memoria viene
posto su uno dei due bus esterni. Il tipo di accesso in

12
memoria è indicato da un apposito bit nell'opcode dell'istruzione, in base a questo bit (presente
sugli ingressi ma, mb, mc) la memoria discrimina tra uno dei due accessi descritti.
Entrambi gli ingressi vengono trattati simultaneamente, per cui occorre un solo ciclo di clock per
leggere entrambi gli operandi di un'istruzione.
La scrittura è controllata da un apposito segnale di write attivo alto, e dal bit di modo mc. Poiché
la scrittura in memoria avviene solamente se il registro di destinazione è indiretto devono essere
attivi entrambi i controlli di scrittura e di modo (quest'ultimo è attivo basso per la memoria, in
quanto se il bit di modo è zero allora il modo di indirizzamento dell'operando è indiretto).
L'indirizzo di destinazione della memoria viene preso dal'ingresso c.
Il fetch di un'istruzione richiede di accedere in memoria alla locazione indicata dal PC. Con la
microarchitettura implementata il PC viene aggiornato con lo stesso sommatore presente
nell'ALU facendo la somma tra il PC ed 1, il risultato sarà presente sul bus_c che è utilizzato in
questo caso dalla memoria come indirizzo al quale prelevare un'istruzione. L'istruzione è poi
passata all'unità di controllo dall'uscita fetched.
In questo caso appare evidente inoltre la necessità di disporre di un controllo, out_enable attivo
alto, in grado di porre la uscite in alta impedenza per poter utilizzare il bus con in PC per
operazioni come il branch, o per utilizzare il bit expander come nel caso di imove.

Altri blocchi
Uno sguardo infine agli altri blocchi che compongono la microarchitettura del processore.
PC è il registro del Program Counter che ovviamente contiene l'indirizzo dell'ultima istruzione
prelevata dalla memoria. Completamente asincrono, il PC reagisce immediatamente ai segnali di
controllo, cioè un segnale per la memorizzazione del PC, ed un segnale PC2a attivo alto che
abilità l'uscita del PC che altrimenti è posta in alta impedenza.
Il bit expander invece serve a prendere le costanti contenute nelle istruzioni di lunghezza
inferiore a 32 bit, per portarle in uscita (u) in binari a 32 bit in complemento a 2 adatti per l?ALU
conservandone il segno. Se en = 0 l?uscita è in alta impedenza ed il blocco è disattivato, infine il
controllo exp_bitnumber indica di quandi bit è composto il binario in ingresso.
Il blocco indicato come cmp necessario per l'esecuzione del branch è indicato in figura con un
ingresso connesso al bus operandi a, esso è il comparatore. Il suo scopo è di prendere in ingresso
il contenuto del bus_a e di porre il bit di uscita ad uno se questo è positivo. L'uscita è passata alla
CU che memorizza questo bit come flag!

Control Unit
L'unità di controllo è organizzata come macchina a stati, ad ogni stato corrisponde una fase di
un'istruzione, con i corrispondenti segnali asseriti o negati per ciascuno stato. Al suo interno
contiene il registro istruzioni (IR) contenente l'opcode dell'istruzione in fase di esecuzione. La
maggior parte dei bit dell'IR è permanentemente collegata a dei segnali di controllo in uscita.
Abbiamo ad esempio i bit di modo dei registri coinvolti nelle operazioni permanentemente
collegati alle relative uscite ma, mb, mc, i tre campi da 5 bit dell'IR che indicano i registri coinvolti
nell'operazione sono collegati ai segnali di selezione (sel a, b, c) dei registri. Altri, come ad
esempio i 4 bit di controllo dell'ALU sono applicati presi dall'IR nella maggior parte delle
operazioni, ma la CU ha la possibilità di applicare segnali differenti quando necessario, come ad
esempio nelle istruzioni di branch in cui l'unità di controllo pone l'uscita ctrl_alu al valore
necessario per effettuare la somma. Non tutte le istruzioni utilizzano gli stessi campi dell'IR nello

13
stesso modo! In caso di sovrapposizione i bit sono connessi ad entrambe le possibili uscite,
saranno gli altri controlli a determinare quale blocco opera, quindi la correttezza delle
assegnazioni!
Inoltre la CU contiene un registro FLAG formato da due bit che indicano (in ordine dal più
significativo al meno significativo) se c'è stato overflow, e se il risultato è maggiore di 0.
Vediamo ora come vengono svolte alcune operazioni con l'architettura proposta:

Istruzioni con due operandi

ADD, SUB, MUL, AND, XOR, OR

Formato istruzione
31 29 28 27 23 22 21 17 16 15 11 0
O O O M R R R R R M R R R R R M R R R R R O

Registro dest Operando 1 Operando 2


Opcode

Consideriamo l’istruzione già carica nell’instruction register. Dall’unità di controllo i bit


dell’opcode vengono posti sui controlli dell’ALU, i 5 bit che identificano ognuno dei 3 registri
coinvolti vengono inviati ai registri (sel), ed i bit di modo degli operandi infine controlleranno i
segnali read_a, b, dei registri oppure i segnali fetch_a, b, dell’EMI.
Se il modo di indirizzamento è diretto (M = 1) un ciclo dopo si sta propagando il risultato che
posso memorizzare già sul secondo fronte di salita del clock, altrimenti devo attendere il prelievo
del dato che sarà pronto sul bus solamente quando l’EMI attiva il segnale di ack. La logica di
controllo vedrà tale segnale solamente al fronte successivo del clock, cioè quando anche il
risultato si sarà propagato, quindi quando la CU legge il segnale di ack deve immediatamente
memorizzare il dato.
Il risultato di un’operazione può essere scritto nei registri interni del processore oppure nella
memoria esterna, sempre in base al valore del bit di modo M. Nel primo caso basterà porre ad 1 il
segnale write dei registri, ricordando però che se cerco di scrivere su uno dei registri dal quale sto
leggendo le uscite dei registri vanno in alta impedenza ed il dato non è memorizzato.
Contemporaneamente vengono memorizzati i flag dell’istruzione eseguita negli appositi registri
In caso di indirizzamento indiretto occorre alzare il segnale store dell’EMI e negare i segnali di
fetch, dopodiché basta attendere l’ack.

Nel caso in cui le operazioni facciano uso dei registri speciali, per ogni lettura o scrittura in una
delle 4 locazioni si attende il segnale di ack dal link manager dei registri. In tal caso non serve una
temporizzazione dei segnali di controllo per gestire prelievo da un’altro processore e poi la
scrittura da un’altro processore, il link manager infatti è in grado di attendere il dato da un’altro
processore, aspettare la propagazione del risultato e poi inviarlo ad un’altro processore e
solamente ad operazione conclusa inviare il segnale di ack al processore, anche se i controlli sono
stati impostati tutti dall’inizio.

CMP
L’istruzione di comparazione è a due operandi, ma non contiene nessun registro esplicito in cui
memorizzare il risultato. Infatti l’uscita di tale istruzione è il semplice bit di flag pari ad 1 se a>b.
Il comparatore di per se funziona anche se in modo diverso durante l’esecuzione di una qualsiasi

14
istruzione per fornire i 2 bit di flag. Anche in questo caso le operazioni per prelevare i due
operandi sono standard, cambia la fase di store che deve registrare esclusivamente il flag.

Istruzioni ad un solo operando

SHIFT, BCLR, BSET


Le istruzioni ad un solo operando necessitano del solo bus a. Il dato viene caricato su tale bus nel
modo usuale, settati correttamente i controlli per l’ALU il risultato si ottiene in un solo ciclo, e
viene memorizzato nella maniera usuale. In particolare però i flag non vengono aggiornati al
termine di tali operazioni

Altre istruzioni

BRANCH

Formato istruzione
31 29 28 27 19 18 17 13 12 0
O O O C T T T T T T T T T M R R R R R O

Target Registro
Opcode

Per prima cosa devo porre il registro sul bus selezionando tale operando come uscita dell’ALU.
Sul bus_c ritrovo quindi lo stesso registro invariato, in più il comparatore interno all’ALU avrà
stabilito se il numero è positivo o uguale a zero.
Se il bit di condizione C è zero (devo saltare se il contenuto del registro è zero) e il flag Z è uno,
allora si ha il salto. Pongo quindi in alta impedenza le uscite dell’EMI e dei registri sul bus,
l’operando a diviene il program counter (alzo un segnale di tipo Program counter al bus a PC2a)
invio l’offset dall’unità di controllo al registro costanti indicato con l’1 sopra il bus b e richiedo
una somma algebrica.
Sul bus_c ho il nuovo PC, lo salvo nel registro e lo prelevo con l’EMI asserendo store_c ed uno
dei segnali di fetch. Un ciclo dopo devo riportare il bus in alta impedenza per permettere all’EMI
di scrivere su di esso la successiva istruzione, che passerà attraverso l’ALU opportunamente
settata per tale scopo, infine l’unità di controllo preleva l’istruzione dal bus_c.
Durante l’esecuzione di tali istruzioni vengono ignorati i flag in uscita dall’ALU.
Nel caso in cui non si abbia il salto devo semplicemente incrementare il PC in pratica la
differenza sta nel valore di offset che sarà pari ad 1 invece che a quanto specificato nell’istruzione.
Nel caso di branch incondizionato o condizionato dai flag il ciclo dell’istruzione risulta
semplificato. In tal caso infatti è l’unità di controllo a settare correttamente tutti i controlli già al
primo ciclo, poiché non sono richieste fasi specifiche per il prelievo di un registro e la verifica del
suo contenuto. Partendo dunque dal codice istruzione per prima cosa mi rendo conto che si
tratta di un salto dovuto a flag, per cui confronto immediatamente il flag per sapere se saltare o
meno. Se salto allora sommerò l’offset al PC, altrimenti il PC verrà incrementato di un’unità. Se il
salto è incondizionato non è necessario neppure controllare i flag, sommo semplicemente l’offset
al PC.

15
IMOVE
In questo caso è l’unità di controllo a porre l’operando immediato sul bus_b, passando attraverso
il blocco che gestisce l’espansione a 32 bit delle costanti i nove bit del campo immediate data.
Successivamente abilito la scrittura dei registri.
Il banco di registri deve consentire la scrittura, le uscite sui bus a, b sono in alta impedenza. Si
può fare ponendo i controlli di lettura in modo che siano attivate le uscite per l’EMI, oppure
ponendo sel_c uguale ad uno dei 2 sel a, b con write posto ad 1 che porta tutto in alta impedenza.
L’alta impedenza per l’EMI si realizza negando i segnali di fetch. In entrambi i casi occorre
attendere un ciclo poiché sono unità che reagiscono ai segnali applicati, solo sul fronte di clock.

MOVE
Un registro viene chiamato sul bus (ne occorre uno solo posso utilizzare il bus_a) dai registri o
dall’EMI, lo faccio passare attraverso l’ALU, dopodiché si abilitano i controlli per la scrittura.
Anche in questo caso può essere diretta o indiretta, nulla di nuovo

NOP
Eseguire una nop significa non fare nulla. Tutti i controlli sono posti a zero, per cui i registri non
leggono, l’EMI non preleva dati dall’esterno, PC ed il modulo di espansione costanti presentano
le uscite in alta impedenza...

Fetch istruzione
Il fetch di un’istruzione dalla memoria esterna non è un’istruzione programmabile, ma è
un’operazione che deve essere comunque effettuata dall’unità di controllo tra ogni istruzione,
tranne che in seguito ad istruzioni tipo branch. Il modo di procedere ricalca invece il
comportamento delle istruzioni di branch, anche in questo caso infatti deve essere eseguita la
somma tra il PC e 1, verranno trascurati i valori di riporto, aggiornato il PC col nuovo valore
calcolato che sarà anche utilizzato dall’EMI per prelevare l’istruzione corrispondente in memoria.

Altre operazioni
L’unità di controllo infine dovrà gestire il reset del processore e l’inizializzazione del processore
stesso. Ciò deve avvenire non appena viene asserito dall’esterno un apposito segnale di reset (o
wake up). Lo stato di riposo corrisponde ad una indefinita successione di nop, dopo il reset deve
essere effettuato il fetch di un’istruzione senza utilizzare il PC. L’unità di controllo invia una
costante nulla al modulo di espansione delle costanti, e seleziona l’ingresso b come uscita
dell’ALU. Ottengo quindi l’indirizzo 0, che viene memorizzato nel program counter mentre l’Emi
viene impostata per prelevare l’istruzione dalla memoria esterna. Caricata l’istruzione si procede al
solito modo.

16
Simulazioni
Il processore è stato sottoposto a molteplici simulazioni, sia dei singoli componenti sia del
processore nel suo insieme. Come ultimo test è stato creato un file ascii contenente stringhe di 1
e 0, per un totale di 32 per riga. Il file è stato caricato in memoria ed il processore ha interpretato
le sequenze di bit come istruzioni, eseguendole. Di seguito riportiamo il programma utilizzato per
le simulazioni con la spiegazione delle sequenze binarie.

Codice Istruzione Descrizione

0 101 111111111111 100101 1 1111111110 imove Costante #-2 in reg 5

1 101 000000000000 100110 1 0000000100 imove Costante #+6 in reg 6

2 101 000000000000 100111 1 0000100111 imove Costante #39 in reg 7

3 000 100101 100110 000111 0 0000000000 sum Somma, mem 7 = reg 5 + reg 6

4 101 000000000000 101000 1 0000101000 imove Costante #40 in reg 8

5 010 100111 100110 001000 0 0000000000 mul Moltiplica mem 8 = reg 7 * reg 6

6 011 001000 000000 111111 1 0000000000 move Muovi mem 8 in reg 31

7 110 111111 000100 111110 0 0000000000 bclr Azzera il bit 2 del reg 31 in reg 31

8 101 000000000000 101001 1 0000100000 imove Costante #32 in reg 9

9 011 111110 000000 001001 1 0000000000 move Muovi reg 31 in mem 9

10 111 100110 000000 000000 0 0000000011 branch Salta di #+3 se reg 5>0

11 000 000000 000000 000000 0 0000000000 sum Somma mem 0 = mem 0 + mem 0

12 000 000000 000000 000000 0 0000000000 sum Somma mem 0 = mem 0 + mem 0

13 101 000000000000 101001 1 0000100001 imove Costante #33 in reg 9

14 110 100111 100100 001001 1 0000000000 bset Azzera il bit 2 del reg 7 in mem 9

15 101 000000000000 101001 1 0000100010 imove Costante #34 in reg 9

16 010 100101 100110 001001 0 0000000000 mul Moltiplica mem 9 = reg 5 * reg 6

17 010 000000000000000000 1 0000000000 nop

18 011 111110 000000 100000 1 0000000000 move Muovi reg 30 in link 0

19 101 000000000000 101001 1 0000100011 imove Costante #35 in reg 9

20 000 100101 100000 001001 0 0000000000 sum Somma mem 9 = reg 5 + link 0

17
21 imove
101 000000000000 101001 1 0000100100 Costante #36 in reg 9

22 not
111 100111 000000 001001 1 0000000000 Mem 9 = reg 7 negato bit a bit

23 010 000000000000000000 1 0000000000 nop

24 010 000000000000000000 1 0000000000 nop

25 010 000000000000000000 1 0000000000 nop

26 010 000000000000000000 1 0000000000 nop

27 010 000000000000000000 1 0000000000 nop

28 010 000000000000000000 1 0000000000 nop

29 010 000000000000000000 1 0000000000 nop

30 010 000000000000000000 1 0000000000 nop

31 010 000000000000000000 1 0000000000 nop

32 sum
000 000000 000000 000000 0 0010001000 Somma Link 0 = link 0 + link 0

33 sum
000 000000 000001 000000 0 0000100111 Somma link 0 = link 0 + link 0

34 not
111 111111 111111 111111 1 1111110111 Reg 31 = reg 31 negato bit a bit

35 sum
000 000000 000000 000000 0 0010000110 Somma link 0 = link 0 + link 0

36 not
111 111111 111111 111111 1 1111011000 Reg 31 = reg 31negato bit a bit

18
Elenco file
Il processore è stato dunque realizzato in VHDL strutturale, le varie parti precedentemente descritte
sono state realizzate come entità indipendenti ciascuna scritta in un proprio file e poi connesse insieme.
Vediamo quindi quali sono i file che compongono il processore con una descrizione sommaria del loro
funzionamento e la loro posizione gerarchica, e la loro descrizione VHDL.

one_bit_adder.vhd
Ingressi abit, bbit, cinbit (1)
Uscite sumbit, coutbit (1)
Descrizione: Addizionatore ad un bit. Somma sumbit = abit + bbit + cinbit. In oltre ho il
riporto coutbit.

add32.vhd
Ingressi a,b (32), cin (1)
Uscite sum (32) , cout (1)
Descrizione: Calcola l'addizione con 32 bit. Sum = a+ b + cin, e genera il riporto cout. L’
L’ingresso cin è sempre essere impostato a 0.

sub32.vhd
Ingressi as, bs (32), cins(1)
Uscite sums (32), couts (1)
Descrizione: Calcola la sottrazione as – bs. Anche in questo caso il roporto è 0, sempre

badd32.vhd
Ingressi
Uscite
Descrizione: Sommatore di booth utilizzato nell'omonimo moltiplicatore

bmul32.vhd
Ingressi a,b (32),
Uscite c (32), mul_oflow (1)
Descrizione: Moltiplicatore di booth. Calcola il prodotto tra a e b, l'uscita c è a 32 bit.Il
riporto in uscita serve al solito per impostare il flag di overflow.

shifter_32bit.vhdl
Ingressi Input (32); shift_type (1)
Uscite output (32)
Descrizione: Effettua lo shift di 32 bit in ingresso a destra se shift_type = 0, a sinistra se è
1. I bit aggiunti agli estremi sono sempre pari a 0

xor32.vhdl
Ingressi a,b (32)
Uscite outl (32)
Descrizione: L'uscita c si ottiene dallo xor logico tra a, b.
and32.vhdl
Ingressi a, b (32)
Uscite c (32)
Descrizione: L'uscita c si ottiene da l'and logico tra a, b.

or32.vhdl
Ingressi a, b (32)
Uscite c (32)
Descrizione: L'uscita c si ottiene da l'or logico tra a, b.

Reg_with_link.vhdl
Ingressi
Uscite
Descrizione: Vedi documento

bit_clear.vhdl
Ingressi reg (32), indice_reg (5);
Uscite temp (32);
Descrizione: Prende in ingresso il binario a 32 bit indicato con reg (contenuto nel bus_a
della microarchitettura), ed imposta il bit indice_reg-esimo (a partire da
destra) a 0.

Cmp.vhd
Ingressi a, b (32);
uscite c (1);
descrizione È un comparatore, l’uscita è 1 se a > b

bit_set.vhdl
Ingressi reg (32), indice_reg (5);
Uscite temp (32);
Descrizione: Analogo a bit clear, ma imposta il valore del bit selezionato ad 1..

ALU.vhd
Ingressi a, b (32);
ctrl (4), indice_reg (4), shift_type (1);
Uscite y (32), ovflow (1), cmp (1);
Descrizione: Mette insieme i pezzi definiti per fare operazioni aritmetico logiche, in modo
del tutto combinatorio. Oltre ai segnali ovvi quali due ingressi a, b, e l’uscita
y, ci cono 4 bit per selezionare l’operazione da svolgere (ctrl), alcuni segnali
per le operazioni di shift, bit clear, bit set, il segnale di overflow in uscita
aggiornato all’ultima operazione che può dare overflow, è il segnale del
comparatore.

Memoria.vhd
Ingressi
Uscite
Descrizione: È la memoria del processore. Vedi documento per maggiori informaz.

PC_reg.vhd
Ingressi i (32); PC2a, PCw (1);
Uscite u (32);
Descrizione: È il registro del PC. Completamente asincrono, il PC reagisce immediatamente
ai segnali di controllo. Sul fronte di salita di PCw il PC in ingresso (i) viene
memorizzato. Quando il segnale PC2a è alto il PC è abilitato sul bus_a,
altrimenti la sua uscita (u) è posta in alta impedenza.

bit_expander.vhd
Ingressi i (10), sel, en (1);
Uscite u (32)
Descrizione: Serve a prendere le costanti contenute nelle istruzioni (i), lunghe 9 o 10 bit,
ed a trasformarle in uscita (u) in binari a 32 bit adatti per l’ALU. Se en = 0
l’uscita è in alta impedenza, se sel = 1 si considerano tutti i 10 bit
dell’ingresso.

CU.vhd
Descrizione: L’unità di controllo del sistema

Microtransputer.vhd
Descrizione: L’entity per eccellenza, raccoglie tutti i pezzi precedenti

clock.vhdl
É il clock di sistema, usato per le simulazioni

Struttura

Microtransputer
EMI.vhd
reg_with_link.vhd
CU.vhd
ALU.vhd

add32.vhd
one_bit_adder.vhd

bmul32.vhd
badd32.vhd

one_bit adder

add32
one_bit adder

sub32.vhd

shifter_32bit.vhdl
xor32.vhdl
and32.vhdl
or32.vhdl
bit_clear.vhd
bit_set.vhd
cmp.vhd
bit_expander.vhd
PC_reg
memory.vhd
clock.vhdl

Potrebbero piacerti anche