Che materia stai cercando?

Anteprima

ESTRATTO DOCUMENTO

Introduzione.

Lezione del 10/10/07

Esempio:

Variazione nella precisione di misura di 1 Kg. in un sistema di pesatura basato su

microprocessori con diversa dimensione del bus dati

Il peso è una grandezza analogica: devo trasformarlo in una grandezza digitale con un

Analog to Digital Converter. Divido l’intervallo di misurazione in tanti intervallini: il

primo assume valore identicamente uguale a 0, l’ultimo

uguale a 1. Il numero di intervallino influisce

pesantemente sulla precisione di rappresentazione.

Se il numero di bit del bus dati ha 4 bit, posso

4 4

informazioni diverse; 2 è cioè il

rappresentare 2

numero di intervallino in cui ho diviso l’intervallo di

misurazione. La massima differenza tra un intervallino e

, cioè la grandezza dell’intervallino, è 6.25%.

Numero di bit bus dati 4 8 16

4 8 16

Dati rappresentabili 2 =16 2 = 256 2 = 65.536

Precisione relativa 6.25% ~3.9 ‰ ~0.015‰

Precisione max. 62.5 gr ~3.9 gr ~0.015 gr

Dispositivi single chip: racchiudono all’interno di un unico circuito integrato, memorie,

bus, CPU.

Vantaggio: occupazione di uno spazio minimo.

Svantaggio: non è espandibile.

DSPÆ Digital Signal Processor. Sono CPU particolari per elaborare dati con particolare

rapidità.

La CPU. BUS DATI ESTERNO

BUS DATI INTERNO

ACC C D I

F

SP PC R R O E N

L N C S

e e A

…. T O T.

g g G R. D.

0 N AL R

E

G.

BUS IND. ESTERNO

BUS INDIRIZZI 6

Introduzione.

Æ

CPU Central Processing Unit = processore. È il vero “cervello” di qualsiasi computer. È

costituito da uno o più chip, circuiti integrati che sono in grado di eseguire istruzioni di

programma, leggere e scrivere nella memoria. La CPU include tutti i circuiti logici che

permettono di prelevare in memoria una istruzione con gli operandi, decodificarla,

eseguirla e trasferire qualsiasi dato verso la memoria o altri dispositivi.

È formata da: Æ permette alla Cpu di scambiare dati tra le varie parti che la

Bus dati interno

compongono e i dispositivi esterni (memorie). Entrano ed escono i dati.

Æ

Bus indirizzi interno permette alla Cpu di identificare gli indirizzi dei dati e delle

istruzioni di cui necessita per eseguire le operazioni richieste e per immagazzinare in

dispositivi esterni i risultati ottenuti. Solo uscente: la CPU richiede tramite il bus

indirizzi interno e poi quello esterno, alle memorie, gli indirizzi in cui sono contenuti i dati e

le istruzioni di cui necessita. Questi entrano nella CPU attraverso il bus dati.

Æ

REGISTRI INTERNI sono un insieme di memorie ad altissima velocità della capacità di

pochi byte.

Æ

MBR Memory Buffer Register: vi vengono temporaneamente collocati i dati provenienti

dalla memoria a seguito di lettura, o da ricopiare in memoria in caso di scrittura.

Æ

MAR Memory Address Register: contiene l’indirizzo della locazione di memoria nella

quale si trova il dato da leggere o da scrivere che transiterà nel MBR.

Registri genericiÆ sono destinati a contenere dati, risultati intermedi o indirizzi di

memoria durante le elaborazione. ENTRANTE E USCENTE VERSO IL BUS

DATI : i dati intermedi possono essere memorizzati e riutilizzati dalla ALU.

USCENTE VERSO IL BUS INDIRIZZI: i dati contenuti possono essere memorizzati

in qualche dispositivo esterno all’indirizzo fornito dal registro.

Æ

Program Counter –PC– è un registro particolare in cui viene memorizzato l’indirizzo di

memoria al quale il processore trova la prossima istruzione da caricare ed eseguire. Ogni

programma, infatti, viene memorizzato come una sequenza ordinata di istruzioni, ciascuna

delle quali possiede un proprio indirizzo. Un incremento del PC comporta, al ciclo

successivo, il caricamento dell’istruzione immediatamente successiva a quella eseguita. È

un registro che si auto-aggiorna. Tuttavia alcune istruzioni di jump, modificano il contenuto

del PC in modo che una locazione diversa da quella immediatamente successiva diviene

la prossima istruzione da eseguire. Perciò, se l’istruzione di jump, il PC salta all’indirizzo di

memoria indicato nell’istruzione di jump.

Verso il bus dati interno USCENTE: richiede informazioni alle memorie esterne se

un’operazione va rifatta n° volte. ENTRANTE: carica la successiva istruzione che il

processore deve eseguire.

USCENTE VERSO IL BUS INDIRIZZI: punta all’indirizzo a cui trovare l’istruzione

successiva. Æ

Stack pointer è un registro della CPU che contiene l’ultimo indirizzo dell’ultima

istruzione che la CPU ha temporaneamente abbandonato per eseguirne un’altra. Lo stack

pointer punta alla sommità dello stack, cioè ad un’area di memoria gestita in logica LIFO,

last in first out, cioè l’ultimo valore introdotto è il primo ad uscire. È grazie allo stack pointer

che possiamo gestire situazioni di chiamate a sottoprogrammi, senza perdere l’operazione

interrotta.

USCENTE VERSO IL BUS INDIRIZZI: ha bisogno di un circuito di incremento e

decremento per funzionare.

Æ

IR Instruction Register: vi viene memorizzata l’istruzione da eseguire, letta dalla

memoria. NB: solo il codice operativo!

ALU (Arithmetic and Logic Unit)Æ è la parte che compie effettivamente i calcoli aritmetici

e logici utilizzando i valori depositati nei registri durante la fase di caricamento delle

7

Introduzione.

istruzioni (fetch). La ALU ha 2 ingressi dal bus dati interno: uno passa dall’accumulatore,

uno diretto. DAL BUS DATI ALL’ACCUMULATORE: nell’Acc. viene caricato uno

degli operandi che servono per eseguire l’istruzione. Alla fine dell’esecuzione

dell’istruzione, il risultato, salvato nell’accumulatore, attraverso il bus dati interno viene

caricato nei registri interni, oppure, attraverso il bus dati interno e poi esterno, nelle

memorie esterne. DALL’ACCUMULATORE ALLA ALU: l’operando salvato

nell’accumulatore viene prelevato dalla ALU per eseguire l’istruzione e il risultato, definitivo

o provvisorio, viene ricaricato nell’accumulatore.

DIRETTO ENTRANTE DAL BUS DATI INTERNO: carica nella ALU l’altro operando

che serve per eseguire il calcolo.

La ALU ha alcuni registri interni:

Æ

Registro dei FLAG interagisce esclusivamente con la ALU. È un registro speciale che

fornisce informazioni riguardo all’ultima operazione aritmetico –logica eseguita. È costituito

dall’insieme di più flag, cioè segnalatori che indicano il verificarsi di condizioni particolari,

quali: l’overflow, il carry, zero, negative.

CON LA ALU: Il risultato viene mandato dalla ALU al FLAG: questo ci dice se c’è

un errore. Gli errori possono essere:

Æ

CARRY riporto o prestito: superamento della capacità di rappresentazione dei numeri

in valore assoluto.

Æ

OVERFLOW superamento della capacità di rappresentazione per i numeri in

complemento a 2 (sommando due positivi si ottiene un negativo.)

Æ

Accumulatore dove è memorizzato uno degli operandi coinvolti nell'operazione

aritmetica o logica e dove rimane memorizzato il risultato di tale operazione;

Æ

UNITA’ DI CONTROLLO È la parte della CPU che gestisce la successione delle

operazioni da svolgere, sincronizzando le attività di tutti gli altri elementi. A tale scopo

preleva dalla memoria centrale una alla volta le istruzioni del programma, che vengono

caricate nell’IR, le decodifica (tramite il DECODER di istruzioni) e le esegue inviando gli

opportuni segnali di controllo agli organi della CPU che ne attuano l’esecuzione.

Æ

Istruction Register –IR– vi viene, attraverso il bus dati interno, inserita l’istruzione che

deve essere eseguita. Nota bene: solo il codice operativo!!!

Æ decodifica il codice operativo che arriva dall’IR: fa capire al processore

Decoder

l’istruzione che deve essere eseguita.

Æ

Controller è la parte della CPU che gestisce la successione delle operazioni da

svolgere e le attività di tutti gli altri elementi, non attivando le parti non necessarie per

l’esecuzione dell’istruzione (così rende il processo più veloce).

CPU “standard” vs. MIPS.

CPU standard MIPS

L1: ADD A, Reg1 add $t1, $t2, $t3

JP ovfw, Err …

… …

… …

Err: …

¬ Nel MIPS non c’è il flag di overflow. Quando scrivo ignoro il

add $t1, $t2, $t3

problema che possa generarsi un overflow, scrivendo quindi di seguito altre istruzioni.

Se effettivamente non si verifica overflow, posso continuare ad eseguire le operazioni

successive senza alcun problema, in quanto non c’è nessun errore. Quando invece si

verifica overflow la ALU genera una sorta di interrupt interno che fa saltare in un

8

Introduzione.

sottoprogramma ben definito che gestisce il problema dell’overflow con istruzioni

correttive.

Ð Vantaggio: quando non si verifica overflow è più vantaggiosa la soluzione del

MIPS, in quanto ho delle istruzioni in meno.

Ð Svantaggio: ad una prima approssimazione sembrerebbe più svantaggiosa la

soluzione del MIPS in caso l’overflow si verificasse, poiché devo interrompere il

main program per passare il controllo ad una subroutine, impiegando così più

tempo. Tuttavia la probabilità che si verifichi un problema di overflow, dipende

dalla dimensione del bus dati: poiché nel MIPS il bus dati è a 32 bit, quindi di

