ALU a 1 bit

Un ALU, acronimo di Arithmetic Logic Unit ovvero Unità Aritmetico-Logica, ovvero una scatola che consente di eseguire sia operazioni logiche che aritmetiche.

La nostra ALU a 1 bit
...

La nostra ALU consentirà di effettuare le operazioni di AND, OR e somma.
Il nostro circuito dovrà scegliere quale operazione dovrà effettuare, ogni operazioni ha un codice, diciamo che l'AND è riconosciuto da 00, OR da 01 e che la somma sia riconosciuta da 10.
Per poter rappresentare questi codici sono necessari due bit.

OperazioneCodice
AND00
OR01
SUM10
???11

Avremmo la possibilità di rappresentare un'altra operazione, ma al momento ignoriamo una eventuale operazione con codice 11.

Mettendo insieme tutto ciò che abbiamo studiato fino ad ora, cosa può esserci utile?

  • Un multiplexer per selezionare l'operazione da effettuare, in particolare tale multiplexer avrà due linee di controllo, poiché i codici operativi sono su due bit;
  • una porta AND per l'operazione di AND;
  • una porta OR per l'operazione di OR;
  • un addizionatore per effettuare la somma.

Come abbiamo già ribadito, le linee di un circuito logico "vanno sempre avanti", la nostra ALU, dati due bit in input, eseguirà contemporaneamente tutte le operazioni per cui è progettata, ma grazie al multiplexer verrà mandata in uscita solamente l'operazione selezionata.

Posizioniamo le porte che eseguiranno le operazioni: l'AND, l'OR e l'addizionatore
...

photo_2023-05-29_18-01-22.jpg
Adesso il nostro circuito è in grado di eseguire le operazioni desiderate, tuttavia non abbiamo ancora scelto quale fra tutte restituire in output.
Ovviamente, posizionando l'addizionatore è necessario anche inserire un bit per il riporto in entrata.

Aggiungiamo il multiplexer
...

photo_2023-05-29_18-07-55.jpg
I bit operation in entrata nel multiplexer è di 2 bit, come abbiamo detto poc'anzi, il motivo è che bisogna prendere una scelta fra 3 e 2 bit ci consentono di portare a termine questo obiettivo.

ALU in serie
...

Per l'intuizione accennata nel file sugli addizionatori, possiamo collegare in serie ALU ad un bit per ottenere ALU a diversi bit, per esempio a 64 bit. I bit di operation sono condivisi tra tutte le ALU, in modo che l'operazione che viene mandata in uscita sia la stessa per tutte le ALU.

Pasted image 20230529181344.png

Estendiamo la nostra ALU per far si che supporti anche la sottrazione
...

Implementeremo la sottrazione come una somma, infatti sappiamo che .
Quindi per calcolare la differenza tra due bit dobbiamo invertire uno dei due operandi, diciamo b.

Problema

In decimale l'inverso di 1 è -1, quindi invertire un numero è estremamente facile. In binario puro l'inverso di 01 è 11, quindi sarebbe sufficiente invertire il bit più significativo. Nei calcolatori è utilizzata la notazione in complemento a 2, quindi ciò che bisogna fare è:

  • invertire tutti bit
  • sommare 1

photo_2023-06-01_11-35-56.jpg

Abbiamo aggiunto un multiplexer con un bit (bitinvert) che non è altro che un bit di selezione per il multiplexer. Quando bitinvert = 0 b non viene invertito, mentre se bitinvert = 1 b viene invertito.
Deve succedere che quando bitinvert = 1 e quindi quando deve essere invertito b, deve essere anch'esso uguale 1, poiché dobbiamo invertire un bit in complemento a 2 (dunque sommare dopo l'inversione 1).

Succede che:

BitinvertCarryIn
00
11

bitinvert e CarryIn sono sempre uguale, quindi possiamo tenerne solo uno e collegarlo sia all'addizionatore che al multiplexer per invertire b.

photo_2023-06-01_11-35-55.jpg

Estendiamo ancora l'ALU: aggiungiamo la possibilità di fare l'operazione NOR
...

L'operazione NOR è l'operazione opposta dell'OR.

ABNOR
001
010
100
110

Per le leggi di De Morgan, la NOR:
Quindi la NOR è implementabile come l'AND di due bit negati, abbiamo già il multiplexer per negare il bit b, ne aggiungiamo un altro per negare a.

Attenzione

Per fare la NOR, facciamo la AND di due bit NEGATI, non invertiti, quindi in questa circostanza verrà mandata in uscita l'operazione 01 ovvero l'AND.

photo_2023-06-01_11-35-53.jpg
Quando si vorrà fare la NOR, verranno negati entrambi i bit (a e b) e l'operazione che verrà mandata in uscita è la 01, ovvero l'AND.

Estendiamo l'ALU: aggiungiamo l'operazione slt
...

L'operazione slt: set on less than restituisce 1 se rs1 < rs2 e 0 altrimenti.
Con rs1 e rs2 ci riferiamo ai registri degli operandi di RISC-V.

Quindi vogliamo aggiungere un operatore che ci consenta di stabilire se un numero è strettamente minore dell'altro:

  • se il numero è strettamente minore verrà ritornato: 1
  • altrimenti 0

Avendo un n bit quindi quello che vedremo saranno nel primo caso, n-1 bit e l'n-esimo posto a 1, altrimenti tutti i bit posti a 0.

