Sei sulla pagina 1di 22

Università degli studi di Roma

SAPIENZA

Università degli studi di Roma S APIENZA Tesina di Architettura di Sistemi integrati Prof. Mauro Olivieri

Tesina di

Architettura di Sistemi integrati

Prof. Mauro Olivieri

1

Perticaroli Stefano Patrizi Roberto Di Liberto Alessio Barbieri Stefano

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)

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

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
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 2 32 = 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
M A A A A A M B B B B B M D D
M A A A A A M B B B B B M D D

M

A

A

A

A

A

M

B

B

B

B

B

M

D

D

D

D

D

M A A A A A M B B B B B M D D D
M A A A A A M B B B B B M D D D
M A A A A A M B B B B B M D D D
M A A A A A M B B B B B M D D D
M A A A A A M B B B B B M D D D
M A A A A A M B B B B B M D D D
M A A A A A M B B B B B M D D D
M A A A A A M B B B B B M D D D
M A A A A A M B B B B B M D D D
M A A A A A M B B B B B M D D D
M A A A A A M B B B B B M 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 1 00101
è il seguente:
000
1
00101

100110

1 00111
1
00111

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.

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 ( registro, sempre indirizzato direttamente:

101 000000000000

1 00101
1
00101

1 0000000010 (nessun bit inutilizzato);

10)

nel quinto (00101)

Se invece avessi considerato un'istruzione di branch che avanza di 3 posizioni ( registro (00110) è maggiore di zero il codice corretto sarebbe stato:

111

1 00110
1
00110

0 00000 000000 0 0000000011

011)

se il sesto

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
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

10110 0 0

1 00011 1
1 00011
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

1 00101
1
00101

1 00000

1 0000000000 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

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!

exp_en exp_bitnumeber data_c exp_constant G Control Unit PC_enable ovflow PC_update IR O G ctrl_ALU
exp_en
exp_bitnumeber
data_c
exp_constant
G
Control Unit
PC_enable
ovflow
PC_update
IR
O
G
ctrl_ALU
indice_reg
shift_type
clk
reset
Pluto
sel_a
sel_b
sel_c
lmngr_ack
lmngr_err
fetched
ma
mb
mc
mem_write
mem_out_en
f
lmngr_err fetched ma mb mc mem_write mem_out_en f PC BUS_A CMP Bit expander BUS_B data_a data_b
lmngr_err fetched ma mb mc mem_write mem_out_en f PC BUS_A CMP Bit expander BUS_B data_a data_b
lmngr_err fetched ma mb mc mem_write mem_out_en f PC BUS_A CMP Bit expander BUS_B data_a data_b

PC

lmngr_err fetched ma mb mc mem_write mem_out_en f PC BUS_A CMP Bit expander BUS_B data_a data_b

BUS_A

CMP
CMP

Bit expander

mb mc mem_write mem_out_en f PC BUS_A CMP Bit expander BUS_B data_a data_b data_in data_a a

BUS_B

data_a data_b data_in data_a a segnali lnkmngr Memory data_b b data_c c Reg_with_link ck ck
data_a
data_b
data_in
data_a
a
segnali lnkmngr
Memory
data_b
b
data_c
c
Reg_with_link
ck
ck
data_c
sel_a
sel_b
sel_c
ack
err
write_enable
m
fetched
ma
mb
mc
w
out_enable
f
ALU
ALU

BUS_C

ck ck data_c sel_a sel_b sel_c ack err write_enable m fetched ma mb mc w out_enable

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

sel_a

err

ack

sel_c

m

sel_b

write_enable

Registri

I registri sono costituiti da un array di 32

parole da 32 bit ciascuna, i primi 4 registri sono particolari, poiché sono utilizzati come link per interfacciare altri rpocessore dello stesso tipo e saranno considerati nel paragrafo seguente.

Ogni elemento è indirizzabile con 5 bit, contenuti direttamente nell'istruzione.

Poiché le istruzioni possono gestire fino acon 5 bit, contenuti direttamente nell'istruzione. tre operandi dei quali due in lettura, due in scrittura,

tre operandi dei quali due in lettura, due inPoiché le istruzioni possono gestire fino a scrittura, ci sono tre ingressi a 5 bit per

scrittura, ci sono tre ingressi a 5 bit per tre indirizzi simultanei, cioè sel_a e sel_b e sel_c . Ad ogni fronte di salita del clock sulle uscite sel_a e sel_b e sel_c. Ad ogni fronte di salita del clock sulle uscite data_a, data_b saranno presenti i 32 bit indirizzati rispettivamente da sel_a,