grandi dimensioni, ho scarsa probabilità che si verifichi overflow. Nei pochi casi in

cui si verifica genero l’eccezione, altrimenti l’esecuzione del programma continua

dopo l’operazione di senza bisogno di aggiungere ulteriori istruzioni che

add,

correggano possibili overflow.

¬ Poiché avviene di frequente nei programmi di aver bisogno di far confronti con il

numero 0, il MIPS prevede che un registro, detto $zero, interno alla CPU assuma

sempre valore 0. Questo registro non è modificabile dal programmatore. Il vantaggio

che se ne ricava è una maggior velocità nell’effettuare tale confronto, in quanto

l’operando 0 è interno alla CPU e non in memoria. Lo svantaggio è legato alla perdita

di un registro per la programmazione.

¬ Gestione di sottoprogrammi:

Ð 1^soluzione: prevedo un registro “PC old” in cui, in caso di chiamata a

sottoprogramma, salvo l’indirizzo di rientro al main program. Questa soluzione è

funzionale solo nei casi in cui non ci sono chiamate nidificate a sottoprogramma.

Sia per, esempio, M il programma principale: in M compare una chiamata al

sottoprogramma A; in “PC old” salvo l’indirizzo di rientro verso M, cioè l’indirizzo

dell’istruzione in M, successiva a quella che ha effettuato la chiamata a

sottoprogramma. Nel sottoprogramma A compare una chiamata al

sottoprogramma B; in “PC old” salvo l’indirizzo di rientro verso A, cioè l’indirizzo

dell’istruzione in A, successiva a quella che ha effettuato la chiamata a

sottoprogramma. Così facendo ho perso l’indirizzo di rientro da A verso M!

Ð 2^soluzione: prevedo un’area di memoria gestita con logica LIFO, last in, first out,

in cui inserisco gli indirizzi delle varie chiamate a sottoprogramma. Quando un

sottoprogramma viene chiamato, l’indirizzo di rientro, cioè quello dell’istruzione

successiva a quella che ha effettuato la chiamata, viene memorizzato nello stack,

a cui punta lo stack pointer; quando un sottoprogramma termina l’esecuzione,

viene letto dalla pila l’ultimo indirizzo caricato che non è stato ancora prelevato e

viene trasferito nel Program Counter. La gestione LIFO dello stack permette di

nidificare le chiamate ai sottoprogrammi. Tale soluzione è, però, carente dal punto

di vista delle prestazioni, in quanto, ogni lettura di memoria richiede molto tempo.

Il MIPS prevede entrambe le possibilità: Hennesy e Patterson, hanno effettuato degli

studi su alcuni dei programmi in uso più importanti e hanno notato che il caso più

frequente è quello di una sola chiamata a sottoprogramma e non di chiamate nidificate.

All’interno della CPU è presente un registro in cui, quando viene chiamato un

$ra,

sottoprogramma con l’istruzione (jump and link), viene salvato l’indirizzo di rientro

jal

al programma chiamante. Poiché tale possibilità non prevede nidificazione, il

programmatore, qualora ci fossero chiamate nidificate a sottoprogramma, deve

provvedere a salvare gli indirizzi di rientro dei vari sottoprogrammi nello stack.

¬ Nel MIPS tutte le operazioni matematiche impongono di utilizzare i registri. Gli operandi

devono quindi essere preventivamente caricati in opportuni registri. Per questo nel

MIPS non c’è l’accumulatore. 9

Introduzione.

Formato di un’istruzione.

Le istruzioni sono codificate da stringhe di bit. Una volta caricata nell’IR, un’istruzione deve

essere decodificata ed eseguita. Il decodificatore ha il compito, ricevute n linee in ingresso

n combinazioni diverse è quella di mio interesse, cioè di attivare in

di capire quale fra le 2

uscita la sola linea corrispondente all’operazione identificata dal codice operativo arrivato

in ingresso. A tal scopo l’unità di controllo deve conoscere:

Æ

1. CODICE OPERATIVO è il campo che caratterizza le varie istruzioni.

Æ

2. SORGENTE dati su cui operare.

Æ

3. DESTINAZIONE dove porre il risultato e, se sorgente e destinazione sono in

memoria le MODALITA’ DI INDIRIZZAMENTO.

Codice Operativo Operando 1 Operando 2 Se ho 0 operandi =gli

operandi sono già

Campo che all’interno della CPU.

Gli operandi possono

caratterizza le varie 2

essere 0, 1,

Ciclo di esecuzione di un’istruzione.

L’unità di controllo svolge il suo lavoro ripetendo continuamente un algoritmo che la guida

attraverso un processo a 3 fasi detto ciclo macchina. Le tre fasi sono:

Æ

Fetch prelevamento dell’istruzione: l’unità di controllo richiede che la memoria

principale fornisca l’istruzione memorizzata all’indirizzo indicato dal Program Counter.

L’unità di controllo pone l’istruzione ricevuta dalla memoria nel suo registro delle istruzioni

e poi incrementa il PC, in modo che esso contenga l’indirizzo della fase successiva.

Æ

1. (PC) MAR

Æ Æ

2. ((MAR)) MBR (PC) +1 PC

Æ

3. (MBR) IR.

I passi 1, 2, 3 permettono di caricare in IR (instruction register) il codice operativo (OP

Code) dell’istruzione corrente. Passi analoghi permettono di caricare in opportuni registri

della CPU gli operandi presenti nell’istruzione. In tal caso, nel passo 3 la destinazione del

dato proveniente dalla memoria non è più IR, ma opportuni registri.

Nella fase di fetch sono coinvolti: il PC, l’unità di controllo, i registri (o l’istruction register).

Æ

Decode decodifica: l’unità di controllo decodifica l’istruzione, cioè scompone il campo

operando nei suoi componenti sulla base del codice operativo dell’istruzione.

Sono coinvolti: il decoder.

Æ

Execute l’unità di controllo esegue l’istruzione attivando la circuiteria adeguata a

svolgere il compito richiesto. Per esempio se l’istruzione è un’operazione aritmetiche

l’unità di controllo attiva la ALU e i registri necessari.

Coinvolti: la ALU, i registri.

Una volta che l’istruzione è stata eseguita, l’unità di controllo inizia un nuovo ciclo con la

fase di reperimento.

Esempio 1: Somma tra il contenuto del registro R2 e il contenuto dell’accumulatore. Il

risultato va nell’accumulatore.

FORMATO codice operativo

FETCH come in precedenza

ESECUZIONE (R2)+(ACC)→ACC 10

Introduzione.

Esempio 2: somma tra il contenuto della cella di memoria il cui indirizzo è specificato

nell’istruzione ed il contenuto dell’accumulatore; il risultato va nell’accumulatore

Ð FORMATO: codice operativo+operando

Ð FETCH:

1) (PC)→MAR 4) (PC)→MAR

→MBR; →PC →MBR; →PC

2) ((MAR)) (PC)+1 5) ((MAR)) (PC)+1

→IR →Rn

3) (MBR) 6) (MBR)

Ð EXECUTE: →MAR →Rn

1) (Rn) 3) (MBR)

→MBR →ACC

2) ((MAR)) 4) (Rn)+(ACC)

Esempio 3: saltare all’istruzione che è memorizzata nella cella il cui indirizzo è specificato

all’interno dell’istruzione corrente:

Ð FORMATO: codice operativo+operando

Ð FETCH:

1) (PC)→MAR 4) (PC)→MAR

→MBR; →PC →MBR; →PC

2) ((MAR)) (PC)+1 5) ((MAR)) (PC)+1

→IR →Rn

3) (MBR) 6) (MBR)

Ð EXECUTE:

→PC

(Rn) 11

Le istruzioni

ÐCAPITOLO 2Ï

LE ISTRUZIONI

LEZIONE DEL 29/10/07.

CASE/SWITCH

{

Switch (k) slt $t3, $s5, $zero # k <0?

case 0: f=i+j; break; bne $t3, $zero, Exit

slt $t3, $s5, $t2 # k >3?

case 1: f=g+h; break; beq $t3, $zero, Exit

add $t1, $s5, $s5

case 2: f=g-h; break; add $t1, $t1, $t1 # $t1=4*k

add $t1, $t1, $t4

case 3: f=i-j; break; lw $t0, 0($t1)

jr $t0 #vai a indir. letto

} L0: add $s0, $s3, $s4 #k=0, f=i+j

j Exit

L1: add $s0, $s1, $s2 #k=1, f=g+h

j Exit

f = $s0, g = $s1, h = $s2, i = $s3, j = $s4, L2: sub $s0, $s1, $s2 #k=2, f=g-h

k= $s5; $t2 = 4 ;$t4 =indirizzo tabella j Exit

etichette L3: sub $s0, $s3, $s4 #k=3, f=i-j

Exit:

Nel linguaggio ad alto livello confronto K con 0, poi con 1, poi con 2, poi con 3…cioè mi

chiedo: k=0? Se no mi chiedo K=1? Se no mi chiedo K=2?...alcune condizioni di K sono

particolarmente veloci: se K=1, l’esecuzione è veloce… se ho 100 casi e K=100 devo fare

100 test prima di trovare il caso giusto!!! Questa soluzione è particolarmente svantaggiosa

per i tempi di esecuzione.

Soluzione:

slt $t3, $s5, $zero # k <0?

bne $t3, $zero, Exit

slt $t3, $s5, $t2 # k >3?

beq $t3, $zero, Exit

Dato l’esempio precedente queste 4 istruzioni controllano se 0<k<4. se questo non è

verificato il programma esce e non esegue nessuna delle operazioni richieste.

La soluzione al problema della lentezza di effettuare i test reiterati è la

seguente: L0

si costruisce in memoria una tabella,detta in

tabella degli indirizzi di salto,

cui vengono collocati gli indirizzi di inizio delle varie routine, poiché scrivere il L1