L'idea che vogliamo sfruttare per implementare questa operazione è la sottrazione e in particolare: avendo 2 numeri, diciamo e , come possiamo dire se a è strettamente minore di ?
, quindi 38 è strettamente minore di 40, dunque:
se allora .

Come controllare se (a - b) è negativo?

Verifichiamo che il bit più significativo della sottrazione tra a e b valga 1.

Prima di tutto aggiungiamo al multiplexer delle operazioni, l'operazione 11 (la quarta, che non avevamo ancora considerato).

photo_2023-06-01_11-35-54.jpg

Nell'operazione SLT so che dovrò restituire 1 (0...01) oppure 0 (0...0). Quello che può cambiare è il bit meno significativo che potrebbe anche essere 1.
L'ALU che abbiamo sviluppato è ad un solo bit. Questo vorrà dire che per implementare la funzione SLT per n bit, dobbiamo avere n ALU. Il punto è che, le prime n-1 ALU dovranno mandare verso l'uscita il bit 0, mentre l'ultima ALU dovrà mandare verso l'uscita 1 se la sottrazione ha restituito un numero negativo, 0 altrimenti.
Nell'ALU sopra abbiamo aggiunto al multiplexer, l'operazione 11 per SLT. Quando SLT sarà impostata nel multiplexer, verrà mandato in uscita il bit che è impostato nell'input Less, che sarà sempre 0 per le prime n-1 ALU.

L'n-esima ALU invece sarà così fatta:
photo_2023-06-01_11-50-36.jpg
A questo punto l'ALU è stata arricchita anche di un modulo per l'identificazioni di eventuali overflow, di cui discuteremo successivamente.
Inoltre si noti che la linea azzurra non ha un comportamento particolare, ma è stata colorata solo per distinguere meglio le linee del circuito.

Infine, notiamo che questa ALU, per l'n-esimo bit prende il risultato restituito dall'addizionatore. In particolare tiene conto solo di quest'ultimo bit, che è il primo nella sequenza numerica, infatti ricordiamo che un cifra binaria è considerata in questo modo: , questa ALU è quella progettata per il bit 63, se il bit in uscita da set è 0, la sottrazione tra la cifra e la cifra , non è un numero negativo, altrimenti se tale bit è 1, vuol dire che la sottrazione ha restituito un numero negativo.

Ricorda sempre

Le linee del circuito avanzano sempre, cambia solo il risultato che viene mandato effettivamente in uscita. Quindi non è strano che set prende il risultato della somma, che viene comunque eseguito dalla ALU, nonostante il valore mandato in uscita si quello selezionato dal multiplexer per l'operazione 11.

Quindi se :

  • avremo, set = 1 e tutti gli altri bit uguali a 0, in particolare avremo: 10...0
  • altrimenti avremo, set = 0 e tutti gli altri bit uguali a 0, in particolare avremo: 00...0
    ma noi vogliamo restituire 0...01 o 0...00, ovvero nel bit meno significativo.

Quindi come facciamo?
Mandiamo set indietro al bit in posizione 0. Infatti, notate che la selezione nel multiplexer dell'operazione 11 manda in uscita anche nella ALU per l'n-esimo bit il bit less = 0, mentre il bit set viene rimandato alla ALU in posizione 0, come si vede nell'immagine seguente:
Pasted image 20230601122437.png
Notate che se operation = 11 (slt), deve anche essere seguita la sottrazione tra a e b e quindi Bnegate (nell'immagine) deve essere posto a 1. Ogni ALU sputa fuori less = 0, l'ALU numero 63 sputa anch'essa less = 0, ma rispetto alle ALU precedenti tiene conto del bit più significativo risultante dalla differenza tra le cifre a e b, e lo rimanda alla ALU alla 0-esima (bit meno significativo) posizione nella serie.

ALU finale
...

Pasted image 20230601122508.png
Rispetto alla ALU nella versione precedente è stato aggiunto un circuito per il segnale Zero.
Utilizzabile per esempio per controllare se il risultato di una differenza è uguale 0, in modo da poter controllare anche se i registri sono uguali o no, questo ci consente anche le operazioni di controllo come: . Si noti che la porta OR grande, collega i risultati di tutte le ALU ad un bit, ma il collegamento (il pallino pieno nero) è posto prima della freccia, il che vuol dire che il risultato di ogni singola ALU viene mandato in uscita, se viene selezionata l'operazione di slt, allora viene mandato in uscita il risultato della porta Zero.

Vediamo come funzione la rilevazione dell'overflow
...

Nella somma/differenza di due interi con segno in complemento a due, abbiamo overflow se i due operandi (le cifre) hanno lo stesso segno, ma il risultato ha segno opposto.
Possiamo dunque dire che quando il riporto in entrata del bit più significativo e il riporto in uscita di quello stesso bit sono discordi.

Quindi l'overflow mette semplicemente in XOR CarryIn e CarryOut, se sono discordi lo XOR restituisce 1, quindi l'overflow viene rilevato.

Tutte le combinazioni della ALU per eseguire tutte le operazioni
...

bitinvert(A)bitInvert(B)OperationFunzione
0000AND
0001OR
0010add
0110sub
0111set less than
1100NOR

Il simbolo usato per la ALU
...

Pasted image 20230601124559.png
Lo stesso simbolo è usato per gli addizionatori, quindi è bene specificare di che modulo stiamo parlando.

Adesso siamo pronti per passare ai circuiti sequenziali.