presenti i 32 bit indirizzati rispettivamente da sel_a , data_in segnali lnkmngr data_a data_b data_c Reg_with_link

data_in

segnali lnkmngr

data_a

data_b

data_c

Reg_with_link

ck

a

b

c

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

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
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 REG DATA ZZZZZ Link (32) ZZZZZ Req_in <-letto!
Ciclo scrittura -> lettura
Req_out
1=lettura
Rw_out
REG DATA
ZZZZZ
Link (32)
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.

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!

che non sono stati considerati nella precedente descrizione! Memoria   fetched ma mb mc w out_enable

Memoria

 

fetched

ma

mb

mc

w

out_enable

f

data_a

 

data_b

a Memory

a

Memory

b

b

c

c

 

ck

data_c

data_b a Memory b c   ck data_c La memoria è un array di parole da

La memoria è un array di parole da 32 bit ciascuna, implementabile in diverse capacità ma fino ad un massimo di 4G linee, corrispondenti ad indirizzi a 32 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 risultati.

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 bus istruzioni dell'ALU, altrimenti utilizza gli ingressi a, b come indirizzi, il contenuto della memoria viene posto su uno dei due bus esterni. Il tipo di accesso in

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

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
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

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

O O O C T T T T T T T T T M R R
O O O C T T T T T T T T T M R R
O O O C T T T T T T T T T M R R
O O O C T T T T T T T T T M R R
O O O C T T T T T T T T T M R R
O O O C T T T T T T T T T M R R
O O O C T T T T T T T T T M R R
O O O C T T T T T T T T T M R R
O O O C T T T T T T T T T M R R
O O O C T T T T T T T T T M R R
O O O C T T T T T T T T T M R R
O O O C T T T T T T T T T M R R
Target Registro Opcode
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.

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.

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

1 00101
1
00101

1 1111111110

imove

Costante #-2 in reg 5

1 101

000000000000

1 00110
1
00110

1 0000000100

imove

Costante #+6 in reg 6

2 101

000000000000

1 00111
1
00111

1 0000100111

imove

Costante #39 in reg 7

3 000

1 00101
1
00101

1

00110

0 00111
0
00111

0

0000000000

sum

Somma, mem 7 = reg 5 + reg 6

4 101

000000000000

1 01000
1
01000

1

0000101000

imove

Costante #40 in reg 8

5 010

1 00111
1
00111

1

00110

0 01000
0
01000

0

0000000000

mul

Moltiplica mem 8 = reg 7 * reg 6

6 011

0 01000
0
01000

000000

1 11111
1
11111

1

0000000000

move

Muovi mem 8 in reg 31

7 110

1 11111
1
11111

000100

1 11110
1
11110

0

0000000000

bclr

Azzera il bit 2 del reg 31 in reg 31

8 101

000000000000

1 01001
1
01001

1 0000100000

imove

Costante #32 in reg 9

9 011

1 11110
1
11110

000000

0 01001
0
01001

1 0000000000

move

Muovi reg 31 in mem 9

10 111

1 00110
1
00110

000000 000000 0 0000000011

branch

Salta di #+3 se reg 5>0

11 000

0 00000
0
00000

0

00000

0 00000
0
00000

0

0000000000

sum

Somma mem 0 = mem 0 + mem 0

12 000

0 00000
0
00000

0

00000

0 00000
0
00000

0

0000000000

sum

Somma mem 0 = mem 0 + mem 0

13 101

000000000000

1 01001
1
01001

1 0000100001

imove

Costante #33 in reg 9

14 110

1 00111
1
00111

100100

0 01001
0
01001

1 0000000000

bset

Azzera il bit 2 del reg 7 in mem 9

15 101

000000000000

1 01001
1
01001

1 0000100010

imove

Costante #34 in reg 9

16 010

1 00101
1
00101

1

00110

0 01001
0
01001

0

0000000000

mul

Moltiplica mem 9 = reg 5 * reg 6

17 010

000000000000000000

1 0000000000

nop

 

18 011

1 11110
1
11110

000000

1 00000
1
00000

1

0000000000

move

Muovi reg 30 in link 0

19 101

000000000000

1 01001
1
01001

1

0000100011

imove

Costante #35 in reg 9

20 000

1 00101
1
00101

1

00000

