Personal computer/Linguaggio Macchina/DLX/DLX sequenziale

Wikibooks, manuali e libri di testo liberi.
Indice del libro

Datapath sequenziale[modifica]

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]

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]

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]

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]

L'ALU elabora gli operandi decodificati nella fase precedente eseguendo una delle possibili funzioni:

Riferimento alla memoria[modifica]

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]

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]

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]

Questa fase è attraversata soltanto dalle istruzioni di caricamento, memorizzazione, salti e diramazioni.

Caricamento[modifica]

Se richiesto l'accesso in memoria il datapath preleva i dati all'indirizzo calcolato in precedenza

  MDR <- M[MAR]

Memorizzazione[modifica]

Se l'istruzione è una memorizzazione i dati vengono scritti

  M[MAR] <- MDR

Diramazione / Salto[modifica]

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]

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]

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]

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]

  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]

  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]

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]

JR[modifica]

  PC <- A

Essendo un'istruzione di ritorno deve solo aggiornare il PC

J[modifica]

  PC <- PC + IR0..25 ## (IR25)6

Modifica il program counter con l'immediato

JAL[modifica]

  C <- PC
  PC <- PC + IR0..25 ## (IR25)6
  R31 <- C

Prima di sovrascrivere il PC ne salva il valore in R31

JALR[modifica]

  C <- PC
  PC <- A
  R31 <- C

Controller per l'istruzione di inizializzazione[modifica]

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]

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]

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]

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]

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