nome di un etichetta in realtà significa scrivere l’indirizzo che l’assemblatore L2

nella tavola dei simboli ha associato a quella etichetta. L’indirizzo di partenza

di questa tabella è contenuta in un registro ($t4). L3

Se K=0 devo raggiungere la routine L0 => devo raggiungere la casella in

Æ

memoria identificata da $t4.

Se k=1 devo raggiungere la routine L1 => devo spostarmi di 1 word nella

Æ

tabella degli indirizzi di salto: sommo il valore 4=k*4 all’indirizzo $t4.

12

Le istruzioni

Se k=2 devo raggiungere la routine L2 => devo spostarmi di 2 word nella tabella degli

Æ

indirizzi di salto: sommo il valore 8=k*4 allp’indirizzo $t4…

Guardando il codice:

L’indirizzamento a byte del processore mi impone di moltiplicare il valore di k per 4:

se K=0 0

Æ

se k=1 4

Æ

se k=2 8

Æ

se k=3 12.

Æ

add $t1, $s5, $s5

add $t1, $t1, $t1 # $t1=4*k

Ora sommo il valore di K all’indirizzo di partenza delle tabella degli indirizzi di salto. Così

ottengo l’indirizzo della routine a cui voglio saltare.

add $t1, $t1, $t4

Leggo l’indirizzo della routine a cui voglio andare e lo carico nel Program Counter.

lw $t0, 0($t1)

jr $t0 #vai a indir. letto

Vantaggi:

Il tempo per raggiungere ogni singola routine non varia se varia il numero dei casi da

œ verificare. Ha un tempo di esecuzione piccolo e indipendente dal numero di casi.

Il numero di istruzioni non varia al variare del numero dei casi da verificare.

œ

Svantaggi:

All’aumentare del numero di casi da verificare aumenta la dimensione della tabella

œ degli indirizzi di salto.

GESTIONE DELLE SUBROUTINE.

Una procedura o subroutine è uno strumento che i programmatori C e java utilizzano per

strutturare i programmi, per renderli più comprensibili e per permetterne il riutilizzo del

codice. Le subroutine acquisiscono risorse, svolgono determinate istruzioni e tornano al

punto di partenza, restituendo risultati. Durante l’esecuzione di una procedura, il

programma esegue e seguenti passi:

1. mettere i parametri in un luogo accessibile alla subroutine;

2. trasferire il controllo alla subroutine;

3. acquisire le risorse necessarie per memorizzare dei dati;

4. eseguire il compito richiesto;

5. mettere il risultato in un luogo accessibile al programma chiamante;

6. restituire il controllo al punto di origine;

I registri sono il luogo che permette l’accesso ai dati più rapido. Il software MIPS usa le

seguenti convenzioni per allocare i suoi 32 registri nelle chiamate a sottoprogrammi:

quattro per il passaggio dei parametri;

Æ

$a0-$a3 registri argomento

due per la restituzione dei valori;

Æ

$v0, $v1 registri valore

un per tornare al punto di origine (all’istruzione successiva

Æ

$ra registro di ritorno

quella che ha effettuato la chiamata).

L’istruzione (jump and link) salta a un indirizzo e contemporaneamente salva

jal

l’indirizzo dell’istruzione successiva a quella di salto nel registro $ra, detto indirizzo di

ritorno. Tale istruzione, quindi, salva il valore PC+4 (il Program Counter è un registro che

contiene l’indirizzo dell’istruzione del programma correntemente in esecuzione) nel

registro $ra, per creare il collegamento all’indirizzo dell’istruzione successiva a quella di

13

Le istruzioni

chiamata, così da predisporre il ritorno al main. L’indirizzo di ritorno è necessario, poiché

la stessa subroutine può essere chiamata da diversi punti del programma.

Per effettuare il ritorno dalla subroutine i calcolatori MIPS utilizzano l’istruzione (salta

jr

tramite registro), che implica un salto incondizionato all’indirizzo specificato in un registro.

La gestione delle subroutine avviene in questo modo:

Ð il mette i valori dei parametri da passare alla subroutine nei

programma chiamante

registri e utilizza l’istruzione per saltare al sottoprogramma X.

$a0-$a3 jal X

Ð Il (cioè X) esegue le operazioni richieste, memorizza i

programma chiamato

risultati nel registri e e restituisce il controllo al chiamante con l’istruzione

$v0 $v1

jr $ra.

Si supponga che un compilatore abbia bisogno, all’interno di una procedura, di un numero

maggiore di registri rispetto ai quattro per i parametri e ai due per i valori da restituire.

Inoltre, per svolgere qualsiasi compito, il programma chiamato necessita dei registri:

poiché il numero di registri del MIPS non è elevato, accade che il programma chiamato

utilizzi dei registri che già il programma chiamante stava utilizzando: non è possibile che i

valori che questi registri contenevano prima della chiamata a sottoprogramma vadano

perduti! Qualunque registro utilizzato dal programma chiamante deve, quindi, essere

riportato al valore che conteneva prima della chiamata. In questa situazione è necessario

La struttura ideale per riversare i registri è lo una

riversare i registri in memoria. stack,

coda del tipo last-in-first-out (cioè l’ultimo a entrare è il primo a uscire). Lo stack ha

bisogno del puntatore all’indirizzo del dato introdotto più di recente, per indicare dove la

procedura può memorizzare i registri da riversare e dove può recuperare i vecchi valori dei

registri. Questo è aggiornato ogni volta che si inserisce o si estrae il valore di

stack pointer

un registro. Esistono termini generali per indicare il trasferimento dati da e verso lo stack:

=> memorizzazione di un dato nello stack;

push

=> estrazione di un dato dall’ stack.

pop

Il software MIPS alloca un altro registro appositamente per lo stack: $sp, lo stack pointer

denota l’indirizzo dell’elemento dello stack allocato più di recente, il quale mostra dove i

registri devono essere salvati o dove si trovano i vecchi valori dei registri salvati. Lo stack

cresce a partire da indirizzi di memoria alti vero indirizzi di memoria bassi. Questa

convenzione indica che quando vengono inseriti dei dati nello stack, il valore dello stack

pointer diminuisce; al contrario quando sono estratti dati dallo stack, aumenta il valore

dello stack pointer riducendo la dimensione dello stack.

USO DELLO STACK

int proc (int g, int h, int i, int j) Per convenzione:

{ int f; $t0-$t9 temporanei da non salvare

f=(g+h)-(i+j); $s0-$s7 da conservare

return f; si potevano risparmiare 2

} push/pop

I parametri g,h, i,j corrispondono ai registri argomento $a0, Sa1, $a2 e Sa2 e f corrisponde

a $s0.

proc:addi $sp, $sp, -12 # 3 push

sw $t1, 8($sp)

sw $t0, 4($sp)

sw $s0, 0($sp)

add $t0, $a0, $a1 # calc. f 14

Le istruzioni

add $t1, $a2, $a3

sub $s0, $t0, $t1

add $v0, $s0, $zero # $v0=f

lw $s0, 0($sp) # 3 pop

lw $t0, 4($sp)

lw $t1, 8($sp)

addi $sp, $sp, 12

jr $ra # ritorno

Il programma inizia con l’etichetta della procedura proc. Il passo successivo consiste nel

salvare tutti i registri usati dalla procedura. È necessario salvare i contenuti dei registri

$s0, $t0, $t1. Si crea così lo spazio per tre parole all’interno dello stack dove vengono

memorizzati i vecchi valori:

addi $sp, $sp, -12.

Con questa istruzione si aggiorna lo stack pointer, per fare posto a 3 parole.

sw $t1, 8($sp)

sw $t0, 4($sp)

sw $s0, 0($sp)

Con queste 3 istruzioni il contenuto dei 3 registri viene salvato in memoria.

Indirizzi alti Contenuto di $s0.

Contenuto di $t0.

Contenuto di $t1.

Indirizzi bassi

Le tre istruzioni successive corrispondono al calcolo che la procedura deve svolgere.

add $t0, $a0, $a1 # calc. f

add $t1, $a2, $a3

sub $s0, $t0, $t1

Per restituire il valore di f occorre poi copiarlo in un registro di ritorno, cioè in un registro v.

add $v0, $s0, $zero # $v0=f

Prima del ritorno al programma chiamante i vecchi valori vengono ripristinati all’interno dei

registri, estraendoli dallo stack (pop):

lw $s0, 0($sp) # 3 pop

lw $t0, 4($sp)

lw $t1, 8($sp)

Lo stack pointer viene dunque aggiornato per eliminare i 3 elementi:

addi $sp, $sp, 12

la procedura termina con un’istruzione di salto tramite registro che utilizza l’indirizzo di

ritorno.

jr $ra

In questo esempio sono stati utilizzati dei registri temporanei ed è stata fatta l’ipotesi che il

loro valore originale dovesse essere salvato e ripristinato. Per evitare di salvare e

ripristinare registri il cui valore non viene mai utilizzato, il software MIPS suddivide 18 dei

registri in due gruppi: 15

Le istruzioni

$t0-$t9 registri temporanei che non sono preservati in caso di chiamata a

Æ

sottoprogramma: il programmatore è libero di utilizzarli in sottoprogrammi senza dover

salvare e ripristinare il valore che avevano prima della chiamata.

$s0-$s7Æ registri che devono essere preservati in caso di chiamata a sottoprogramma,

cioè registri che, se utilizzati, devono essere salvati e ripristinati dal programma chiamato.

Questa convenzione riduce la necessità di salvare registri in memoria.

Nell’esempio precedente, dato che il programma chiamante non si aspetta che i registri

$t0 e $t1 siano preservati durante la chiamata a sottoprogramma si possono eliminare dal

codice 2 istruzioni di push e 2 di pop.

Registri preservati Registri non preservati

Registri: $s0-$s9 Registri temporanei: $t0-$t9.

Stack pointer: $sp Registri argomento: $a0-$a3.

