RISC: reduced instruction set computer.
CISC: complex set instruction computer.
Le macchine RISC hanno istruzioni più semplici, cioè meno potenti.
Le macchine CISC hanno istruzioni più complesse, cioè più potenti.
La potenza di una istruzione indica "quante cose riesce a fare quella istruzione tutte in una volta".
La complessità ovvero potenza di una istruzione è legata al modo di indirizzamento degli operandi e più in generale a tutto ciò che è di contorno
all'istruzione.
Utilizzando l'indirizzamento implicito, le istruzioni sono poco potenti: ne servono molte per fare anche le operazioni più semplici.
Ad esempio una istruzione di somma è sempre una istruzione che attiva l'opportuno circuito della CPU, ma se ci si riferisce agli operandi implicitamente, allora è meno potente e
più semplice, se al contrario gli operandi sono indicati espicitamente, è più potente e complessa. Nel caso dell'istruzione semplice, bisogna prima portare i due operandi
dalla memoria o dai registri in cui sono ai registri predefiniti; bisogna quindi chiamare l'istruzione ed infine spostare il risultato dal registro in cui viene di default messo, alla memoria o
al registro in cui si intende conservarlo. Per la somma con indirizzamento esplicito, invece, basta una sola istruzione, nella quale vengono contestualmente indicate le posizioni degli operandi e
del risultato.
Per questo, le macchine RISC hanno carenza di modi di indirizzamento e operano direttamente sui registri della CPU e non sulla memoria centrale. Vengono a tal proposito fornite solo due
istruzioni che accedono alla RAM: LOAD e STORE. Con queste si caricaro le celle di memoria su cui si vuole operare nei registri della CPU e si salvano in memoria i risultati ottenuti .
Un'altro degli elementi di contorno è il formato delle istruzioni: nelle macchine CISC può essere variabile (come già visto, questo significa che la lunghezza delle
istruzione può variare di multipli di word), nelle RISC è fisso ed in genere pari ad una word.
Ovviamente esistono macchine intermedie fra RISC e CISC.
I motivi di questa distinzione sono storici:
inizialmente i calcolatori erano RISC perchè più economici e facili da realizzare; allora, infatti, la tecnica costruttiva era ancora molto primitiva e gli elementi utilizzati
erano molto costosi e rari;
si è poi passati a macchine CISC; questo passaggio è stato necessario poichè la tecnica costruttiva era migliorata mentre il costo dei componenti era ancora elevato; si
potevano quindi realizzare macchine più complesse ma ancora con poca memoria; servivano per questo istruzioni molto potenti, così che i programmi occupassero meno spazio
possibile;
con l'economizzazione dei componenti ed ulteriori miglioramenti nella tecnica costruttiva, si è avuta la rinascita di calcolatori RISC; a macchine più semplici, infatti,
corrisponde una maggiore efficienza dovuta proprio alla semplicità architetturale: non utilizzano la microprogrammazione (utilizzando istruzioni semplici, il
codificatore/decodificatore non è complesso), permettono una più semplice ed efficace canalizzazione (le tre fasi di caricamento, decodifica, esecuzione richiedono lo stesso
tempo, visto anche il fatto che la microprogrammazione non è necessaria e perchè è più facile fare in modo che le tre fasi non interferiscano fra loro), sono
più facili da realizzare, molte delle istruzioni complesse delle macchine CISC non vengono quasi mai utilizzate, sono più veloci, permettono una portabilità del codice
più agevole (essendo più semplici delle CISC, permettono ai vari costruttori di realizzare macchine più simili e con set di istruzioni molto vicini fra loro).
Tuttavia, le macchine CISC sono ancora presenti in quantità ed attualmente si ha una coesistenza delle due architettura.
Tutti i computer che utilizzano processori Pentium ed AMD sono CISC, tutti i computer che utilizzano processori Motorola (i computer della Apple) sono RISC.
2. Macchina RISC di esempio
Un esempio di maschera RISC si studia nel Laboratorio di questo corso: MIPS.
3. Macchina CISC di esempio
3.1 Introduzione
Prendiamo come esempio la famiglia di calcolatori PDP 11 della Digital, prodotta negli anni settanta.
Caratteristiche generali:
clock pari ad un Mhz
lunghezza della parola pari a 16 bit, con la possibilità di indirizzare anche metà parola
sistema di interconessione a bus - fu la prima macchina ad implementarlo
memoria centrale di 32k parole organizzata in 4 pagine per un totale di 256 kbyte di spazio
una parte di memoria dedicata allo stack
numeri interi rappresentati in complemento a 2, mentre i naturali in modo standard binario
interruzioni/eccezioni vettorizzate - fu la prima macchina ad implementarlo
Permetteva di gestire più efficientemente le periferiche a quel tempo più utilizzate: i terminali. Allora, infatti, c'era un solo grande calcolatore centrale, detto mainframe,
e tutti gli utenti avevano un proprio terminale che includeva solo un monitor ed una tastiera collegati col mainframe, per poterlo utilizzare. Ogni volta che ad es. su un qualsiasi terminale
veniva premuto un tasto, partiva una interruzione verso il mainframe. Usando interruzioni vettorizzate non c'era bisogno di ricercare chi avesse lanciato l'interruzione, evitando di
rallentare la macchina come succedeva invece con il polling, poichè il segnale di interruzione portava con se il codice univoco del mittente.
8 registri da 16 bit ad uso generico nella CPU, anche se il sesto conteneva il puntatore di catasta ed il settimo era un puntatore al P.C.
un registro di stato detto PSW (processor status word) organizzato come in figura:
N Z V C
TRAP (1 bit)
PRIORITÀ (3 bit)
MODO DI FUNZIONAMENTO (2 bit)
con N, Z, V, e C risultati logici attuali, TRAP t.c. ogni volta che il programmatore lanciava una interruzione si alzava fino al ritorno dal programma di servizio (serviva per il debugging),
PRIORITÀ del processo attuale (da 0 a 7 con 0 il massimo), scritto dal programma in esecuzione, che stabiliva da chi questo poteva accettare interruzioni\eccezioni, MODO DI
FUNZIONAMENTO comprendente tre opzioni: sistema operativo, utente e intermedio; il set di istruzioni veniva modificato non permettendo l'accesso ad istruzioni pericolose (come lo spegnimento
della macchina) all'utente.
l'I\O avveniva tramite l'estenzione all'esterno della memoria centrale
3.2 Modi di indirizzamento
I modi di indarizzamento possibili erano (il numero che li identifica veniva messo nel campo "modo di indirizzamento" delle istruzioni):
modo 0 - a registro: nel registro c'è il dato - notazione: Rn
modo 1 - a registro differito: nel registro c'è l'indirizzo del dato - notazione: (Rn)
modo 2 - ad autoincremento: nel registro c'è l'indirizzo del dato ed ogni volta che si accede al dato l'indirizzo viene incrementato di una parola o di una mezza parola a seconda che
si operi su parole o mezze parole - notazione: (Rn)+
modo 3 - ad autoincremento differito: nel registro c'è l'indirizzo di una cella di memoria in cui si trova l'indirizzo del dato ed ogni volta che si accede al dato l'indirizzo nel
registro viene incrementato di una parola o di una mezza parola a seconda che si operi su parole o mezze parole - notazione: @(Rn)+
modo 4 - ad autodecremento: nel registro c'è l'indirizzo del dato ed ogni volta che si accede al dato l'indirizzo viene decrementato di una parola o di una mezza parola a seconda che
si operi su parole o mezze parole - notazione: -(Rn)
modo 5 - ad autodecremento differito: nel registro c'è l'indirizzo di una cella di memoria in cui si trova l'indirizzo del dato ed ogni volta che si accede al dato l'indirizzo nel
registro viene decrementato di una parola o di una mezza parola a seconda che si operi su parole o mezze parole - notazione: @-(Rn)
modo 6 - ad indice: nel registro si trova un indirizzo di memoria a cui viene sommato un offset (l'indice) per ottenere l'indirizzo del dato - notazione: offset(Rn)
modo 7 - ad indice differito: nel registro si trova un indirizzo di memoria a cui viene sommato un offset (l'indice) per ottenere l'indirizzo di una seconda cella di memoria in cui c'è
il dato - notazione: @offset(Rn)
Sul registro 7 della CPU (P.C.) si potevano utilizzare solo 2,3,6,7.
3.3 Istruzioni a due operandi d'ingresso
Il formato di queste istruzioni era il seguente:
1 bit
3 bit
6 bit
6 bit
Se il primo bit era 1, segnalava che gli operandi erano mezze parole, se era zero segnalava che erano word: come scritto, si potevano indirizzare sia mezze parole che parole e quindi tutte le
istruzioni potevano lavorare sia su mezze parole che su parole intere.
I 3 bit seguenti indicavano l'operazione che si voleva eseguire (codice dell'istruzione), che quindi erano al massimo otto (23).
Nei successivi 6 bit si trovava il primo operando. Questi 6 bit venivano divisi in due parti da 3 bit ogniuna: il modo di indizzamento (infatti c'erano otto modi - 23) ed il registro
a cui si riferiva il modo di indirizzamento (infatti c'erano otto registri nella CPU - 23).
Gli ultimi 6 bit erano analoghi ai precedenti, ma contenevano il secondo operando. Nel caso di operazioni con un valore di ritorno, il risultato veniva messo in questi ultimi 6 bit,
sovrascrivendo il secondo operando.
Le istruzioni avevano i seguenti codici mnemonici:
MOV: spostava una word o mezza word da un posto ad un'altro
CMP: comparava i due opernadi, mettendo il risultato nei bit logici di PSW
BIT: and logico
BIC: mascheramento - azzerava tutti i bit del I operando che corrispondevano agli uno del II opernado (la maschera)
BIS: or esclusivo (xor)
ADD: somma e sottrazione
Tutte queste istruzioni operavano su parole.
Aggiungendo una B alla fine del nome si ottenevano istruzioni operanti su mezze parole.
3.4 Istruzioni ad un operando d'ingresso
Il formato di queste istruzioni era il seguente:
1 bit
9 bit
6 bit
Se il primo bit era 1, segnalava che l'operando era una mezza parola, se era zero segnalava che era di una word: come scritto, si potevano indirizzare sia mezze parole che parole e quindi tutte
le istruzioni potevano lavorare sia su mezze parole che su parole intere.
I 9 bit seguenti indicavano l'operazione che si voleva eseguire (codice dell'istruzione), che quindi erano molte di più delle precedenti (29).
Negli ultimi 6 bit si trovava l'operando. Questi 6 bit venivano divisi in due parti da 3 bit ogniuna: il modo di indizzamento (infatti c'erano otto modi - 23) ed il registro a cui si
riferiva il modo di indirizzamento (infatti c'erano otto registri nella CPU - 23). Nel caso di operazioni con un valore di ritorno, il risultato veniva messo in questi ultimi 6 bit,
sovrascrivendo l'operando.
Le istruzioni avevano i seguenti codici mnemonici:
JMP: salto incodizionato con un offset di 6 bit
SWAB: scambiava le due mezzse parole di una parola fra loro
CLR: azzerava l'operando
COM: ???
INC: incrementava di uno l'operando
DEC: decrementava di uno l'operando
NEG: negava l'operando complementando i suoi bit
ADC: addizionava il riporto di una somma precedente, contenuto nei bit dei risultati logici di PSW;
serviva per addizionare stringhe più lunghe di una word
SBC: sottraeva il prestito di una differenza precedente, contenuto nei bit dei risultati logici di PSW;
serviva per sottrarre stringhe più lunghe di una word
TST: testava la positività o negatività dell'operando rappresentato in Ca2, controllando il MSB; il risultato veniva scritto nei risultati logici in PSW
ROR: shift logico a destra di una posizione (i bit che escivano da un lato rientravano dal lato opposto: serviva per fare operazioni bit a bit)
ROL: shift logico a sinistra di una posizione (i bit che escivano da un lato rientravano dal lato opposto: serviva per fare operazioni bit a bit)
ASR: shift aritmetico a destra di una posizione (i bit che escivano da dx NON rientravano da sn, perchè a sn entrava lo stesso bit che c'era per primo, per mantenere il segno: serviva per
dividere per multipli di due l'operando)
ASL: shift aritmetico a sinistra di una posizione (i bit che escivano da sn NON rientravano da dx, perchè a dx entravano zeri, per mantenere il numero: serviva per moltiplicare per
multipli di due l'operando)
SXT: estendeva il segno per i numeri in Ca2 (ad es. passando da 8 bit a 16 bit, ripeteva a sinistra il bit più significativo fino a coprire tutti i 16 bit della word)
Aggiungendo una B alla fine del nome si ottenevano istruzioni operanti su mezze parole.
3.5 Istruzioni di salto
Il formato di queste istruzioni era il seguente:
8 bit
8 bit
I primi otto bit rappresentavano il codice dell'istruzione, gli ultimi otto bit rappresentavano l'offset (quindi indirizzamento realtivo). Si potevano quindi effettuare salti a +127 e -128
posizioni dal contenuto del P.C. .
Le istruzioni avevano i seguenti codici mnemonici:
BR: salto incodizionato con un offset di 8 bit
BNE: saltava se nel bit Z dei risultati logici di PSW c'era 0 (non uguale)
BEQ: saltava se nel bit Z dei risultati logici di PSW c'era 1 (uguale)
BGE: saltava se maggiore o uguale
BLT: saltava se minore
BGT: saltava se maggiore
BLE: saltava se minore o uguale
BLP: saltava se positivo
BMI: saltava se negativo
BHI: saltava se maggiore o uguale per naturali non in Ca2
BLOS: saltava se minore o uguale per naturali non in Ca2
???: saltava se overflow (Ca2)
???: saltava se trabocco (naturali non in Ca2)
JSR: saltava a subroutine (salvando P.C. nello stack)
RTS: ritornava da subroutine (ripristinando P.C. dallo stack)
3.6 Istruzioni di trap
Il formato di queste istruzioni era il seguente:
8 bit
8 bit
I primi otto bit rappresentavano il codice dell'istruzione, gli ultimi otto bit rappresentavano l'opportuna locazione del vettore delle interruzioni (che quindi aveva 28
posizioni).
Le istruzioni avevano i seguenti codici mnemonici:
EMT: saltava alla specificata locazione del vettore delle interruzioni (salvando registro di stato e P.C.) - veniva raccomandato di non utilizzare questa istruzione perchè riservata alla
casa costruttrice per costruire il software di base
TRAP: come la precedente ma utilizzabile liberamente; separando le due istruzioni si evitavano conflitti fra software di base e programmi utente; nulla vietava cmq di utilizzare EMT
BPT: saltava alla posizione 14 del vettore delle interruzioni, in cui si trovava l'indirizzo del programma di servizio scritto dal produttore che dopo ogni istruzione eseguita da parte del
programma utente interrompeva la macchina (usato per debugging)
IOT: saltava alla posizione 20 del vettore delle interruzioni, in cui si trovava l'indirizzo del programma di servizio scritto dal produttore che gestiva l'I\O con interruzioni
RTI: ritornava dal programma di servizio (ripristinando registro di stato e P.C.)
3.7 Istruzioni di controllo
HALT: arrestava il calcolatore
HOP: perdeva un ciclo di clock senza far nulla (utile per sincronizzazione/temporizzazione)
WAIT: arrestava la macchina in attesa di una interruzione: appena veniva lanciata una qualsiasi interruzione, il calcolatore ripartiva
RESET: metteva a zero tutti i registri sia interni al calcolatore che della periferia
3.8 Istruzioni a formato variabile
Non esistono istruzioni "native" a formato variabile.
Si è detto tuttavia che il settimo registro della CPU era un puntatore al P.C. .
Questo permetteva di creare istruzioni a formato variabile per realizzare gli indirizzamenti assoluto e immediato. Analizzando le istruzioni sinora trattate, infatti, si nota che questi due tipi
di indirazzamento non erano possibili, poichè nel campo dell'istruzione contenente gli operandi non ci sarebbe stato sufficiente spazio per mettere direttamente il valore di questi
(sarebbero serviti 16 bit per ogni operando).
Ad esempio scrivendo: ADD (R1), (R2)
gli operandi non erano contenuti nella word di ADD, dove si trovavano, invece, soltanto i nomi dei registri che li contenevano.
Scrivendo: ADD (R7)+, (R7)+
veniva comunicato alla macchina che gli operandi si trovavano nelle due word successive a quella dell'istruzione ADD. Si otteneva, in pratica, una istruzione di tre word, una contenente ADD e le altre due contenenti gli operandi.
Ovviamente si poteva utilizzare questo trucco anche su di un solo operando, cosė da ottenere una istruzione di 2 word: ADD (R1), (R7)+