Personal computer/Linguaggio Macchina/DLX/DLX sequenziale
Datapath sequenziale
[modifica | modifica sorgente]La funzione fondamentale dell'unità di controllo è la lettura degli operandi dal banco dei registri (R0 - R31), la loro trasformazione all'interno della ALU e la rimemorizzazione del risultato.
Il processore DLX utilizza tre bus: S1, S2, e Dest, i primi due sono di ingresso per la alu e sono pilotati dai registri dell'unità di calcolo, il bus Dest, invece, funziona come uscita per la ALU e ingresso per i registri.
Dato che il banco dei registri non viene letto o scritto ad ogni ciclo di clock per velocizzare queste operazioni nell'unità di controllo sono presenti degli elementi di memoria alle due uscite del banco di registri (elementi A e B) ed uno in ingresso ( C )
Oltre ai 32 registri già visti vi sono anche i registri:
- PC: Program counter o contatore di programma
- IAR: registro di indirizzamento delle interruzioni, registro che fa parte dello stato della macchina
- MAR: registro di indirizzamento della memoria,
- MDR: registro di lettura e scrittura della memoria,
- IR: registro delle istruzioni
- Temp: registro temporaneo detto a perdere perché è disponibile per la memorizzazione dei dati intermedi durante l'esecuzione di alcune istruzioni del DLX.
Fasi di esecuzione delle istruzioni
[modifica | modifica sorgente]Le istruzioni tipiche del DLX viste nei paragrafi precedenti sono tutte eseguite in più cicli di clock, volendo scomporre ogni istruzione in micro-operazioni si osserva come tutte le operazioni del DLX ( ad esclusione di quelle in virgola mobile) siano scomponibili in cinque fasi fondamentali:
- prelievo dell'istruzione
- decodifica
- esecuzione ed indirizzamento
- accesso alla memoria
- scrittura del risultato
Prelievo dell'istruzione
[modifica | modifica sorgente]Il Datapath, a partire dal valore del PC, preleva l'istruzione da eseguire dalla memoria scrivendola nel registro delle istruzioni:
MAR <- PC; IR <- M[MAR]
Il contenuto del PC deve essere trasferito nel MAR visto che soltanto quest'ultimo è collegato alla memoria, mentre il PC non lo è
Decodifica
[modifica | modifica sorgente]Viene decodificata l'istruzione e contemporaneamente si accede al banco dei registri per leggerli, i valori dei registri saranno salvati nei due elementi di memoria, viene inoltre incrementato il PC
A <- Rs1; B <- Rs2; PC <- PC + 4
La decodifica dell'operazione può avvenire in parallelo con la lettura dai registri soltanto perché la posizione dei registri sorgente all'interno di una istruzione DLX è fissa dopo i 6 bit del codice operativo, si parla di decodifica a campi fissi. Per lo stesso motivo anche l'estensione in segno del valore immediato viene effettuata in questa fase qualora l'istruzione contenga un valore immediato
Esecuzione e indirizzamento
[modifica | modifica sorgente]L'ALU elabora gli operandi decodificati nella fase precedente eseguendo una delle possibili funzioni:
Riferimento alla memoria
[modifica | modifica sorgente]L'ALU calcola l'indirizzo effettivo della cella di memoria e viene inizializzato il registro MDR per un'operazione di memorizzazione
MAR <- A + (IR16)16##IR16..31 MDR <- Rd
Funzione dell'ALU
[modifica | modifica sorgente]L'ALU esegue l'operazione specificata dal codice operativo con operandi Rs1 (A) e Rs2 (B) oppure con il valore immediato esteso di segno
C <- A op ( B or (IR16)16##IR16..31 )
Diramazione o salto
[modifica | modifica sorgente]L'ALU calcola l'indirizzo del salto sommando al PC il valore immediato esteso in segno, viene anche controllato un registro per decidere se l'indirizzo va caricato o meno nel PC ( è il caso delle diramazioni )
C <- PC + (IR16)16##IR16..31; cond <- (A op 0)
op è l'operatore di relazione specificato dal codice operativo ( BEQZ -> op = EQual ovvero "==" ) Le istruzioni JAL e TRAP sono simili a quella descritta ma in più memorizzano l'indirizzo di ritorno rispettivamente in R31 e IAR.
Accesso alla memoria
[modifica | modifica sorgente]Questa fase è attraversata soltanto dalle istruzioni di caricamento, memorizzazione, salti e diramazioni.
Caricamento
[modifica | modifica sorgente]Se richiesto l'accesso in memoria il datapath preleva i dati all'indirizzo calcolato in precedenza
MDR <- M[MAR]
Memorizzazione
[modifica | modifica sorgente]Se l'istruzione è una memorizzazione i dati vengono scritti
M[MAR] <- MDR
Diramazione / Salto
[modifica | modifica sorgente]Se si verifica la condizione calcolata nella fase precedente il contenuto del PC viene sostituito con l'indirizzo di destinazione della diramazione
if (cond) PC <- C
Per i salti incondizionati cond è sempre vera
Scrittura del risultato
[modifica | modifica sorgente]Il risultato in uscita alla ALU viene scritto nel banco dei registri, sia che provenga dalla memoria
Rd <- MDR
che dalla ALU
Rd <- C
Unità di controllo per il DLX
[modifica | modifica sorgente]L'unità di controllo è la parte della CPU che si occupa di indicare all'unità di calcolo le micro-operazioni da eseguire ad ogni ciclo di clock durante l'esecuzione delle istruzioni.
Solitamente si usa un diagramma a stati finiti per specificare le attività svolte dall'unità di calcolo, in questo diagramma ogni stato corrisponde ad un ciclo di clock e le operazioni eseguite sono inserite all'interno dello stato.
La prima fase di esecuzione di una istruzione è distribuita nei primi tre stati del diagramma.
La seconda fase viene eseguita nel terzo stato
- durante il primo ciclo di clock il valore del PC viene caricato nel registro di indirizzamento della memoria,
MAR <- PC
- nel secondo stato il registro delle istruzioni viene caricato dalla memoria
IR <- M[MAR]
- nel terzo stato viene incrementato il PC e vengono, durante lo stesso ciclo di clock, caricati i due operandi dei registri Rs1 e Rs2 in A e B
PC <- PC + 4 A <- Rs1 B <- Rs2
Lo stato successivo del diagramma differisce a seconda che si stia facendo un trasferimento dati, un'operazione ALU, una inizializzazione un salto o diramazione
Si possono anche rappresentare i primi due stati con uno solo
IR <- M[PC]
ricordando che in condizioni ideali l'operazione richiede due cicli di clock.
I clock necessari per eseguire l'operazione di caricamento del registro IR dipendo fortemente dai tempi di accesso alla memoria, che possono richiedere più di un clock, per cui si indica il primo stato come stabile su se stesso fintanto che l'accesso alla memoria è incompleto
N.B.: L'aver ridotto i primi due stati ad un singolo stato (IR <- M[PC]) implica la necessità di effettuare un collegamento a livello circuitale tra la porta indirizzi della memoria(RAM) e il registro PC(Program Counter). Normalmente,infatti,l'unico registro ad essere collegato a tale porta è il MAR(Memory Address Register) e quindi,senza prevedere questo ulteriore collegamento circuitale, l'unico modo per effettuare un indirizzamento in memoria a un indirizzo contenuto nel PC è quello di passare tale contenuto preventivamente nel MAR; questa operazione di passaggio del dal PC al MAR avviene attraverso l'ALU. Avendo optato per la soluzione di uno doppio collegamento alla porta indirizzi della RAM (PC e MAR) si renderà,inoltre,necessario un maggiore controllo da parte della Control Unit(CU),la quale ora, dovrà specificare da quale dei due registri(PC o MAR) si dovrà prelevare l'indirizzo a cui fare riferimento.Normalmente ciò si realizza circuitalmente con un Multiplexer con due ingressi collegati uno al PC e l'altro al MAR e una uscita collegata alla porta indirizzi della memoria.
Controller per le istruzioni di memoria
[modifica | modifica sorgente]Sia per le istruzioni di caricamento che memorizzazione il primo stato (dopo i tre comuni a tutti i controller visti prima) è
MAR <- A + (IR16)16 ## IR16..31
viene quindi calcolato il registro di indirizzamento alla memoria, la fase successiva differisce a seconda che si tratti di
controller Caricamento
[modifica | modifica sorgente]MDR <- M[MAR]
Viene prelevata l'informazione dalla memoria e
C <- MDR
inserita nell'elemento di memoria C, quest'ultima operazione si riferisce al casi di Load Word, infatti il MDR conterrà 32 bit, se l'operazione di caricamento opera con Half Word, Byte o dati diversi si selezionano dal MDR soltanto i bit richiesti
LB C <- (MDR24)24 ## MDR24..31 LBU C <- (0)24 ## MDR24..31 LH C <- (MDR16)16 ## MDR16..31 LHU C <- (0)16 ## MDR16..31
Al successivo clock il valore dell'elemento di memoria riempie il registro di destinazione
Rd <- C
Dopo questa micro-operazione il diagramma degli stati ritorno all'inizio con il prelevamento di una istruzione dalla memoria
controller Memorizzazione
[modifica | modifica sorgente]MDR <- B
Il dato da memorizzare viene inserito nell'apposito registro
M[MAR] <- MDR
e scritto in memoria all'indirizzo precedentemente calcolato, questo stato è stabile fino a che l'accesso in memoria non sia completo, può quindi richiedere più clock
Controller per le istruzioni ALU
[modifica | modifica sorgente]Nelle istruzioni ALU l'operazione indicata dall'op code viene eseguita tra l'elemento di memoria A e il registro Temp, per cui il primo blocco consiste nel riempire questo registro con il secondo elemento di memoria ( B ) se si tratta di una operazione tra registri, andrà invece riempito con l'immediato (esteso di segno a 32 bit) se l'operazione da eseguire è di tipo I
Registro Temp <- B Immediato Temp <- IR0..15##(IR15)16 Immediato senza segno Temp <- IR0..15 ## (0)16
Dopo di che viene eseguita la micro-operazione corrispondente al codice operativo specificato
ADD C <- A + Temp AND C <- A & Temp SUB C <- A - Temp OR C <- A | Temp
Ed il risultato viene scritto sul registro destinazione
Rd <- C
Controller per l'istruzione di salto
[modifica | modifica sorgente]JR
[modifica | modifica sorgente]PC <- A
Essendo un'istruzione di ritorno deve solo aggiornare il PC
PC <- PC + IR0..25 ## (IR25)6
Modifica il program counter con l'immediato
JAL
[modifica | modifica sorgente]C <- PC PC <- PC + IR0..25 ## (IR25)6 R31 <- C
Prima di sovrascrivere il PC ne salva il valore in R31
JALR
[modifica | modifica sorgente]C <- PC PC <- A R31 <- C
Controller per l'istruzione di inizializzazione
[modifica | modifica sorgente]O anche istruzioni di set
La prima micro-operazione è la copia nel registro Temp del valore del secondo operando
Registro Temp <- B Immediato Temp <- IR0..15 ## (IR15)16
Al successivo ciclo di clock viene eseguita l'operazione di confronto, per cui
SEQ A == Temp SNEQ A != Temp SLT A < Temp SGE A >= Temp SGT A > Temp SLE A <= Temp
Nel diagramma degli stati a questo punto si ha una diramazione a seconda del risultato del precedente confronto
vero C <- 1 falso C <- 0
L'ultima operazione è quella di scrivere il contenuto di C nel registro destinazione
Rd <- C
Controller per l'istruzione di branch
[modifica | modifica sorgente]I branch sono di due tipi
BEQZ A == 0 BNEZ A != 0
E la diramazione che ne segue comporta il ritorno all'inizio del datapath in caso di esito negativo, oppure di aggiornamento del PC in caso di esito positivo
PC <- PC + IR0..15 ## (IR15)16
Altri esempi di controller
[modifica | modifica sorgente]Supponiamo di voler creare una nuova istruzione DLX del tipo
CMPS Rx, Ry, Rz
L'istruzione confronta il dato di tipo unsigned byte situato in memoria all'indirizzo Rx con quello all'indirizzo Ry e pone Rz a 1 se i due dati sono uguali
Una descrizione RTL delle operazioni svolte dalla nuova istruzione è data da:
if (M[Rx] = M[Ry]) then Rz <- 1 else Rz <- 0;
Il controller (datapath) di questa nuova istruzione, compresi gli stati di fetch e decodifica, sarà
IR <- M[PC] ; fetch dell'istruzione
A <- Rx B <- Ry ; decodifica PC <- PC + 4
MAR <- A ; preparo il registro di accesso alla memoria
MDR <- M[MAR] ; ed accedo
Temp <- MDR0..7 ## (0)24 ; Salvo soltanto i primi 8 bit (unsigned byte) nel registro temporaneo
MAR <- B ; e mi preparo a prelevare anche B
MDR <- M[MAR] ; lo prelevo
Temp == MDR0..7 ## (0)24 ; e lo confronto con temp
uguali C <- 1 ; se i dati prelevati dalla memoria sono uguali diversi C <- 0 ; oppure diversi, l'unità di calcolo eseguirà solo una delle due istruzioni
Rz <- C ; scrivo il valore calcolato nel registro destinazione
Ogni blocco rappresenta un ciclo di clock, ad esclusione di quelli che accedono alla memoria per i quali la durata dipende dal tempo di accesso alla memoria
Numero di clock necessari per eseguire le istruzioni
[modifica | modifica sorgente]Il numero di cicli di clock per eseguire una qualsiasi istruzione del DLX si ottiene contando gli stati del controller per ogni istruzione, il valore reale dipende poi dal numero e dalla durata degli accessi alla memoria, la seguente tabella riassume il numero di cicli di clock e il numero degli accessi alla memoria per le istruzioni del DLX nel caso in cui l'accesso alla memoria duri 1 clock
Istruzione | Numero minimo
di clock |
Accessi alla
memoria |
---|---|---|
Caricamento | 6
|
2
|
Memorizzazione | 5
|
2
|
ALU | 5
|
1
|
Inizializzazione | 6
|
1
|
Jump | 3
|
1
|
Jump and link | 5
|
1
|
Branch taken
(eseguito) |
4
|
1
|
Branch not taken | 3
|
1
|
Qualora l'accesso alla memoria duri più cicli di clock, questi andrebbero moltiplicati al numero di accessi alla memoria e sommati al numero minimo di cicli di clock, in questo caso si parla di cicli di stallo della memoria o stati di attesa o wait. In macchine dotate di cache i cicli di wait valgono zero ( l'accesso alla memoria cache richiede quindi un solo clock )
Calcolo del CPI
[modifica | modifica sorgente]Supponiamo di avere un programma che esegue le seguenti operazioni con frequenza relativa:
Caricamento 21 % Memorizzazione 12 % ALU 37 % Inizializzazione 6 % Jump 2 % Jump an link 0 % Branch taken 12 % Branch not taken 11 %
Il CPI medio, ricordando la formula data nel primo capitolo, si ottiene sommando i prodotti tra il CPI di ogni istruzione (secondo la tabella sopra riportata e gli stati di wait) e la sua frequenza relativa, in questo esempio il CPI medio risulta 6,28