Registro di ritorno: $ra. Registri valore: $v0-$v1.

Lezione del 31/10/2007

PROCEDURE ANNIDATE.

Si supponga per esempio che il programma principale chiami la procedura A con un

parametro uguale a 3, mettendo il valore 3 nel registri $a0 e usando l’istruzione jal A.

L’indirizzo di ritorno da A al main è dunque contenuto in $ra. Si supponga poi che la

procedura A chiami la procedura B con un passandole il valore 7 posto in $a0. si

jal B

verificano 2 problemi:

Ð dato che A non ha ancora finito il suo lavoro, si verifica un conflitto nell’uso del

registro $a0;

Ð si verifica anche un conflitto nell’utilizzo di $ra: l’istruzione di provvede a

jal B

salvare l’indirizzo di ritorno della procedura B verso la procedura a in $ra,

eliminando l’indirizzo di ritorno della procedura A verso il main.

Una soluzione consiste nel salvare nello stack tutti i registri che devono essere preservati.

Ð Il programma chiamante memorizza nello stack qualsiasi registro argomento ($a0-

$a3) o registri temporaneo ($t0-$t9) di cui avrà bisogno dopo la chiamata;

Ð Il programma chiamato invece salva nello stack il registro di ritorno $ra e gli altri

registri che utilizza ($s0-$s7).

Esempio: programma che calcola il fattoriale di un numero n.

int fattoriale (int n)

{ if (n<1) return (1);

else return (n*fact(n-1);

}

Il parametro n corrisponde al registro argomento $a0.

Il programma innanzitutto salva nello stack due registri: l’indirizzo di ritorno e $a0. Si

aggiorna lo stack per fare posto a 2 elementi e si salvano l’indirizzo di ritorno e il

parametro n.

Fattoriale: addi $sp, $sp, -8

sw $ra, 4($sp)

sw $a0, 0($sp)

La prima volta che la proceduta fattoriale viene chiamata, l’istruzione sw salva un indirizzo

nel programma che l’ha chiamata. Le due istruzioni successive verificano se n è minore di

1, saltando a L1 se n≥1 16

Le istruzioni

slti $t0, $a0, 1

beq $t0, $zero, L1

Se n<1, fattoriale restituisce il valore 1 mettendolo in un registro valore. Quindi ripristina

dallo stack i due valori salvati e salta all’indirizzo di ritorno.

addi $v0, $zero, 1

addi $sp, $sp, 8

jr $ra

prima dell’aggiornamento della stack pointer si sarebbero dovuti ripristinare $a0 e $ra, ma

dato che quando n è minore di 1 non cambiano, è possibile non farlo.

Se n non è minore di 1 si salta a L1: il parametro n viene decrementato di 1 e viene

nuovamente chiamata la procedura Fattoriale passandole tale valore.

L1: addi $sa, $sa, -1

jal Fattoriale

l’istruzione successiva è quella a cui la procedura Fattoriale ritornerà; il vecchio indirizzo

di ritorno e il vecchio parametro sono ripristinati, oltre ad eseguire l’aggiornamento dello

stack pointer: lw $a0, 0($sp) # ind. = L1+8

lw $ra, 4($sp)

addi $sp, $sp, 8

Successivamente nel valore $vo viene memorizzato il prodotto del valore corrente per il

vecchio parametro $a0; qui si suppone l’esistenza di un’operazione di moltiplicazione,

analizzata più avanti. Infine la procedura fattoriale salta nuovamente all’indirizzo di ritorno.

mul $v0, $a0, $v0

jr $ra

Gestione dello stack

Al 1° richiamo salva nello stack:

1) l’indirizzo di ritorno che è nella zona del chiamante

(nome attribuito JALM + 4);

2) il valore di $a0 = n.

Al 2° richiamo salva nello stack:

1) l’indirizzo della procedura Fattoriale (indicato da L1+8);

2) il valore di $a0 = n-1.

Al 3° richiamo salva nello stack L1+8 e $a0 = n-2.

. . . . .

Al n-mo richiamo salva nello stack L1+8 e $a0 = 0.

Esempi di esecuzione al variare di n:

n=0

$ra = JALM+4

$a0 = n = 0

n=1

$ra = JALM+4 1^esecuzione

$a0 = n = 1

$ra = L1+8 2^esecuzione

$a0 = n-1 = 0 17

Le istruzioni

Alla prima iterazione salta a L1;

$a0=0;

$ra=L1+8.

Alla seconda iterazione non salta a L1: ritorna a L1+8, dove $a0=1; ra=JALM+4;

$v0*1=$v0 e ritorna al main.

n=2

$ra = JALM+4 1^ esecuzione

$a0 = n = 2

$ra = L1+8 2^ esecuzione

$a0 = n-1 = 1

$ra = L1+8 3^ esecuzione

$a0 = n-2 = 0

Alla 1^iterazione salta a L1; a0 diventa 1; ra=L1+8;

Alla 2^iterazione salta a L1; a0 diventa 0; ra=l1+8;

Alla 3^ iterazione: non salta a L1, quindi v0=1 e torna a L1+8, a0=1; ra=L1+8; v0*1=v0;

torna a L1+8, a0=2, ra=JALM+4, v0=1*a0=2 e torna al main program.

fatt.

Salva indirizzo di

ritorno e valore a0 Richiamo

nello stack no

sì a0<1

v0=1 dec a0

Preleva a0 Ritorno all’ultima

chiamata effettuata

(2 casi: n-1 volte si

ritorna alla routine

Ultima iterazione Iter. intermedie

fatt. all’indirizzo

L1+8 e si preleva

a0 dallo stack, solo v0=a0*v0

l’ultima si torna al

Ritorno main (JALM+4)) e

si aggiorna SP 18

Le istruzioni

Fattoriale: addi $sp, $sp, -8

sw $ra, 4($sp)

sw $a0, 0($sp)

slti $t0, $a0, 1

beq $t0, $zero, L1

addi $v0, $zero, 1

addi $sp, $sp, 8

jr $ra

L1: addi $sa, $sa, -1

jal Fattoriale

lw $a0, 0($sp) # ind. = L1+8

lw $ra, 4($sp)

addi $sp, $sp, 8

mul $v0, $a0, $v0

jr $ra

Commenti ai programmi per il calcolo del fattoriale:

Limite massimo di cui possiamo calcolare il fattoriale?

Il numero massimo di cui possiamo calcolare il fattoriale è limitato dal valore stesso che il

fattoriale assume, in quanto questo risultato deve essere contenuto in un registro: non

deve superare i 32 bit!!!

Cosa accade se il numero che passiamo al sottoprogramma è maggiore del numero

32

massimo di cui vogliamo calcolare il fattoriale, cioè cosa accade se n!>2 -1? Il risultato

che viene restituito sono i soli 32 bit meno significativi del n! calcolato.

Nel fare la moltiplicazione, il processore utilizza 2 registri: Hi, in cui mette i 32 bit più alti,

più significativi del numero (n!) e Lo, in cui mette i 32 bit meno significativi (RICORDA:

moltiplicare 2 numero da 32 bit = numero da 64 bit!).

Come si modifica il programma per controllare a tempo di esecuzione se ho superato il

numero massimo di cui posso calcolare il fattoriale? Se il registro Hi contiene un numero

diverso da 0, significa che il risultato del fattoriale supera i 32 bit a disposizione.

Lezione del 5/11/07

GESTIONE CARATTERI

La maggior parte dei calcolatori utilizza 8 bit per rappresentare i caratteri e la codifica

ASCII è quella più utilizzata. L’elaborazione di testi è talmente diffusa che il MIPS offre

istruzioni apposite per trasferire i byte: (lb) prende un byte dalla memoria,

load byte

mettendolo negli 8 bit meno significativi di un registro (quelli a destra), mentre store byte

(sb) prende il bit corrispondente agli 8 bit meno significativi di un registro e lo mette in

memoria.

Esempio: programma che copia la stringa y nella stringa x, usando il byte

Null come carattere di fine stringa.

In realtà ci sono 3 modi per capire se una stringa è finita:

1. il primo valore contenuto nella stringa di caratteri ne codifica la lunghezza;

2. c’è una variabile ulteriore, oltre alla stringa, che è la lunghezza della stringa stessa;

3. le stringhe sono terminate dal carattere Null (ATTENZIONE: null è diverso da 0, ma

null in codice ASCII è rappresentato da 000, mentre 0=048).

19

Le istruzioni

void strcpy (char x[], char y[])

{ int i;

i = 0;

while ((x[i] = y[i]) != 0) /* copia e test byte */

i = i + 1;

}

Si supponga che gli indirizzi di base dei vettori siano: x=$a0; y=$a1; mentre i=$s0.

strcpy: addi $sp, $sp, -4

sw $s0, 0($sp) # salva $s0 nello stack

add $s0, $zero, $zero # i = 0

L1: add $t1, $a1, $s0 # ind. y[i] in $t1

lb $t2, 0($t1) # $t2 = y[i]

add $t3, $a0, $s0 # ind. x[i] in $t3

sb $t2, 0($t3) # x[i] = y[i]

addi $s0, $s0, 1 # i = i + 1

bne $t2, $zero, L1 # se y[i] 0 vai a L1

lw $s0, 0($sp) # ripristina $s0 dallo stack

addi $sp, $sp, 4

jr $ra # ritorno

La procedura aggiorna lo stack pointer e poi salva il registro $s0 nello stack:

addi $sp, $sp, -4

sw $s0, 0($sp)

per inizializzare i=0, l’istruzione successiva pone $s0 a 0, sommando 0 a 0 e mettendo la

somma in $s0.

add $s0, $zero, $zero

Inizia il ciclo. L’indirizzo y[i] è creato sommando i a y[ ] e ponendo il risultato in $t1:

add $t1, $a1, $s0

Non è necessario moltiplicare i per 4, dato che y è un vettore di byte e non di word: non è