0 01001
0
01001

0

0000000000

sum

Somma mem 9 = reg 5 + link 0

21 101

000000000000

1 01001
1
01001

1 0000100100

imove

Costante #36 in reg 9

22 111

1 00111
1
00111

000000

0 01001
0
01001

1 0000000000

not

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 000

0 00000
0
00000

0

00000

0 00000
0
00000

0 0010001000

sum

Somma Link 0 = link 0 + link 0

33 000

0 00000
0
00000

0

00001

0 00000
0
00000

0

0000100111

sum

Somma link 0 = link 0 + link 0

34 111

1 11111
1
11111

111111

1 11111
1
11111

1

1111110111

not

Reg 31 = reg 31 negato bit a bit

35 000

0 00000
0
00000

0

00000

0 00000
0
00000

0

0010000110

sum

Somma link 0 = link 0 + link 0

36 111

1 11111
1
11111

111111

1 11111
1
11111

1

1111011000

not

Reg 31 = reg 31negato bit a bit

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

Uscite

Descrizione:

sub32.vhd

Ingressi

Uscite

Descrizione:

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

. L’ L’ingresso cin è sempre essere impostato a 0. as, bs (32), cins(1) sums (32),
. L’ L’ingresso cin è sempre essere impostato a 0. as, bs (32), cins(1) sums (32),
. L’ L’ingresso cin è sempre essere impostato a 0. as, bs (32), cins(1) sums (32),

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

as, bs (32), cins(1) sums (32), couts (1) Calcola la sottrazione as – bs. Anche in
as, bs (32), cins(1) sums (32), couts (1) Calcola la sottrazione as – bs. Anche in

badd32.vhd

Ingressi

Uscite

Descrizione:

Sommatore di booth utilizzato nell'omonimo moltiplicatore

bmul32.vhd

Ingressi

Uscite

Descrizione:

a,b (32), c (32), mul_oflow (1) 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

Uscite

Descrizione:

xor32.vhdl

Ingressi

Uscite

Descrizione:

Input (32); shift_type (1) output (32) 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

se è 1. I bit aggiunti agli estremi sono sempre pari a 0 a,b (32) outl
se è 1. I bit aggiunti agli estremi sono sempre pari a 0 a,b (32) outl
se è 1. I bit aggiunti agli estremi sono sempre pari a 0 a,b (32) outl

a,b (32) outl (32) L'uscita c si ottiene dallo xor logico tra a, b.

bit aggiunti agli estremi sono sempre pari a 0 a,b (32) outl (32) L'uscita c si
bit aggiunti agli estremi sono sempre pari a 0 a,b (32) outl (32) L'uscita c si

and32.vhdl

Ingressi

Uscite

Descrizione:

or32.vhdl

Ingressi

Uscite

Descrizione:

a, b (32) c (32) L'uscita c si ottiene da l'and logico tra a, b.

a, b (32) c (32) 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

Uscite

Descrizione:

ALU.vhd

Ingressi

Uscite

Descrizione:

Memoria.vhd

Ingressi

Uscite

reg (32), indice_reg (5); temp (32); Analogo a bit clear, ma imposta il valore del bit selezionato ad 1

a, b (32); ctrl (4), indice_reg (4), shift_type (1); y (32), ovflow (1), cmp (1); 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.

Descrizione:

PC_reg.vhd

È la memoria del processore. Vedi documento per maggiori informaz.

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
EMI.vhd
reg_with_link.vhd
CU.vhd
ALU.vhd
add32.vhd
one_bit_adder.vhd
bmul32.vhd
badd32.vhd
one_bit adder
add32

sub32.vhd

sub32.vhd one_bit adder … xor32.vhdl and32.vhdl or32.vhdl bit_clear.vhd bit_set.vhd cmp.vhd
one_bit adder
one_bit adder
one_bit adder
one_bit adder

one_bit adder

one_bit adder

sub32.vhd one_bit adder … xor32.vhdl and32.vhdl or32.vhdl bit_clear.vhd bit_set.vhd cmp.vhd
sub32.vhd one_bit adder … xor32.vhdl and32.vhdl or32.vhdl bit_clear.vhd bit_set.vhd cmp.vhd

xor32.vhdl

and32.vhdl

or32.vhdl

bit_clear.vhd

bit_set.vhd

cmp.vhd

shifter_32bit.vhdl

bit_expander.vhd

PC_reg

memory.vhd

clock.vhdl