Stored Program
•
•
•
•
•
•
Istruzioni sono stringhe di bit
Programmi: sequenze di istruzioni
Programmi (come i dati) memorizzati in memoria
La CPU legge le istruzioni dalla memoria (come i dati)
Ciclo macchina (ciclo Fetch – Decode – Execute)
• La CPU legge (fetch) l’istruzione corrente (indirizzata da un
registro Program Counter = PC), e la pone in un registro
speciale interno
• La CPU usa i bit dell’istruzione per "controllare" le azioni da
svolgere, e su questa base esegue l’istruzione
CPU determina la “prossima” istruzione e ripete il ciclo
Operandi e memoria
•
I dati devono essere prelevati dalla memoria prima che le
operazioni possano utilizzarli
Load word
lw $t0, indirizzo-di-memoria
•
Processore
Registro
Memoria
I dati devono essere immagazzinati in memoria quando
necessario
Store word
sw $t0, indirizzo-di-memoria
Processore
Registro
Memoria
Operandi e memoria
•
Il compilatore organizza i dati del programma nella memoria
•
Conosce la locazione in memoria di ogni variabile del programma
•
Per ogni istruzione di load/store genera l’opportuno indirizzo di memoria
int a int b int c int d[10]
indirizzo base
…
Operandi immediati
•
Una istruzione potrebbe richiedere una costante come input
•
Un’istruzione immediata usa una costante numerica come uno
degli input (al posto di un operando registro)
addi $s0, $zero, 1000
# l’indirizzo base del programma è 1000
# ed è memorizzato in $s0
immediate
# $zero è un registro speciale
# contenente sempre 0
addi $s1, $s0, 0
# indirizzo della variabile a
addi $s2, $s0, 4
# indirizzo della variabile b
addi $s3, $s0, 8
# indirizzo della variabile c
addi $s4, $s0, 12
# indirizzo della variabile d[0]
Indirizzamento della memoria
•
Siccome la dimensione minima di una cella di memoria si 1 byte,
l’indirizzamento di memoria è “al byte” (indirizzamento al byte)
•
Nel MIPS (e in molte altre architetture) è obbligatorio che le parole
di memoria abbiano indirizzi multipli di 4 (vincolo di allineamento)
•
Codice C:
d[3] = d[2] + a
•
Assembler:
lw $t0, 8($s4)
# d[2] è caricato in $t0
lw $t1, 0($s1)
# a è caricato in $t1
offset
add $t0, $t0, $t1 # la somma è in $t0
sw $t0, 12($s4) # $t0 è scaricato in d[3]
Istruzioni Aritmetico/Logiche
•
•
•
•
•
•
Le istruzioni aritmetiche del MIPS permettono solo
operazioni elementari (add, sub, mult, div) tra coppie di
operandi a 32 bit
Le istruzioni logiche (and, or) sono bit a bit
Tutte le istruzioni hanno 3 operandi
L’ordine degli operandi è fisso
L’operando destinazione in prima posizione
Esempio
• Codice C: A = B + C
• Codice Assembler: add $t0, $s1, $s2
• Il compilatore associa le variabili ai registri
Codifica in formato R-Type
esempio
add $t0, $s1, $s2
semantica
$t0 = $s1 + $s2
codifica
000000 10001 10010 01001 00000 100000
op
op:
rs
rt
rd
shamt
funct
operazione base dell’istruzione
rs: registro del primo operando
rt: registro del secondo operando
rd: registro destinazione, che contiene il risultato dell’operazione
shamt: utilizzato per istruzioni di shift; posto a zero per le altre istruzioni
funct: seleziona la specifica variante dell’operazione base definita nel campo op
Istruzioni di trasferimento dati
•
•
•
•
•
•
Leggere dalla memoria su registro: lw (load word)
Scrivere da registro alla memoria: sw (store word)
Esempio:
A è un array di
numeri interi
• Codice C: A[8] += h
• Codice Assembler: lw $15, 32($4)
add $15, $5, $15
sw $15, 32($4)
displacement
Indirizzo di memoria &A[8] → $4 + 32
Nota: sw ha la destinazione come ultimo operando
Nota: le istruzioni aritmetiche operano su registri, non su
celle di memoria.
Codifica in formato I-Type
esempio
lw $t0, 32($s3)
semantica
$t0 = memory[$s3] + 32
codifica
000000 10010 01001 0000000000100000
op
rs:
rs
rt
16-bit constant
registro della locazione di memoria
rt: registro destinazione
16-bit constant: operando immediato (displacement)
Questo formato codifica anche operazioni aritmetico-logiche
con valori immediati, i.e., costanti: addi $t0, $s1, 8
Operazioni Logiche
esempio
sll $t2, $s0, 4
semantica
$t2 = $s0 << 4
codifica
000000 00000 10000 01010 00100 000000
0
0
rt
rd
shamt
0
Istruzioni di controllo del flusso
•
•
•
Il flusso di esecuzione è normalmente sequenziale
Le istruzioni di controllo cambiano la prossima istruzione
da eseguire
Istruzioni di salto condizionato
branch if equal
beq $s4, $s5, LABEL
•
Esempio
if (i == j)
i = i + j;
...
•
branch if not equal
bne $s6, $s5, LABEL
bne $s4, $s5, LABEL
add $s4, $s4, $s5
LABEL: ...
Formato I-Type (operando immediato relativo a PC)
Istruzioni di controllo del flusso
•
Salto non condizionato
j LABEL
•
Esempio
if (i != j)
h = i + j;
else
h = i – j;
...
•
ELSE:
EXIT: ...
beq $s4, $s5, ELSE
add $3, $4, $5
j EXIT
sub $3, $4, $5
Formato J-Type
op
26-bit constant
Istruzioni di controllo del flusso
•
•
•
Come facciamo a esprimere “Salta se minore o uguale di”?
In MIPS c’è un’istruzione aritmetica, set-on-less-than
Istruzione
Significato
slt $t1, $s4, $s5
if ($s4 < $s5)
$t1 = 1;
else
$t1 = 0;
Formato R-Type / I-Type (versione immediata)
Esempio: Ciclo
Tradurre il seguente codice C in codice assembly:
while (save[i] == k) i += 1;
i e j sono, rispettivamente, in $s3 e $s5 and la base dell’array save è in $s6
Loop: sll
Exit:
$t1, $s3, 2
# Moltiplico i per 4
add
$t1, $t1, $s6 # Calcolo l’indirizzo di save[i]
lw
$t0, 0($t1)
bne
$t0, $s5, Exit # Condizione di uscita dal ciclo
addi
$s3, $s3, 1
# Corpo del ciclo
j
Loop
# Ricomincio…
# Carico save[i] in $t0
Procedure
Per eseguire una procedura (detta callee, chiamato), un
programma (detto caller, chiamante) deve eseguire 6 passi:
1. mettere i parametri in un luogo accessibile alla procedura
2. trasferire il controllo alla procedura
3. acquisire le risorse necessarie per l’esecuzione della procedura
4. eseguire il compito richiesto
5. mettere il risultato in un luogo accessibile al chiamante
6. restituire il controllo al chiamante
Registri MIPS
I 32 registri MIPS sono partizionati come segue:
•
Reg 0
: $zero
memorizza sempre la costante 0
•
Regs 2-3
: $v0, $v1
valori di ritorno di una procedura
•
Regs 4-7
: $a0-$a3
valori di ingresso di una procedura
•
Regs 8-15 : $t0-$t7
registri temporanei
•
Regs 16-23 : $s0-$s7
registri variabili
•
Regs 24-25 : $t8-$t9
altri registri temporanei
•
Reg 28
: $gp
global pointer
•
Reg 29
: $sp
stack pointer
•
Reg 30
: $fp
frame pointer
•
Reg 31
: $ra
return address
Jump-and-Link
•
Un registro speciale contiene l’indirizzo dell’istruzione correntemente
eseguita – questo registro è il program counter (PC)
•
L’invocazione della procedura è eseguita invocando l’istruzione jump-andlink (jal)
•
Il valore corrente di PC (in realtà PC+4) è salvato nel registro $ra
•
Si salta all’indirizzo iniziale della procedura specificato come parametro
dell’istruzione jal
•
Poiché jal potrebbe sovrascrivere un valore pre-esistente di $ra, questo
deve essere salvato in memoria prima di invocare l’istruzione jal
•
Tramite l’istruzione jump-register $ra si ripristina il flusso di controllo del
chiamante al termine della procedura
•
Cosa succede se i registri $a0-$a3 e $v0, $v1 non sono sufficienti?
Stack
•
Bisogna copiare il contenuto dei registri in memoria
•
La struttura dati utilizzati è lo stack (pila), una coda di tipo LIFO (lastin first-out) utilizzata per salvare il contenuto dei registri
•
Per ragioni storiche, lo stack “cresce” verso indirizzi di memoria bassi
•
L’indirizzo dell’elemento dello stack allocato più di recente è
memorizzato nello stack pointer ($sp)
•
•
Inserendo dati nello stack (push), il valore di $sp diminuisce
•
Estraendo dati dallo stack (pop), il valore di $sp aumenta
Per convenzione, il contenuto dei registri $s0-$s7 deve essere salvato
sullo stack prima dell’invocazione di una procedura
Gestione dei dati dello stack
•
Una nuova procedura deve creare spazio per tutte le sue variabili
sullo stack
•
Prima di eseguire la jal, il chiamante deve salvare i valori necessari
dei registri $s0-$s7, $a0-$a3 e $ra nel suo stack
•
Gli argomenti sono copiati in $a0-$a3 e l’istruzione jal è eseguita
•
Il chiamato può creare il suo spazio stack, aggiornando il valore di
$sp
•
Al termine dell’invocazione, il chiamato copia il valore di ritorno in $v0
e libera lo stack se lo ha occupato
•
Il chiamante può recuperare dallo stack i suoi valori precedentemente
salvati ($s0-$s7, $a0-$a3 e $ra)
Esempio
int leaf_example (int g, int h, int i, int j)
{
int f;
f = (g + h) – (i + j);
return f;
}
indirizzi alti
$sp
indirizzi bassi
Memoria
leaf_example:
addi
$sp, $sp, -4
sw
$s0, 0($sp)
add
$t0, $a0, $a1
add
$t1, $a2, $a3
sub
$s0, $t0, $t1
add
$v0, $s0, $zero
lw
$s0, 0($sp)
addi
$sp, $sp, 4
jr
$ra
Nuovi dati delle procedure
Codici ASCII
•
load byte: lb $t0, 0($sp)
•
store byte: sb $t0, 0($sp)
Esempio
void strcpy(char x[], char y[])
{
int i;
i=0;
while ((x[i] = y[i]) != `\0’)
i += 1;
}
strcpy:
addi
sw
add
L1:
add
lb
add
sb
beq
addi
j
L2:
lw
addi
jr
$sp, $sp, -4
$s0, 0($sp)
$s0, $zero, $zero
$t1, $s0, $a1
$t2, 0($t1)
$t3, $s0, $a0
$t2, 0($t3)
$t2, $zero, L2
$s0, $s0, 1
L1
$s0, 0($sp)
$sp, $sp, 4
$ra
Grandi costanti
•
Le istruzioni immediate possono specificare solo costanti
su 16 bit
•
L’istruzione lui è usata per copiare costanti a 16 bit nei 16
bit più significativi di un registro
•
Combinando questa istruzione con un ori (OR immediato)
possiamo copiare costanti a 32 bit
Grandi costanti
•
Le istruzioni immediate possono specificare solo costanti su 16 bit
•
L’istruzione lui è usata per copiare costanti a 16 bit nei 16 bit più
significativi di un registro
•
Combinando questa istruzione con un ori (OR immediato) possiamo
copiare costanti a 32 bit
•
Nei salti condizionati (beq, bne) l’indirizzo di salto (nuovo valore di
PC) è una costante a 16 bit, relativa al valore corrente di PC
•
Nel salto (j) l’indirizzo di salto è una costante a 26 bit, di valore
assoluto
•
Se necessario, possiamo usare il contenuto di un altro registro come
base
Metodi di indirizzamento del MIPS
1. Indirizzamento immediato: l’operando è
una costante contenuta nell’istruzione
2. Indirizzamento tramite registro: l’operando
è in un registro
3. Indirizzamento tramite base e
spiazzamento: l’operando è in una cella di
memoria individuata sommando il contenuto
di un registro con una costante contenuta
nell’istruzione
4. Indirizzamento relativo a PC: l’indirizzo di
salto è ottenuto sommando il contenuto di PC
con una costante contenuta nell’istruzione
5. Indirizzamento pseudodiretto: l’indirizzo di
salto è ottenuto concatenando i 26 bit
nell’istruzione con i 4 bit più significativi di PC