necessario rispettare il vincolo di allineamento! Per caricare il carattere presente in y[i] si

usa l’istruzione load byte che mette il carattere in $t2:

lb $t2, 0($t1)

con un calcolo analogo mettiamo l’indirizzo di x[i] in $t3 e il carattere che si trova in $t2

viene scritto nella locazione di memoria così individuata:

add $t3, $a0, $s0

sb $t2, 0($t3)

incrementiamo i e controlliamo se il carattere di fine stringa è Null, cioè se il carattere è 0:

addi $s0, $s0, 1

bne $t2, $zero, L1

se la stringa è terminata, vengono ripristinati i valori di $s0 e dello stack pointer e si esce

dalla procedura.

lw $s0, 0($sp)

addi $sp, $sp, 4

jr $ra

Nota: se invece del registro $s0, veniva usato un registro t, ad esempio $t4, non erano

necessarie le operazioni di push e pop. 20

Le istruzioni

OPERANDI IMMEDIATI.

Molto spesso accade che si necessiti, all’interno di un programma di piccole costanti:

addi $sp, $sp, 4

Possibili soluzioni:

mettere in memoria le costanti tipiche e caricarle da questa soluzione troppo lenta!

œ Æ

Creare registri preservati per le costanti, come il $zero nel MIPS ho a disposizione

œ Æ

solo 32 registri: sono troppo pochi per memorizzare dati, costanti, valori…!

Modifichiamo le istruzioni di le facciamo diventare

œ add, slt, and, or…e addi

=add with immediate… rendi il caso più comune il più veloce possibile.

PRINCIPIO DI PROGETTO 3:

Le operazioni su costante avvengono molto di frequente e includendo le costanti all’interno

dello operazioni aritmetiche queste ultime risultano molto più veloci rispetto a quando le

costanti sono caricate dalla memoria.

addi $29, $29, 4

slti $8, $18, 10

andi $29, $29, 6

ori $29, $29, 4

Dimensioni delle costanti:

addi $29, $29, 4

Il formato utilizzato è il formato ho a disposizione al massimo 16 bit. Se la costante è

I:

lunga al massimo 16 bit, quando la ALU fa la somma, somma un numero di 32 bit a uno di

16: i 16 bit mancanti?

Faccio l’operazione dell’estensione poiché per la somma la ALU lavora con

del segno:

numeri in complemento a 2, quando voglio trasformare un numero da 16 bit a 32 bit, copio

ripetutamente nei 16 bit mancanti il bit di segno

Posso settarli a se la

œ 0 costante è positiva;

Se la costante è negativa?un numero in complemento a 2 negativo ha il bit più

œ significativo uguale a 1: se settassi anche questi 16 bit a 0, sommerei un numero

positivo (esempio: addi $29, $29, -1. il numero -1=1111111111111111. Se aggiungo

16 zeri: -1= 0000000000000000 1111111111111111. Questo numero è 65536, e non -

1!!!). Se il aggiungo 16 bit identicamente uguali a

numero è negativo 1.

L’estensione del segno è usata anche nelle istruzioni di e di di e di

load store, bne beq,

di slti.

e invece non estendono il segno, ma riempiono i 16 bit mancanti di 0: non sono

Andi ori,

numeri in complemento a due, ma sequenze di bit.

Gestione delle grandi costanti.

Che cosa accade se ho bisogno di costanti grandi?Se la costante è più grande di 16 bit?

Sebbene, infatti, le costanti siano molto spesso piccole e trovino spazio all’interno del

campo di 16 bit a loro assegnato, qualche volta sono più grandi. L’insieme di istruzioni

MIPS include l’istruzione per caricare i 16 bit più significativi di

load upper immediate, lui,

una costante, nella parte alta di un registro, consentendo a un’istruzione successiva di

specificare la parte bassa della costante. Questa istruzione successiva è nei 16 bit

ori:

più alti è identicamente uguale a zero: infatti 0+x=x , mentre nei 16 bit più bassi è uguale

alla parte bassa della costante da caricare.

Esempio: devo caricare la costante seguente nel registro $s0:

0000 0000 0011 1101 0000 1001 0000 0000

21

Le istruzioni

lui $s0, 0000 0000 0011 1101

a questo punto il registro $s0 contiene:

lui $s0, 0000 0000 0011 1101 Sono settati a zero

00000000000111101 0000000000000000

Ora dobbiamo sommare i 16 bit meno significativi, il cui valore è 0000 1001 0000 0000

Ori $s0, $s0, 0000 1001 0000 0000

0000000000111101 0000000000000000

0000000000000000 0000100100000000 Ori

0000000000111101 0000100100000000

Il valore finale nel registro $s0 è il valore desiderato.

In realtà , invece di scrivere le due istruzioni di e l’assemblatore accetta la

lui ori,

pseudoistruzione (load immediate).

li

Ad esempio: 3 casi possibili: lui $t0, 0x1124

li $t0, 0x1124ABF0 = ori $t0, $t0, 0xABF0

------------------ perché 25.000 è rappresentabile con 16 bit

li $t0, 25.000 = ori $t0, $t0, 25.000

perchè 65.536=0x0001 0000

lui $t0, 1

li $t0, 65.536= ---------------

Può capitare che all’interno del programma ho bisogno di caricare un indirizzo di memoria,

che è lungo 32 bit. Lo posso fare con l’istruzione (load sia il nome

address).

la Msg

dell’etichetta a cui l’assemblatore associa l’indirizzo di memoria.

la $t0, msg

=carica in t0 l’indirizzo associato all’etichetta msg. L’indirizzo di memoria identificato con

msg, può essere uno dei 3 casi sopra descritti: l’assemblatore capisce in quale caso siamo

e si comporta di conseguenza.

Lezione del 7/11/07.

LINGUAGGIO ASSEMBLATIVO CONTRO LINGUAGGIO MACCHINA:

¬ il linguaggio assemblativo offre la possibilità di utilizzare una rappresentazione

simbolica; questo risulta più semplice rispetto a scrivere sequenze di numeri. Tuttavia,

c’è una sintassi da rispettare: ad esempio nelle istruzioni aritmetiche il primo registro è

la destinazione; 22

Le istruzioni

¬ è importante ricordare che al di sotto del linguaggio assemblativo c’è il linguaggio

macchina;

¬ il linguaggio assemblativo consente di scrivere pseudoistruzioni, significative per il

programmatore, che successivamente l’assemblatore traduce in sequenze di istruzioni

interne al MIPS.

¬ Tuttavia quando è necessario considerare le prestazioni del processore (tempo di

esecuzione, spazio di memoria occupato), bisogna tenere conto delle istruzioni reali,

non delle pseudoistruzioni.

RIASSUNTO 1:

panoramica sul MIPS:

¬ le istruzioni del MIPS sono tutte lunghe 32 bit: questo deriva dalla logica RISC, cioè dei

calcolatori a set di istruzioni ridotte. Ciò poiché si vuole perseguire l’obiettivo, non tanto

della semplicità dell’hardware, quanto dell’efficienza, intesa come tempi di risposta

quanto più brevi possibili e minima occupazione di memoria.

I,

¬ Esistono solo 3 formati di istruzioni diversi: R, J. In tutti e 3 il primo campo

rappresenta il codice operativo, in modo da poter capire subito di quale istruzione e

quindi di quale formato si tratta.

¬ Grazie anche al compilatore riusciamo di ottenere buone prestazioni.

op rs rt rd shamt funct R

I

op rs rt 16 bit address J

op 26 bit address

MODALITA’ DI INDIRIZZAMENTO.

Indirizzamento nei salti. la prossima istruzione è a Label se $t4 è diverso da $t5

Æ

bne $t4,$t5,Label la prossima istruzione è a Label se $t4 è uguale a $t5

Æ

beq $t4,$t5,Label

la prossima istruzione è a Label.

Æ

j Label

Il modo di indirizzamento più semplice è quello dell’istruzione jump:

¬ utilizza il formato J, in cui 6 bit specificano il codice operativo e i restanti bit sono il

campo indirizzo. Tuttavia 26 bit non bastano ad identificare un indirizzo:

– in realtà è come se fossero 28, in quanto questi indirizzi puntano a word e perciò i 2

bit meno significativi sono identicamente 0.

– Mancano ancora 4 bit per avere un indirizzo intero: per il principio di località degli

accessi, la distribuzione degli indirizzi generati durante l’esecuzione di un

programma non è casuale: esiste un’elevata probabilità che a partire da un indirizzo

ne venga poi generato uno simile, cioè a pochi accessi in memoria. Per questo i 4

bit più significativi rimangono invariati rispetto a quelli del PC all’atto dell’esecuzione

di questa istruzione.

– Così facendo è come se dividessimo la memoria in 16 blocchi, poiché sono 4 i bit

26 word.

che rimangono invariati. Ognuno dei blocchi è costituito da 2

¬ L’istruzione ha il vincolo di rimanere all’interno del blocco.

j

¬ Le istruzioni di jump e di jump-and-link chiamano procedure che possono essere anche

molto distanti dal PC corrente. Utilizzano, per questo, la modalità di indirizzamento

pseudodirreto. 23

Le istruzioni

Istruzioni di salto condizionato, bne, beq:

I,

¬ utilizza il in quanto le istruzioni di salto condizionato devono specificare 2

formato

operandi oltre all’indirizzo di salto, rispetto all’istruzione di jump.

Queste istruzioni hanno a disposizione solo 16 bit per l’indirizzo di salto. Se gli indirizzi

del programma dovessero trovar posto in questo campo di 16 bit, ne seguirebbe che

16

nessun programma può avere dimensioni superiori a 2 . Una soluzione a tale

problema, consiste nella specificare un registri il cui valore deve essere sommato

all’indirizzo del salto. L’istruzione di salto condizionato dovrebbe quindi effettuare il

seguente calcolo: Program Counter=Registro+Indirizzo di salto. 32 .

La somma consentirebbe al programma di raggiungere una dimensione pari a 2

