Processore Didattico
Processore Didattico
Pasquale Rullo
1 PREMESSA 2
8 DISPOSITIVI DI I/O 13
9 CONCLUSIONI 15
1
1 Premessa
Un processore general purpose è un sistema di elaborazione programmabile, cioè, in grado di eseguire
programmi. Esso è pertanto una macchina universale, capace di risolvere tutti i problemi per i quali esiste un
algoritmo (a patto che il linguaggio di programmazione sia sufficientemente potente). Un processore
general purpose è, in ultima analisi, un interprete del linguaggio usato per descrivere gli algoritmi.
L’architettura di un calcolatore digitale si basa (1) su un processore general purpose (CPU - Central
Processing Unit) e (2) su una memoria RAM (detta anche memoria centrale) in cui risiede il programma in
esecuzione. Tale modello concettuale è noto come macchina di Von Neumann (o modello a
programma mem orizzato).
CPU e RAM formano l’Unità Centrale –uno schema è riportato nella seguente figura. In esso, la RAM è
collegata alla CPU attraverso un bus dati ed un bus indirizzi. I registri MAR e MDR interfacciano la CPU con
la RAM.
Quando si vuole eseguire un programma, lo si deve preventivamente caricare nella RAM. A questo punto, la
sua esecuzione avviene secondo il seguente schema, detto“ciclo della CPU”:
2
− Registro Acc (Accumulatore): contiene i risultati e gli operandi impliciti delle istruzioni (vedi descrizione
linguaggio macchina)
− Registro IR (Instruction Register): contiene l’istruzione in fase di esecuzione
− Registro PC (Program Counter): contiene l’indirizzo di memoria della prossima istruzione da eseguire
− T0 e T1: registri tampone che memorizzano l’input all’ALU
− ALU (Unità Logico-Aritmetica): è una rete combinatoria che esegue le seguenti operazioni logiche e
aritmetiche: ALU(T0+T1), ALU(T0-T1), ALU(T1) (funzione identità) e ALU(not T1) (complementazione).
La RAM è interfacciata con il processore tramite due registri: MAR e MDR. Il primo contiene l’indirizzo della
cella di memoria da cui leggere o in cui scrivere. Il secondo contiene il dato da scrivere o il risultato della
lettura.
0 15 0 1 2 15 0 14
Acc MDR
ßAcc T0 T1
IR
I2 M
I1 0 11
I0 ALU
0 11 MAR
PC
3
Istruzione Semantica Commento
STORE x Acc à M[x] – trasferisci il contenuto Istruzione di trasferimento dati dalla
dell’accumulatore nella locazione di CPU alla memoria centrale M
memoria con indirizzo x
LOAD x M[x] à Acc - trasferisci il contenuto della Istruzione di trasferimento dati dalla
locazione di memoria con indirizzo x memoria centrale M alla CPU
nell’accumulatore
ADD x Acc + M[x] à Acc – somma il contenuto Istruzione airtmetica; uno dei due
dell’accumulatore con il contenuto della operandi è esplicito (locazione di
locazione di memoria con indirizzo x e salva memoria con indirizzo x), l’altro è
il risultato nell’accumulatore implicito (accumulatore)
SUB x Acc - M[x] à Acc Come sopra
JZ x If Acc == 0 salta all’istruzione che si trova Istruzione di salto condizionato
all’ind. x
JUMP x salta all’istruzione che si trova all’ind. x Istruzione di salto incondizionato
HALT fine programma Istruzione di chiusura del programma
Come si può notare, tutte le istruzioni di LMCD hanno un unico operando (operando esplicito) che è un
indirizzo di memoria. Ciò perché, nel caso di operazioni binarie (STORE, LOAD, ADD, SUB, JZ), gli altri
operandi sono impliciti. Ad esempio, l’istruzione ADD x ha il seguente significato: somma il contenuto M[x]
della locazione di memoria (RAM) che ha indirizzo x (operando esplicito) al contenuto del registro
Accumulatore (operando implicito), ed il risultato memorizzalo nel registro Accumulatore. In generale, il
registro Accumulatore è la destinazione dei risultati delle istruzioni, nonché il secondo operando delle
istruzioni con due operandi.
• LOAD Y
• STORE X
1. LOAD c
2. ADD d /* c+d à acc
3. STORE y /* acc à y, cioé, c+dà y
4. LOAD a
5. ADD b /* a+b à acc
6. SUB y /* acc – y à acc, cioé, (a+b) – (c+d) à acc
7. STORE y /* (a+b)-(c+d) à y
4
3. ADD b // a+b à acc
4. JUMP 6
5. SUB b // a-b à acc
6. STORE a
const c=1;
int i = 5;
int b=50;
while i != 0 {b=b-i; i=i-c;}
1. LOAD i
2. JZ 10
3. LOAD b
4. SUB i //b-i à acc
5. STORE b //acc à b
6. LOAD i
7. SUB c // i-1 à acc
8. STORE i //acc à a
9. JUMP 2
10. HALT
Codice Operativo - Poiché il numero di istruzioni di LMCD è pari a 7, sono sufficienti 3 bit per
rappresentare il Codice Operativo; in particolare, possiamo utilizzare la seguente codifica:
Operando - Considerato che la memoria ha una capacità di 4 Kbyte (4096 byte), cioè 212 byte, ogni indirizzo
è lungo 12 bit. Pertanto, sono necessari 12 bit per memorizzare l’operando (esplicito) di ogni singola
istruzione.
5
Ne consegue che ogni istruzione è lunga 15 bit (3 per il Codice Operativo e 12 per l’indirizzo di memoria).
Sono pertanto necessari 2 byte (16 bit) per la sua memorizzazione (sono utilizzati i 15 bit più significativi).
Utilizziamo il termine CELLA (o PAROLA) per indicare una sequenza di due byte.
Nel seguito assumeremo che anche i dati siano memorizzati su 2 byte (216 – 1 è quindi il più grande numero
rappresentabile, assumento che siano trattati solo numeri naturali).
Da quanto detto consegue che il bus indirizzi dovrà essere a 12 bit ed il bus dati dovrà essere a 16 bit.
6
• APC = 1 allora
o Se KPC = 0 allora il PC carica dall’esterno (bus indirizzi)
o Se KPC = 1 allora il PC incrementa il suo contenuto (indirizzo della prossima istruzione)
Per il riconoscimento della istruzione corrente nel registro IR, i tre bit più a sinistra vengono inviati all’Unità
di Controllo – essi rappresentano il codice operativo della istruzione.
1. reperisci in memoria la prossima istruzione da eseguire (il cui indirizzo è nel PC) trasferendola nel
registro IR della Parte Operativa, ed aggiorna il PC perché punti alla prossima istruzione – questa
operazione è chiamata FETCH
2. esegui l’istruzione corrente memorizzata nel registro IR, e torna al passo 1.
Tale ciclo viene eseguito fino alla terminazione del programma (istruzione halt).
Ai fini della realizzazione della UC è pertanto necessario progettare la “logica” che implementa il ciclo della
CPU. Ciò richiede la definizione dei microprogrammi che ne definiscono i vari passi, in particolare, il
microprogramma del FETCH (passo 1) e i microprogrammi delle istruzioni del linguaggio macchina (passo 2).
NOTA: durante l’esecuzione di una istruzione del linguaggio macchina, tale istruzione è memorizza nel
registro IR
STORE x
• m1: IR3-14 à MAR; : Acc à MDR
• m2: WriteMem // MDRàM[MAR]
7
LOAD x
• m3: IR3-14 à MAR
• m4: ReadMem (cioè M[MAR]àMDR)
• m5: MDR à Acc
ADD x
• m6: Acc à T0 ; IR3-14 à MAR
• m7 : ReadMem
• m8 : MDR à T1
• m9: Alu(T0+T1) à Acc
SUB x
• m10: Acc à T0 ; IR3-14 à MAR
• m11 : ReadMem
• m12 : MDR à T1
• m13: Alu(T0-T1) à Acc
JUMP x
• m14: IR3-14 à PC
JZ x
• m15: If βAcc == 0 IR3-14 à PC
HALT
• m16: Ø // istruzione vuota
• m16: PC à MAR
• m17: ReadMem; PC = PC+2;
• m18: MDR à IR
Si noti che il PC viene incrementato di una quantità pari a 2 per “puntare” alla cella successiva che contiene
la prossima istruzione del programma nella RAM. Tale incremento viene effettuato in parallelo alla
ReadMem in quanto non vi è “interferenza” tra le due microistruzioni (non vi è ragione perché una preceda
l’altra ed inoltre la loro esecuzione coinvolge componenti diversi dell’architettura).
8
CICLO DELLA CPU
Esegui il microprogramma del Fetch - sia IS l’istruzione trasferita in IR
While IS <> halt
1. Esegui il microprogramma associato a IS
2. Esegui il microprogramma del Fetch; sia IS l’istruzione trasferta in IR
End
Una volta che l’istruzione IS da eseguire è stata trasferita nel registro IR tramite il FETCH, iI suo
riconoscimento avviene attraverso il codice operativo. A tal fine, i tre bit I0, I1, I2 più a sinistra di IR (che
codificano il Codice Operativo di IS) vengono inviati all’UC (vedi Figura 1). Questa, sulla base dei valori di I0, I1,
I2, procede all’esecuzione del microporgramma MP di IS, inviando alla Parte Operativa (PO) una sequenza di
segnali di controllo che codificano la sequenza delle miscroistruzioni di MP.
Così come per le istruzioni del linguaggio macchina, anche l’esecuzione del FETCH richiede l’esecuzione del
relativo microprogramma. A tal fine, si può assimilare il FETCH alle altre istruzioni del linguaggio macchina,
e gli si assegna un codice operativo, ad esempio 000.
Per “forzare” l’esecuzione del FETCH è quindi necessario, di volta in volta, azzerare i tre bit I0, I1, I2 nel
registro IR. Il valore 000 del codice operativo viene infatti interpretato dall’UC come una richiesta di
esecuzione del relativo microporgramma (così come, ad esempio, il codice operativo 001 viene interpretato
come una richiesta di esecuzione del microporgramma del LOAD). Più precisamemnte, l’azzeramento di IR
deve avvenire
• quando il programma P viene caricato nella RAM (passo 1 del Cilco della CPU)
• alla fine della esecuzione di ogni singola istruzione di P (passo 2 del Cilco della CPU). A tale scopo, basta
estendere il microprogramma di ogni istruzione del linguaggio macchina con un comando finale di
azzeramento del registro IR.
Nella seguente tabella è riportata la versione finale dei microprogrammi.
9
Alla luce di quanto appena detto, possiamo codificare il ciclo della CPU come segue:
10
o si parte dal microprogramma più lungo (quello associato alla istruzione ADD o SUB). S0 è lo stato nel
quale l’UC si trova all’inizio ed alla fine della esecuzione di ogni singola istruzione. Quando I0=0, I1 = 1 e
I2=1, ad esempio, l’UC “sa” di dover eseguire l’istruzione ADD. Pertanto, il sistema evolve nello stato S1
(indipendentemente dal valore di βACC) inviando alla PO i segnali di controllo che codificano la
microistruzione m6 (prima microistruzione del microprogramma di ADD); poi passa nello stato S2,
eseguendo la microistruzione m7, ecc. ecc. Una volta eseguita la microistruzione AzzeraIR, l’automa
torna nello stato S0. Questa parte del grafo delle transizioni consta di 4 stati (S0-S3)
o Utilizzando un sottoinsieme dei suddetti stati S0-S3, si rappresentano anche i microprogrammi delle
altre istruzioni. Ad esempio, il grafo delle transizioni per ADD e FETCH è riportato nella seguente figura
– si lascia per esercizio la rappresentazione delle altre istruzioni.
Quando un nuovo programma P viene caricato nella RAM per l’esecuzione, l’avvio del ciclo della CPU avviene
1. Ponendo l’indirizzo della RAM che contiene la prima istruzione di P nel registro PC
2. Azzerando il registro IR al fine di forzare il FETCH della prima istruzione
3. Mettendo la UC nello stato iniziale S0.
11
La parte combinatoria dell’UC è una rete con 6 variabili d’ingresso (I0, I1, I2 e β, più le 2 variabili di anello) e
22 uscite (i 19 segnali di controllo per la Parte Operativa più le 3 variabili di anello). Il comportamento
ingresso-uscita di tale rete si evince facilmente dal grafo delle transizioni
Unità di Controllo
I0
I1 19
I2 PO
β
clock
Il segnale di clock sincronizza il funzionamento del sistema. Il passaggio da uno stato all’altro dell’UC
avviene tra un impulso di clock ed il successivo. In tale intervallo di tempo, la PO esegue una
mocroistruzione. Ne consegue che la velocità di esecuzione della CPU è pari ad una microistruzione per ogni
ciclo di clock. Pertanto, un processore con un clock, ad esempio, di 1 GHz, esegue un miliardo di
microistruzioni al secondo.
ROM
64 x 21
s1
s0
OR OR ........ OR OR
12
La ROM può essere vista come una memoria che memorizza la rappresentazione tabellare dell’automa
descritto nel paragrafo precedente. In particolare, una memoria che contiene 26=64 locazioni (quante sono le
uscite del decondificatore) in ognuna delle quali sono memorizzati i 19 bit di controllo che codificano le
microistruzioni e i due bit s’0 e s’1 che codificano lo stato futuro. I 6 bit in ingresso (I0, I1, I2 e β, s0 e s1)
possono essere interpretati come l’indirizzo di una particolare microistruzione memorizzata nella ROM. Ad
esempio, (0,0,0,0,0,0) è l’indirizzo della microistruzione m1, (0,0,0,0,0,1) della microistruzione m2, etc.
Quindi, il microporgramma del FETCH è, ad esempio, memorizzato agli indirizzi (0,0,0,0,0,0), (0,0,0,0,0,1),
(0,0,0,0,1,0), etc.
Come si può vedere nella precedente tabella, all’interno di ogni microprogramma, il passaggio da una
micrositruzione alla successiva è determinata dai valori delle variabili di stato s’0 e s’1 che, andando in
ingresso al decodificatore (vedi schema architetturale sopra), generano l’indirizzo della prossima
miscroistruzione (a parità di codice operativo della istruzione in esecuzione). Si noti anche che nell’ultima
microistruzione di ogni microporgramma le variabili di stato valgono entrambe zero; in tal modo, il FETCH
successivo partirà dalla prima microistruzione m1.
Si noti infine che il contenuto della ROM è largamente inutilizzato, in quanto non tutti i 64 indirizzi
(configurazioni dei segnali di ingresso) vengono sfruttati (le microistruzioni sono infatti solo 21, ed ognuna
di esse corrisponde ad un indirizzo).
8 Dispositivi di I/O
Un sistema reale è equipaggiato con un insieme di dispositivi di I/O attarverso i quali scambia dati con il
mondo esterno. Una rappresentazione semplificata dell’architettura è riportata nella seguente figura. Ogni
dispotivo ha un indirizzo che viene caricato dal processore nel registro RIND quando il dispositivo deve
utilizzato. Tale indirizzo viene poi fornito in input ad un decodifivcatore che provvede ad attivare il
dispositivo selezionato.
13
Per l’utilizzo di tali dispositivi, estendiamo il linguaggio macchina tramite due istruzioni aggiuntive:
• READ x: trasferisci nell’accumulatore il dato introdotto dall’esterno dal disposiitivo di ingresso x – dato
contenuto del registro RDATA x
• WRITE x: scrivi il contenuto dell’accumulatore mediante l’unità di uscita x
L’interazione tra il processore ed i dispositivi di I/O è condizionata dal fatto che questi ultimi sono
normalmente molto più lenti. Per gestire questa situazione, si usano due tecniche: I/O programmato e I/O
ad interruzione.
Nel caso di I/O programmato, il processore deve attendere che il dato letto da un dispositivo di lettura D sia
effettivamente disponibile. A tal fine, D mette in uscita un segnale pronto che indica quando il dato è
disponibile (vedi figura). Analogamente, quando il processore deve scrivere un dato mediante un dispositivo
di uscita D, attende il segnale pronto da D prima di inviare il dato (per evitare che ci siano sovrascritture).
Bus dati
RDATA 1 RDATA n
CPU RAM …
DECODER
σ
AND RIND
Bus indirizzi
Di seguito riportiamo i microprogrammi delle due istruzioni di I/O nel caso di I/O programmato.
READ x;
1. IRx à RIND;
2. if σ == 0 Ø goto 2
3. RDATAx à Acc
WRITE x
4. IRx à RIND;
5. if σ == 0 Ø goto 5
6. Acc à RDATAx
7. Stampa
Nei suddetti microporgrammi, σ rappresenta un nuovo segnale di condizione per l’Unità di Controllo. Esso è
pari ad 1 quando il dispositivo selezionato è pronto ad interagire con il processore. In attesa che ciò avvenga,
il processore si mette in attesa (vedi cicli alle linee 2 e 5).
Da quanto detto risulta evidente che l’I/O programmato introduce inefficienza, in quanto il processore è
costretto ad attendere (senza far nulla) la disponibilità di un dispositivo molto più lento.
14
La tecnica dell’I/O ad interruzione, utilizzata in quasi tutti i sistemi reali, consente viceversa al processore di
dedicarsi ad altri calcoli mentre il dispositivo di I/O opera.
9 Conclusioni
Un programma P in esecuzione è una sequenza di istruzioni del linguaggio macchina <IS1, IS2, …, ISn>
memorizzate nella RAM. L’esecuzione di P richiede l’esecuzione di ogni singola istruzione nella sequenza
data. Ciò è a carico della CPU (processore), un circuito logico che funge da interprete del linguaggio
macchina. A tal fine, il compito del processore è essenzialmente quello di eseguire il cosiddetto Ciclo della
CPU:
1. Reperisci in memoria la prossima istruzione da eseguire e portala nel registro IR. A tal fine, viene
lanciata l’esecuzione del microporgramma del FETCH
2. Esegui l’istruzione nell’IR lanciando l’esecuzione del rispettivo microprogramma; torna al passo 1.
L’esecuzione del FETCH (1) inizializza l’esecuzione del programma P, e (2) si inserisce tra la fine di ogni
istruzione e la successiva. L’esecuzione di P può quindi essere vista come l’esecuzione di una sequenza di
microporgrammi <MP(F), MP(IS1), MP(F), …, MP(F), MP(ISk), MP(F) ..>, dove MP(F) è il microprogramma del
FETCH e MP(ISk) è il microprogramma della istruzione ISk (si noti che, a causa della presenza di cicli, la
stessa istruzione può essere eseguita più volte).
Un processore genel purpose è pertanto un sistema di eleborazione in grado di eseguire un unico algoritmo,
per l’appunto, il Ciclo della CPU. Si dà il caso, tuttavia, che tale algoritmo consenta di interpretare ogni
programma scritto in linguaggio macchina. Pertanto, se il linguaggio macchina è sufficientemente ricco di
istruzioni tale da poter tradurre qualsiasi programma scritto in un linguaggio di alto livello (ad esempio, C o
C++), allora un processore genel purpose è un sistema in grado di eseguire qualsiasi programma (cioè, di
risolvere qualsiasi problema per il quale esista una soluzione algoritmica).
Il Ciclo della CPU ed i microprogrammi sono “cablati” nella logica dell’automa a stati finiti che rappresenta
l’UC. Questa è una rete sequenziale che interpreta ogni istruzione del linguaggio macchina tramite
l’esecuzione del suo micro-programma. La sintesi dell’UC può essere realizzata con una ROM. In tal caso, la
ROM può essere vista come una memoria nella quale sono memorizzati, in maniera permanente, i
microporgrammi. Pertanto, l’esecuzione di P (che risiede nella RAM) può essere vista come una sequenza di
chiamate a procedure cablate nella ROM dell’UC.
15