“LabArch 2003”

Transcript

“LabArch 2003”
[Docente H. Muccini] http://www.di.univaq.it/~muccini/ArchLab03
“LabArch 2003”
Laboratorio di
Architetture degli
Elaboratori
Terzo Quadimestre, anno 2003
Lecture 6 e 7:
- Procedure
- Stack per le procedure
- Procedure annidate
- Procedure ricorsive
2003 Henry Muccini
LabArch2003
(parte della)
Architettura del MIPS
SEA Group
MAR
Memoria
MBR
R1R2 … R32
32
bit
MEMORIA
ALU
Bus
CPU
2003 Henry Muccini
2/28
1
LabArch2003
Procedure
Int
{
SEA Group
SommaTernaria (int a, int b, int c)
int d;
d = a + b + c;
return d;
}
2003 Henry Muccini
3/28
LabArch2003
SEA Group
Steps per una procedura
1.
2.
3.
4.
5.
6.
Assegnare uno spazio ai parametri
Salto alla procedura
Ottenimento dei Registri necessari alla
procedura
Computazione
Mettere il risultato in un registro
accessibile dal programma chiamato
Salto al programma chiamante
2003 Henry Muccini
4/28
2
LabArch2003
SEA Group
Idea
Main
Istruzione 1;
Istruzione 2;
Registri
$a0 - $a3:
$v0 - $v1:
$ra:
Procedura (par1, par2);
Istruzione 3;
…
Procedura (par1, par2)
Istruzione P1
Istruzione P2
Istruzione P3
Registri per il passaggio dei
parametri
Registri per il ritorno dei
risultati
Registro per memorizzare
l’indirizzo dell’istruzione di
ritorno
end
2003 Henry Muccini
5/28
LabArch2003
SEA Group
Riassunto sui Registri
$s0 - $s7: 8 registri dati
$t0 - $t7: 8 registri per dati temporanei
$a0 - $a3: 4 registri per i parametri
$v0 - $v1: 2 registri per i risultati
$ra: 1 registro per il ritorno da procedura
Mancano ancora 9 registri
2003 Henry Muccini
6/28
3
LabArch2003
SEA Group
Istruzioni per Procedure
jal IndirizzoProcedura
Per saltare ad una procedura
Main
Istruzione 1
Istruzione 2
jal ProceduraSomma # diverso da “j”, poiche’...
Istruzione 3
ProceduraSomma
Istruzione P1
jr $ra
“jal” memorizza
il PC+4
nel registro di
ritorno $ra
2003 Henry Muccini
7/28
LabArch2003
SEA Group
Problema
? Cosa accade se necessitiamo, dentro una
procedura, di altri registri, rispetto ai 4 registri
per i parametri e piu’ di 2 per i risultati???
$a0 - $a3 : 4 registri per i parametri
$v0 - $v1 : 2 registri per i risultati
Necessito anche di $t0, $t1, $s0, per fare calcoli!!!
Il problema e’ nel fatto che $t0, $t1, $s0
potrebbero essere gia’ in uso dal chiamante!!!
2003 Henry Muccini
8/28
4
LabArch2003
Grafichiamo il problema
Main:
$t0
SEA Group
$t1
$s0
Istr1 Tali istruzioni
usano $t0, $t1, $s0
Istr2
Jal Proc
???Dov’e’ il problema???
Istr3
Proc:
IstrP1
Jr $ra
Tale istruzione
usa $t0, $s0
2003 Henry Muccini
9/28
LabArch2003
SEA Group
Stack per le Procedure
Cos’e’ una pila (o stack) e come funziona
Numerazione di uno stack nel MIPS
100
99 … 80
…
1
Stack, in MIPS, e’ un registro $sp dove vengono memorizzati
temporaneamente le informazioni sui Registri in uso dal Main
Idea:
Quando Main chiama Proc:
creo spazio per tutte le variabili usate in Proc ($t0, $s0) nello stack
memorizzo tali variabili nello stack
Quando Proc rida’ il controllo a Main:
rimetto nei registri utilizzati da Proc ($t0, $s0) i valori iniziali
pulisco lo stack
1.
2.
3.
4.
2003 Henry Muccini
10/28
5
LabArch2003
Esempio
SEA Group
Int EsempioProc (int a, int b, int c){
int x;
x = (a+b) - c
return x}
Analisi: ho bisogno di due registri non dedicati
x $s0 (registro che potrebbe essere gia’ in uso)
a+b $t0 (registro temporaneo che potrebbe essere gia’ in uso)
a $a0, b $a1, c $a2 (registri dei parametri)
$v0 per il risultato (registro per risultati)
2003 Henry Muccini
11/28
LabArch2003
Esempio (cont.)
SEA Group
EsempioProc:
sub $sp, $sp, 8 # alloco due spazi nello stack
sw $s0, 4($sp)
sw $t0, 0($sp) # memorizzo I reg. nello stack
add $t0, $a0, $a1 # (a+b)
sub $s0, $t0, $a2 # x = (a+b) – c
add $v0, $s0, $zero # setto il risultato
lw $t0, 0($sp)
lw $s0, 4($sp) # ripristino I vecchi valori di $t0 e $s0
add $sp, $sp, 8
jr $ra
2003 Henry Muccini
12/28
6
LabArch2003
SEA Group
Alcune note
Nota l’ordine con cui le operazioni “sw” e
“lw” vengono eseguite sullo stack (lifo)
E’ proprio uno stack!
4
100
99 … 80
…
0
1
Nota: i registri temporanei solitamente
non vengono salvati e ripristinati
Semplificazione sull’esempio precedente
2003 Henry Muccini
13/28
LabArch2003
SEA Group
Da fare in classe
Int SommaTernaria (int a, int b, int c)
{
}
int d;
d = a + b + c;
return d;
2003 Henry Muccini
14/28
7
LabArch2003
d $s0 (registro che potrebbe essere gia’ in uso)
a+b $t0 (registro temporaneo)
a $a0, b $a1, c $a2 (registri dei parametri)
$v0 per il risultato (registro per risultati)
SEA Group
SommaTernaria:
sub $sp, $sp, 4 # alloco uno spazio nello stack
sw $s0, 0($sp) # memorizzo il reg. $s0 nello stack
add $t0, $a0, $a1 # (a+b)
add $s0, $t0, $a2 # d = (a+b) + c
add $v0, $s0, $zero # setto il risultato
lw $s0, 0($sp) # ripristino il vecchio valore di $s0
add $sp, $sp, 4
jr $ra
2003 Henry Muccini
15/28
LabArch2003
Procedure Annidate
SEA Group
Int SommaTernaria (int a, int b, int c)
{ int d;
int e;
d = Somma (a, b);
e = Somma (c, d);
return e;}
Int Somma (int a, int b)
{ int c;
c = a + b;
return c;}
2003 Henry Muccini
16/28
8
LabArch2003
Ricordiamo come i registri vengono
usati nelle procedure
Main:
I parametri
sono in $ai
Istr1
Istr2
Jal Proc
Istr3
Proc:
Salvo i
risultati in $vi
IstrP1
Jr $ra
SEA Group
Salva PC+4 in
$ra
Salvo i registri $si
nello stack pointer
$sp
Ripristino i registri
$si dallo stack
pointer $sp
2003 Henry Muccini
Procedure Annidate in MIPS
17/28
LabArch2003
SEA Group
Abbiamo bisogno di memorizzare piu’ registri
Main:
istr.1
istr.2
jal Procedure #passo parametri
istr.3
Procedure:
istr. p1
“Procedure” usa
jal Procedure2 #passo parametri $ai per i parametri
istr. p2
$vi per i risultati
jr $ra
Procedure2
!!! Entrambi usano gli stessi registri !!!
istr. Q “Procedure2” usa
jr $ra
$ai per i parametri
$vi per i risultati
2003 Henry Muccini
18/28
9
LabArch2003
SEA Group
Inoltre…
Main:
istr.1
istr.2
jal Procedure
#passo parametri
istr. p1
jal Procedure2
#passo parametri
istr. P2
jr $ra
Procedure2
istr. Q
jr $ra
$ra l’indirizzo di
ritorno
istr.3
Procedure:
“jal” del Main salva in
“jal” di Procedure
salva in
$ra l’indirizzo
di ritorno
!!! Entrambi usano lo stesso registro !!!
Se Procedure sovrascrivesse $ra, non
sarebbe piu’ possibile tornare a Istr. 3 del
Main
2003 Henry Muccini
19/28
LabArch2003
SEA Group
Quindi
Se si lavora con procedure annidate,
bisogna salvare:
I registri $si che potrebbero essere in uso dal
chiamante
I registri $ai per i parametri
Il registro $ra per mantenere l’indirizzo del
chiamante
Lo stack pointer $sp va’ aggiornato per tener
conto del numero di registri memorizzati nello
stack
2003 Henry Muccini
20/28
10
LabArch2003
SEA Group
Uso dei registri in procedure annidate
I parametri
sono in $ai
Main:
…
Jal Proc1
Istr3
Proc1:
Come programma chiamante
IstrP1
Jal Proc2
Jr $ra
Salvo i registri
Salva PC+4 in $ra
Come programma chiamato
Salvo i registri $si nello
stack pointer $sp
Come programma chiamato
Salvo i risultati in
$vi
$ai ed $ra nello
stack pointer
$sp
Proc2:
Come programma chiamante
IstrP2
Ripristino i registri $ai ed $ra Jr $ra
Come programma chiamato
Ripristino i registri $si
dallo stack pointer $sp
dallo stack pointer $sp
2003 Henry Muccini
21/28
LabArch2003
SEA Group
Registri nelle procedure annidate
Programma chiamato:
Salva $si, cioe’
tutto cio’ che lui puo’ usare e che serve ancora al suo
chiamante
Ripristina $si
Programma chiamante:
Salva $ai, $ra (vecchio) cioe’
i registri che potrebbero essere usati dal proprio chiamato e
che serviranno a lui in seguito
Programma chiamato e chiamante:
Salva (e poi ripristina) $si, $ra, $ai
2003 Henry Muccini
22/28
11
LabArch2003
Esempio: Procedure Annidate in
MIPS
Main:
…
SommaIF
…
Int SommaIF (int a, int b)
{
if (a != b)
Somma (a, b)
else return(0);
}
Int Somma (int a, int b)
{ int c;
c = a + b;}
$s0
$ra
USATO dopo SommaIF
PER TORNARE INDIETRO
a = $a0
b = $a1
$v0
$s0
$ra
SEA Group
PARAMETRO
PARAMETRO
RISULTATO
da salvare in $sp (usato da main)
PER TORNARE INDIETRO
a = $a0
PARAMETRO
b = $a1
PARAMETRO
c = $t0
REGISTRO INTERNO
Non usa nessun $si usato dal chiamante
2003 Henry Muccini
23/28
LabArch2003
SommaIf: #(procedura chiamata - chiamante)
SEA Group
sub $sp, $sp, 16 # spazio nello stack per 4 registri
sw $s0, 12($sp) # salvo $s0 del chiamante
Come chiamato
sw $ra, 8($sp) # salvo $ra del chiamante
Come chiamante
sw $a0, 4($sp) # salvo $a0
sw $a1, 0($sp) # salvo $a1
beq $a0, $a1, Else
jal Somma
lw $a1, 0($sp) # ripristino $ai modificati da Somma
lw $a0, 4($sp)
lw $ra, 8($sp) # ripristino $ra per poter tornare al Main
sub $sp, $sp, 12 # ripristino spazio in $sp
add $v0, $v0, $zero # setto il risultato di SommaIf
jr $ra
2003 Henry Muccini
24/28
12
LabArch2003
SEA Group
Else: add $v0, $zero, $zero
lw $s0, 12($sp)
Tali operazioni non sono necessarie
lw $ra, 8($sp)
add $sp, $sp, 8 # libero lo stack
jr $ra
Somma: #(procedura foglia)
# non devo salvare nessun registro, visto che non uso
nessun $si e sono foglia
add $t0, $a0, $a1 # a+b
add $v0, $t0, $zero # setto il risultato
# non devo ripristinare nessun registro, visto che non
uso nessun $si
# non devo liberare spazio nell $sp
jr $ra
2003 Henry Muccini
25/28
LabArch2003
SommaIf: #(procedura chiamata - chiamante)
SEA Group
sub $sp, $sp, 16 # spazio nello stack per 4 registri
sw $s0, 12($sp) # salvo $s0 del chiamante
sw $ra, 8($sp) # salvo $ra del chiamante
sw $a0, 4($sp) # salvo $a0
sw $a1, 0($sp) # salvo $a1
beq $a0, $a1, Else
jal Somma;
lw $a1, 0($sp) # ripristino $ai che potrebbero essere stati modificati da Somma
lw $a0, 4($sp)
lw $ra, 8($sp) # ripristino $ra per poter tornare al Main
sub $sp, $sp, 12 # ripristino spazio in $sp
add $v0, $v0, $zero # setto il risultato di SommaIf
jr $ra
Else: add $v0, $zero, $zero
lw $s0, 12($sp)
lw $ra, 8($sp)
add $sp, $sp, 8 # libero lo stack
jr $ra
Somma: #(procedura foglia)
# non devo salvare nessun registro, visto che non uso nessun $si e sono foglia
add $t0, $a0, $a1 # a+b
2003 Henry Muccini
add $v0, $t0, $zero # setto il risultato
d
h
$
26/28
13
LabArch2003
SEA Group
Esercizio: Procedura ricorsiva in
MIPS
Int fatt (int n){
if (n<1) return (1);
}
else return (n * fatt (n-1));
Dove:
n = $a0
Assumiamo che fatt non usi registri $si in uso
dal Main
2003 Henry Muccini
27/28
LabArch2003
SEA Group
fatt:
sub $sp, $sp, 8 # alloco uno spazio nello stack
sw $ra, 4($sp)
Come chiamante
sw $a0, 0($sp)
slt $t0, $a0, 1 # se a0<1, $t0 diventa 1
beq $t0, $zero, Else # Controllo n < 1
add $v0, $zero, 1
add $sp, $sp, 8 # aggiorno stack
jr $ra
Return 1
Ramo Then
Else: sub $a0, $a0, 1 # calcolo n-1
jal fatt # chiamo il fattoriale
lw $a0, 0($sp) # ripristino $a0
lw $ra, 4($sp) # ripristino $ra
sub $sp, $sp, 8 # aggiorno stack
Dopo aver eseguito il fattoriale,
ripristono I registri che potrebbero
esser stati modificati
mul $v0, $a0, $v0 # setto il risultato n * fatt(n-1)
jr $ra
2003 Henry Muccini
28/28
14