tuttavia quale registro si può utilizzare? La risposta deriva dal contesto in cui i salti

condizionati vengono utilizzati: essi si trovano tipicamente nei cicli e nei costrutti di tipo

quindi hanno la tendenza ad eseguire salti a istruzioni vicine (inferiore a 16

if,

istruzioni). Dal momento che il PC contiene l’indirizzo dell’istruzione corrente, si può

15

saltare fino a una distanza di istruzioni rispetto a quella in esecuzione, se si usa il

±2

C some registro da sommare all’indirizzo di salto. Quasi tutti i cicli e i costrutti hanno

if

16

dimensione inferiore alle 2 word, quindi il PC è la scelta ideale.

¬ Nei 16 bit a disposizione collochiamo quindi lo spostamento che vogliamo effettuare

rispetto al PC.

Esempio: le istruzioni di e (o condividono lo stesso formato: differenze?

lw beq bnq)

lw $t0, 12 ($t1)

Ð punto di partenza: $t1

Ð lo spostamento, 12, deve essere necessariamente un multiplo di 4 per rispettare il

vincolo di allineamento. Se vado all’indirizzo 1012.

$t1=1000

15 15 13 13

Ð Intervallo di spostamento è: -2 <N<2 -1 byte o -2 <N<2 -1 word.

beq $t0, $t1, 12

Ð punto di partenza: PC

Ð lo spostamento 12, non deve essere necessariamente multiplo di 4: nel campo da

16 bit per l’istruzione specifichiamo di quante istruzioni aventi o indietro rispetto

beq

al PC mi voglio muovere, non di quanti byte!Quindi effettivamente non mi sposto di

12, ma di 12x4, per rispettare il vincolo di allineamento! Se PC=1000 vado

all’indirizzo 1048. 15 15 17 17

Ð Intervallo di spostamento è: -2 <N<2 -1 word o -2 <N<2 -1 byte.

Modalità di indirizzamento del MIPS:

modalità di indirizzamento = modo in cui l’istruzione riesce a trovare le informazioni di cui

ha bisogno.

Indirizzamento immediato in cui l’operando è una costante specificata

Æ

I:

nell’istruzione. Utilizza il formato nei 16 bit riservati all’indirizzo troviamo l’operando di

nostro interesse.

1. Immediate addressing

op rs rt Immediate 24

Le istruzioni

Indirizzamento tramite registro in cui l’operando è un registro (add, sub).

Æ

2. Register addressing

op rs rt rd . . . funct Registers

Register

Indirizzamento tramite base in cui l’operando è in una locazione di memoria

Æ

individuata dalla somma del contenuto di un registro e di una costante specificata

nell’istruzione (le istruzioni di load e store).

3. Base addressing Memory

op rs rt Address + Byte Halfword Word

Register

Indirizzamento relativo al Program Counter in cui l’indirizzamento è la somma

Æ

del contenuto del Program Counter e della costante nell’istruzione (istruzioni beq, bne).

4. PC-relative addressing Memory

op rs rt Address + Word

PC

Indirizzamento pseudodirettoÆ in cui l’indirizzo è ottenuto concatenando i 26 bit

dell’istruzione con i 4 bit più significativi del PC. (istruzioni di jump)

5. Pseudodirect addressing Memory

op Address Word

PC

utilizza un indirizzamento a registro per identificare destinazione e primo

Æ

addi

operando; indirizzamento immediato per identificare la costante.

Esempio:

bne $t0, $t1, dopo

…a

…b

…c

dopo:…

se è troppo lontano?

dopo 25

Le istruzioni

Soluzione:

beq $t0, $t1, poi

j dopo

poi: …a

…b

…c

dopo:…

questa è in realtà un’operazione che fa l’assemblatore se si accorge che è troppo

dopo

lontano. E se anche è troppo lontano?

j dopo

(se è un indirizzo di word)

la $t2, dopo dopo

jr $t2

PSEUDOISTRUZIONI.

Le pseudoistruzioni sono versioni modificate delle istruzioni vere, trattate

dall’assemblatore. Queste istruzioni non devono essere implementare in hardware, ma la

loro presenza nel linguaggio assembler semplifica le fasi di traduzione e di

programmazione. Le pseudoistruzioni consentono all’assembler MIPS di avere un insieme

di istruzioni più ricco di quello implementato in hardware; l’unico costo rappresentato dal

registro $at riservato all’assemblatore.

Esempi:

Pseudo istruzione: # $t0 = $t1

move $t0, $t1

Istruzione vera: add $t0, $zero, $t1

Pseudo istruzione: blt $s1, $s2, Label

Istruzioni vere: slt $at, $s1, $s2

bne $at, $zero, Label

Altri esempi: branch condizionati a locazioni distanti trasformati in un e una

bgt, bge, ble; branch

etc.

jump, li, 26

Le istruzioni

RIASSUNTO: MIPS operands

Name Example Comments

Fast locations for data. In MIPS, data must be in registers to perform

$s0-$s7, $t0-$t9, $zero,

32 registers arithmetic. MIPS register $zero alw ays equals 0. Register $at is

$a0-$a3, $v0-$v1, $gp, reserved for the assembler to handle large constants.

$fp, $sp, $ra, $at

Memory[0], Accessed only by data transfer instructions. MIPS uses byte addresses, so

30

2 memory Memory[4], ..., sequential w ords differ by 4. Memory holds data structures, such as arrays,

words Memory[4294967292] and spilled registers, such as those saved on procedure calls.

32 registri accesso rapido ai dati. Nel MIPS i dati devono essere presenti nei registri per

Æ

eseguire operazioni aritmetiche. Il registri $zero ha sempre valore 0. il registro $at è

riservato all’assemblatore.

230 parole di memoria accesso solo tramite le istruzioni di trasferimento dati. Il MIPS

Æ

usa l’indirizzamento a byte, quindi gli indirizzi delle parole consecutive differiscono di 4

unità. La memoria contiene le strutture dati come vettori, registri riversati e i registri salvati

durante la chiamata a sottoprogramma.

MIPS assembly language

Category Instruction Example Meaning Comments

add Three operands; data in registers

add $s1, $s2, $s3 $s1 = $s2 + $s3

Arithmetic subtract Three operands; data in registers

sub $s1, $s2, $s3 $s1 = $s2 - $s3

add immediate Used to add constants

addi $s1, $s2, 100 $s1 = $s2 + 100

