SAPIENZA
Tesina di
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:
or logico OR 1010
4
bit set BSET 1101
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
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.
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
Req_out
1=lettura
Rw_out
Req_in <-letto!
Rw_in
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
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:
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
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.
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.
3 000 100101 100110 000111 0 0000000000 sum Somma, mem 7 = reg 5 + reg 6
5 010 100111 100110 001000 0 0000000000 mul Moltiplica mem 8 = reg 7 * reg 6
7 110 111111 000100 111110 0 0000000000 bclr Azzera il bit 2 del reg 31 in reg 31
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
14 110 100111 100100 001001 1 0000000000 bset Azzera il bit 2 del reg 7 in mem 9
16 010 100101 100110 001001 0 0000000000 mul Moltiplica mem 9 = reg 5 * reg 6
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
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