Memory[ + 100

load w ord Word from memory to register

lw $s1, 100($s2) $s1 = $s2

Memory[ + 100] = $s1

store w ord Word from register to memory

sw $s1, 100($s2) $s2

Data transfer Memory[ + 100

load byte Byte from memory to register

lb $s1, 100($s2) $s1 = $s2

Memory[ + 100] = $s1

store byte Byte from register to memory

sb $s1, 100($s2) $s2

load upper Loads constant in upper 16 bits

16

$s1 = 100 * 2

lui $s1, 100

immediate

branch on equal if ( ) go to Equal test; PC-relative branch

$s1 == $s2

beq $s1, $s2, 25 PC + 4 + 100

branch on not equal if ( ) go to Not equal test; PC-relative

$s1 != $s2

bne $s1, $s2, 25 PC + 4 + 100

Conditional

branch set on less than if ( ) = 1; Compare less than; for beq, bne

$s2 < $s3 $s1

slt $s1, $s2, $s3 else = 0

$s1

set less than if ( ) = 1; Compare less than constant

$s2 < 100 $s1

slti $s1, $s2, 100

immediate else = 0

$s1

go to 10000 Jump to target address

jump j 2500

Uncondi- go to

jump register For sw itch, procedure return

jr $ra $ra

tional jump = PC + 4; go to 10000

jump and link For procedure call

jal 2500 $ra

27

Le istruzioni

Lezione del 12/11/07

Vettori e puntatori.

Vediamo 2 esempi di procedure che azzerano tutti gli elementi di un vettore.

azzera

Procedura che utilizza un vettore.

azz1 (int vett[], int dim)

{ int i;

for (i=0; i<dim; i++)

vett[i] = 0;

}

Indirizzo vett = $a0, dim = $a1, i = $t0

azz1: move $t0, $zero # i = 0

L1: add $t1, $t0, $t0 # 4 * i

add $t1, $t1, $t1

add $t2, $a0, $t1 # $t2 = indirizzo di vett[i]

sw $zero, 0($t2) # vett[i] = 0

addi $t0, $t0, 1 # i = i + 1

slt $t3, $t0, $a1 # i < dim ?

bne $t3, $zero, L1 # se i < dim vai a L1

jr $ra

Innanzitutto inizializiamo l’indice a 0.

i

move $t0, $zero

Per porre vett[i]=0 per prima cosa occorre trovare il suo indirizzo: a questo scopo si

moltiplica per 4 per ottenere l’indirizzo in byte:

i add $t1, $t0, $t0

add $t1, $t1, $t1

Dal momento che l’indirizzo di partenza del vettore è in un registro, si deve sommare tale

indirizzo all’indice per ottenere vett[i]:

add $t2, $a0, $t1

In $t2 ora troviamo l’indirizzo di vett[i]. Ora si può memorizzare 0 nella locazione trovata:

sw $zero, 0($t2)

Questa istruzione è alla fine del corpo del ciclo quindi il passo successivo è

for,

incrementare l’indice i:

addi $t0, $t0, 1

Il test del ciclo verifica se i è minore della dimensione del vettore:

slt $t3, $t0, $a1

bne $t3, $zero, L1

Se i è minore della dimensione del vettore, salta a L1, altrimenti si ritorna al programma

chiamante. 28

Le istruzioni

azzera

Procedura che utilizza i puntatori.

azz2 (int *vett, int dim)

{ int *p;

for (p=&vett[0]; p<&vett[dim]; p++)

*p = 0;

}

L’indirizzo di una variabile è indicato con &, mentre l’oggetto puntato da un puntatore è

indicato da *. Dalle dichiarazioni si vede che sia sia sono puntatori a interi . La

vett p

prima parte del ciclo assegna l’indirizzo del primo elemento di al puntatore La

for vett p.

seconda parte effettua un controllo per vedere se il puntatore ha superato l’ultimo

elemento di Incrementare di uno il puntatore nell’ultima parte del ciclo significa

for

vett.

spostarlo all’elemento successivo di dimensioni pari a quelle dichiarate: dato che è un

p

puntatore a interi, il compilatore genera delle istruzioni MIPS che incrementano di 4

p

unità. L’assegnazione all’interno del ciclo pone a 0 l’oggetto puntato da p.

Indirizzo vett = $a0, dim = $a1, p = $t0

azz2: move $t0, $a0 # p = indir vett[0]

add $t1, $a1, $a1 # 4 * dim

add $t1, $t1, $t1

add $t2, $a0, $t1 # $t2 = indir di vett[dim]

L2: sw $zero, 0($t0) # mem punta

t a da p = 0

addi $t0, $t0, 4 # p = p + 4

slt $t3, $t0, $t2 # p < &vett[dim] ?

bne $t3, $zero, L2 # se è vero vai a L2

jr $ra

il codice inizia con l’assegnazione dell’indirizzo del primo elemento del vettore al puntatore

p: move $t0, $a0

calcoliamo poi l’indirizzo dell’ultimo elemento del vettore, moltiplicando la dimensione per

4 al fine riottenere il valore in byte; poniamo in $t2 l’indirizzo dell’ultimo elemento del

vettore: add $t1, $a1, $a1

add $t1, $t1, $t1

add $t2, $a0, $t1

La parte successiva è relativa al codice del corpo del ciclo che semplicemente

for,

memorizza 0 nella posizione puntata da p:

sw $zero, 0($t0)

L’istruzione successiva deve aggiornare p per far sì che punti ala parola successiva. In C

incrementare un puntatore di 1 significa farlo puntare all’oggetto successivo in sequenza:

dato che p è un puntatore a interi, ciascuno dei quali occupa 4 byte, bisogna incrementare

p di 4 unità: addi $t0, $t0, 4

La fase successiva consiste nel test di fine ciclo, che controlla che p sia minore dell’ultimo

elemento del vettore:

slt $t3, $t0, $t2

bne $t3, $zero, L2 29

Le istruzioni

Se p<dell’ultimo elemento del vettore salta a L2, altrimenti torna al main.

Confrontando le due versioni notiamo che:

Ð la prima versione deve avere la moltiplicazione e la somma necessariamente

all’interno del ciclo, dato che i viene incrementato e quindi l’indirizzo deve essere

ricalcolato a partire dal nuovo valore, mentre la versione con i puntatori incrementa

direttamente il puntatore p;

Ð la versione con i puntatori riduce da 7 a 4 il numero di istruzioni eseguite per ogni

ciclo, ed è quindi più veloce

Architetture alternative

fornire al processore istruzioni più potenti:

persegue l’obiettivo di ridurre il numero di istruzioni per eseguire varie funzioni. Tuttavia

nel fare ciò ci sono dei vantaggi, ma anche degli svantaggi: (RISC vs CISC)

vantaggi:

Ð linguaggio più compatto e ampio: posso utilizzare una sola istruzione per

compiere che svolge determinati compiti invece che costruirmi passo per passo

piccole istruzioni che possano alla fine svolgere lo stesso compito;

svantaggi:

Ð ci sono tante istruzioni che assolvono tante funzioni diverse: è più difficile la scelta

e la memorizzazione per il programmatore;

Ð il tempo di ciclo per ogni istruzione è maggiore: ho bisogno di più periodi di clock

per portare a termine una singola istruzione. Non bisogna dimenticare che avere

tante istruzioni diverse porta all’effetto n+1: aggiungere varie istruzioni in più

rallenta in realtà, l’esecuzione di tutte le istruzioni,anche quelle fondamentali, in

quanto l’hardware ha molta scelta e quindi impiega più tempo ad arrivare

all’istruzione giusta. (RISC vs CISC)

Riassunto: i principi di progetto.

Semplicità e regolarità sono strettamente correlate la ricerca della regolarità è alla

Æ

base di molte delle caratteristiche dell’insieme delle istruzioni MIPS:stessa dimensione per

tutte le istruzioni, sempre 3 operandi di tipo registro nelle istruzioni aritmetiche, campi

registro sempre nelle stesse posizioni all’interno di tutti i formati di istruzioni…

Minori sono le dimensioni, maggiore è la velocità la velocità di esecuzione è il

Æ

motivo per cui il MIPS ha 32 registri anziché molti di più.

Rendere il caso veloce il più frequente esempi di questo tipo che riguardano il MIPS

Æ

includono il modo di indirizzamento relativo al PC per i salti condizionati e l’indirizzamento

immediato per gli operandi costanti …

Un buon progetto richiede buoni compromessi esempi relativi al MIPS è la scelta di

Æ

3 formati di istruzioni anziché 1, il fatto di avere registri dedicati ($ra, $zero), il

compromesso che permette di specificare indirizzi e costanti grandi pur mantenendo la

stessa lunghezza per tutte le istruzioni… 30

Aritmetica dei calcolatori.

Ï

Ð CAPITOLO 3

-L’ARITMETICA DEI CALCOLATORI-

Lezione del 14/11/07.

I bit sono solo bit e non hanno un significato intrinseco. Le convenzioni definiscono le

relazioni tra bit e numeri.

I numeri che dobbiamo gestire sono di dimensioni finite, cioè hanno un intervallo di

rappresentazione finito: ciò porta al problema dell’overflow, cioè del superamento della

capacità di rappresentazione per i numeri in complemento a 2.

Ci sono diversi modi per rappresentare numeri con il segno:

Modulo e segno Complemento a 1 Complemento a 2

000 = +0 000 = +0 000 = +0

001 = +1 001 = +1 001 = +1

010 = +2 010 = +2 010 = +2

011 = +3 011 = +3 011 = +3

100 = -0 100 = -3 100 = -4

101 = -1 101 = -2 101 = -3

110 = -2 110 = -1 110 = -2

111 = -3 111 = -0 111 = -1

Osservazioni:

Ð In tutte e 3 le configurazioni, il bit più significativo, cioè quello più a sinistra, è un

indicatore del segno del numero: se è 0 il numero è positivo, se è 1 il numero è

negativo.

Ð Nelle configurazioni Modulo e Segno, Complemento a 1, ho due rappresentazioni dello

0,ciò comporta il bilanciamento tra il numero di configurazioni per i numeri negativi e i

numeri positivi.

Ð Nella configurazione Complemento a 2, c’è una sola rappresentazione dello 0: ciò

comporta uno sbilanciamento tra numeri positivi e numeri negativi: i numeri negativi

vano da 1 a 3, mentre i numeri negativi da -1 a -4.

¬ Problema: A+B se A=0 => posso sempre farlo, non ho problemi!

A-B se A=0 e B=-4 => A+B=4 non è rappresentabile in Ca2:

overflow!!!

----------dal passato--------

Come rappresentare i numeri negativi.

Rappresentazione in Modulo e Segno (anche detta Binario Naturale)

Si utilizza un bit per rappresentare il segno del numero considerato

0 + (numero positivo)

1 - (numero negativo) Numero 7

Se consideriamo un byte, rimangono ora 7 bit per il 6

modulo del numero: i numeri rappresentabili sono 5

±[0-127]

perciò 4

3

+/- b6 b5 b4 b3 b2 b1 b0 Rappresentazione

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

-1

Ho 2 problemi: -2

1. il doppio 0; -3

2. andamento del grafico prima crescente e poi -4

decrescente: è difficile stabilire quale fra due -5

numeri è maggiore e quale è minore. 31

Aritmetica dei calcolatori.

Significato in Rappresentazione Significato in

modulo e segno binaria valore

assoluto

+7 0 111 7

+6 0 110 6

+5 0 101 5

+4 0 100 4

+3 0 011 3

+2 0 010 2

+1 0 001 1

+0 0 000 0

-0 1 000 8

-1 1 001 9

-2 1 010 10

-3 1 011 11

-4 1 100 12

-5 1 101 13

-6 1 110 14

-7 1 111 15

Addizione e sottrazione sono le operazioni di cui si deve disporre per poter realizzare

qualsiasi operazione aritmetica più complessa. Si supponga che il calcolatore abbia una

“Unità Aritmetica” che realizzi indipendentemente le due operazioni. Di fronte ad una

somma algebrica, il calcolatore dovrebbe:

Ð confrontare i due segni.

Ð se uguali, attivare il circuito di addizione.

Ð se diversi, identificare il maggiore (in valore assoluto) ed attivare il circuito di

sottrazione.

Ð completare il risultato con il segno corretto.

I passi indicati non sono eseguibili contemporaneamente perché ognuno dipende dai

precedenti. In pratica per effettuare somma e sottrazione si ricorre ad un unico circuito,

utilizzando un metodo che permette di evitare le operazioni di confronto.

Complemento alla base. n

Nella rappresentazione in complemento alla base con n cifre le b combinazioni

rappresentano numeri positivi e negativi.

In particolare: n

Ð /2 - 1 rappresentano i numeri positivi, rispettando la

Le combinazioni da 0<p<b

usuale rappresentazione posizionale;

n n

Ð Le combinazioni da b /2<n<b – 1 rappresentano i numeri negativi, con la seguente

definizione: n

dato un numero positivo X, il suo corrispondente negativo è dato da: b -X

b=2, n=5 b=2, n=7

Positivi da 0 a 01111 Positivi da 0 a 0111111

Negativi da 10000 a 11111 Negativi da 1000000 a 1111111

X = 01011; trovo -X X=0011000; trovo -X

1 0 0 0 0 0 - 1 0 0 0 0 0 0 0 -

0 1 0 1 1 = 0 0 1 1 0 0 0 =

1 0 1 0 1 1 1 0 1 0 0 0

32

Aritmetica dei calcolatori.

Regola pratica: partendo dal bit meno significativo, si riportano invariati tutti i bit fino al

→ →

primo bit a 1 compreso; si complementano i rimanenti bit (0 1, 1 0). Oppure:

complemento ogni singolo bit e aggiungo 1, in quanto il complemento alla base è uguale al

complemento alla base meno 1, +1.

Complemento alla base -1. n combinazioni

Nella rappresentazione in complemento alla base -1 con n cifre le b

rappresentano numeri positivi e negativi.

In particolare: n

Ð Le combinazioni da 0<p<b /2 - 1 rappresentano i numeri positivi, rispettando la

usuale rappresentazione posizionale;

n n

Ð /2<n<b – 1 rappresentano i numeri negativi, con la seguente

Le combinazioni da b

definizione: n

dato un numero positivo X, il suo corrispondente negativo è dato da: (b -1)-X

X=36, b=10, n=2

in complemento alla base -1 è: 99 - 36 = 63

Si ottiene complementando a 9 ogni singola cifra

X=01011, b=2, n=5 5

-X in complemento alla base -1 è: (2 - 1) - X = (100000 - 1) - X => 1111 - 01011 = 10100

→ →

Regola pratica: si ottiene complementando ogni singolo bit (0 1, 1 0)

Quindi per la rappresentazione in complemento:

Ð Rappresentazione in complemento a 2: i numeri positivi sono rappresentati dal loro

modulo e hanno il bit più significativo (segno) posto a 0. I numeri negativi sono

rappresentati dalla quantità che manca al numero positivo per arrivare alla base

elevata al numero di cifre utilizzate, segno compreso. Pertanto i numeri negativi hanno

il bit del segno sempre a 1.

Ð Metà delle configurazioni sono perciò riservate ai numeri positivi e metà ai numeri

negativi.

Ð Discorsi analoghi possono essere fatti per basi diverse da 2: in base 10 un numero è

≥ ≥ ≥

negativo se la prima cifra è 5, in base 8 se 4, in base 16 se 8.

Per la rappresentazione in complemento alla base:

Con n bit a disposizione: n-1

Ð Il numero minimo rappresentabile è -2 n-1

Ð Il numero massimo rappresentabile è 2 – 1.

Ð -1 è rappresentato da tutti 1 qualunque sia il numero di bit considerato.

Ð Il numero può essere interpretato considerando il bit più significativo con segno

negativo.

Utilità del complemento alla base:

Con la tecnica del complemento si può utilizzare un solo circuito per effettuare sia

l’addizione, sia la sottrazione.

Operiamo in base 10 e vogliamo calcolare A – B. Si supponga di conoscere il risultato

dell’operazione 10 - B (complemento a 10 di B). Allora:

A - B = A + (10 - B) a condizione che si trascuri il riporto k

Analogo discorso con k cifre purché si disponga del risultato dell’operazione 10 – B

k

(complemento a 10 ). Si ricordi sempre di fissare il numero di cifre.

33

Aritmetica dei calcolatori.

Se operiamo in base 2, con k cifre:

k

A - B = A + (2 - B) a condizione che si trascuri il riporto.

Se si utilizza la tecnica del complemento alla base -1 occorre sommare il riporto al risultato

finale.

esempi:

Complemento a 2 Complemento a 1

19 + (-17) 19 + (-17)

0 1 0 0 1 1 0 1 0 0 1 1

1 0 1 1 1 1 1 0 1 1 1 0

1 0 0 0 0 1 0 (+2) 0 0 0 0 0 1

1

0 0 0 0 1 0 (+2)

Complemento a 2 Complemento a 1

(-17) + (-2) (-17) + (-2)

1 0 1 1 1 1 1 0 1 1 1 0

1 1 1 1 0 1

1 1 1 1 1 0

1 1 0 1 1 0 1 (-19) 1 1 0 1 0 1 1

1

1 0 1 1 0 0 (-19)

Problemi:

somma di due numeri positivi con 6 cifre binarie.

19 + 17

0 1 0 0 1 1 +

0 1 0 0 0 1 =

1 0 0 1 0 0 (-28)

Si sono sommati due numeri positivi e si è ottenuto un numero negativo. Il risultato

corretto (+36) non è rappresentabile in complemento a 2 con 6 bit (massimo numero

rappresentabile = + 31).Il fenomeno si chiama traboccamento o overflow.

Complemento a 2

(-19) + (-17)

1 0 1 1 0 1 +

1 0 1 1 1 1 =

1 0 1 1 1 0 0 (28)

Si sono sommati due numeri negativi e si è ottenuto un numero positivo. Il risultato

corretto (-36) non è rappresentabile in complemento a 2 con 6 bit (minimo numero

rappresentabile = -32 in C.a 2 e –31 in C. a 1).Il fenomeno si chiama traboccamento o

overflow.

0 1 1 1 1 0 0 0 + Complemento a 2 Valore Assoluto

= + 120 + 120 +

0 1 1 0 1 0 0 1

1 1 1 0 0 0 0 1 + 105 = 105 =

- 31 225

Overflow=1 (si) Riporto=0 (no)

34

Aritmetica dei calcolatori.

1 1 1 1 1 0 1 1 + Complemento a 2: Valore assoluto:

1 1 1 1 0 0 0 0 = - 5 + 251 +

1 1 1 0 1 0 1 1 - 16 = 240 =

- 21 235

Overflow=0 Riporto=1

Somma di numeri in complemento a 2.

≤ ≤

≤ ≤ ≤ ≤

N-1 N-1 N-1 N-1

-2 0 A 2 -2

0 A 2 -1 A < 0 -1 A < 0

≤ ≤

≤ ≤ ≤ ≤

N-1 N-1 N-1 N-1

-1 -1 B < 0 B < 0

0 B 2 0 B 2 -2 -2

≤ ≤ ≤ ≤ ≤

N N-1 N-1 N-1 N-1 N

0 S 2 -2 -2 S < 2 -1 -2 S < 2 -1 -2 S < 0

Sommando due Non ci sono mai Non ci sono mai Sommando due

numeri positivi si problemi di problemi di numeri negativi si

ha overflow se si overflow. overflow. ha overflow se si

ottiene un ottiene un

numero negativo. numero positivo.

S potrebbe non S potrebbe non

essere essere

rappresentabile in rappresentabile in

N bit ma lo è N bit ma lo è

sempre in N+1 sempre in N+1

bit. bit.

32 bit signed numbers:

0000 0000 0000 0000 0000 0000 0000 0000 = 0

two ten

= + 1

0000 0000 0000 0000 0000 0000 0000 0001 two ten

0000 0000 0000 0000 0000 0000 0000 0010 = + 2

two ten

...

0111 1111 1111 1111 1111 1111 1111 1110 = + 2,147,483,646

0111 1111 1111 1111 1111 1111 1111 1111 = + 2,147,483,647

1000 0000 0000 0000 0000 0000 0000 0000 = – 2,147,483,648

1000 0000 0000 0000 0000 0000 0000 0001 = – 2,147,483,647

1000 0000 0000 0000 0000 0000 0000 0010 = – 2,147,483,646...

1111 1111 1111 1111 1111 1111 1111 1101 = – 3

1111 1111 1111 1111 1111 1111 1111 1110 = – 2

1111 1111 1111 1111 1111 1111 1111 1111 = – 1

Siano:

$t0=0000 0000 0000 0000 0000 0000 0000 0000 = 0

$t1=1111 1111 1111 1111 1111 1111 1111 1111 = – 1

Quanto vale

slt $t2, $t0, $t1 $t2?

Ð Se i numeri sono pensati in complemento a 2 $t2 vale 0: $t0=0 non è minore di

$t1=-1!

Ð Può capitare, tuttavia, che al programmatore interessi lavorare con degli indirizzi:

siano ora $t0 e $t1 due registri che contengono indirizzi di memoria. In questo caso

$t0<$t1, poiché i numeri sono pensati in valore assoluto, in quanto non ha senso

prevedere degli indirizzi di memoria negativi!

È necessario utilizzare quindi 2 istruzioni diverse:

35


ACQUISTATO

2 volte

PAGINE

68

PESO

1.52 MB

PUBBLICATO

+1 anno fa


DESCRIZIONE APPUNTO

Appunti completi sul corso di calcolatori elettronici.
Cisc risc -macchina di von neumann - struttura cpu - formato istruzione - formato istuzioni mips - gestione subroutine (chiamate a sottoprogrammi) - uso dello stack - procedure annidate - gestione dello stack - gestione caratteri - operandi immediati - indirizzamenti - vettori e puntatori - aritmetica calcolatori - complemento alla base - complemento alla base -1 - overflow - underflow - estensione del segno -rappresentazione numeri in virgola fissa -rappresentazione numeri in virgola mobile


DETTAGLI
Corso di laurea: Corso di laurea in ingegneria informatica (MANTOVA - PAVIA)
SSD:
Università: Pavia - Unipv
A.A.: 2013-2014

I contenuti di questa pagina costituiscono rielaborazioni personali del Publisher ilario.pirini di informazioni apprese con la frequenza delle lezioni di Calcolatori elettronici e studio autonomo di eventuali libri di riferimento in preparazione dell'esame finale o della tesi. Non devono intendersi come materiale ufficiale dell'università Pavia - Unipv o del prof Danese Giovanni.

Acquista con carta o conto PayPal

Scarica il file tutte le volte che vuoi

Paga con un conto PayPal per usufruire della garanzia Soddisfatto o rimborsato

Recensioni
Ti è piaciuto questo appunto? Valutalo!

Altri appunti di Calcolatori elettronici

Reti logiche
Appunto
Programma per MIPS
Esercitazione
Preparazione all'esame di Calcolatori elettronici
Appunto
MIPS Instruction Set
Appunto