Procedures in MIPS

advertisement
CDA 3101 Discussion Section 03
MIPS
Assembly Language
Programming (2)
1
Basic Instructions
• Manipulate data:
– ADD SUB MUL DIV AND OR XOR …
– ADDI SLL …
• Memory Instruction:
– LW SW
– LB SB
• Branches
–J
– BNE BEQ BGE …
2
Decisions: C if Statements
• 2 kinds of if statements in C
– if (condition) statement-block
– if (condition) statement-block1 else statement-block2
• 2nd statement can be rewritten as:
if
(condition) goto L1;
statement-block2;
goto L2;
L1: statement-block1;
L2:
3
Example: Compiling C if into
MIPS
• C Code
if (i == j)
f=g+h;
else
f=g-h;
f: $s0, g: $s1, h: $s2,
i: $s3, j: $s4
MIPS code:
beq $s3,$s4,True
sub $s0,$s1,$s2
j Fin
True: add $s0,$s1,$s2
Fin:
4
Loops in C/Assembly
• There are three types of loops in C:
– do…while
– while
– for
5
Case-Switch Statement
• C code
switch(k) {
case 0: f = i + j; break;
case 1: f = g + h; break;
case 2: f = g - h; break;
case 3: f = i - j; break;
}
• Can be rewritten as
if (k == 0) f = i + j;
else if (k == 1) f = g + h;
else if (k == 2) f = g – h;
else if (k == 3) f = i – j;
6
Procedure
• What is procedure?
Example Code
main()
{
int a, b;
sum(a,b);
…
}
int sum(int x, int y) {
return(x+y);
}
Steps:
1. Caller places parameters in a
place where the procedure
can access them
2. Transfer control to the
procedure
3. Acquire storage resources
required by the procedure
4. Execute the statements in
the procedure
5. Called function places the
result in a place where the
caller can access it
6. Return control to the
statement next to the
procedure call
How do we achieve all this in MIPS
Assembly language
• To achieve this, following registers are
used:
– $4-$7 ($a0-$a3): used to pass arguments
– $2-$3 ($v0-$v1): used to pass return values
– $31 ($ra): used to store the addr of the
instruction which is to be executed
after the procedure returns
main()
{
int a, b;
sum(a,b);
…
}
main:
sum:
int sum(int x, int y) {
return(x+y);
}
add $a0,$s0,$zero
add $a1,$s1,$zero
addi $ra,$zero,?
j sum
...
add $v0,$a0,$a1
jr $ra
#x=a
#y=b
#$ra=?
#jump to sum
# new instruction
In MIPS, all instructions are 4 bytes, and stored in
memory just like data.
main()
{
int a, b;
sum(a,b);
…
}
1000
1004
1008
1012
main:
2000
2004
sum:
int sum(int x, int y) {
return(x+y);
}
add $a0,$s0,$zero
add $a1,$s1,$zero
addi $ra,$zero,?
j sum
...
add $v0,$a0,$a1
jr $ra
#x=a
#y=b
#$ra=?
#jump to sum
# new instruction
main()
{
int a, b;
sum(a,b);
…
}
1000
1004
1008
1012
main:
2000
2004
sum:
int sum(int x, int y) {
return(x+y);
}
add $a0,$s0,$zero
add $a1,$s1,$zero
addi $ra,$zero,1016
j sum
...
add $v0,$a0,$a1
jr $ra
#x=a
#y=b
#$ra=1016
#jump to sum
# new instruction
MIPS provides a single instruction called ‘jal’ to
1. Load $ra with addr of next instruction
2. Jump to the procedure.
main()
{
int a, b;
sum(a,b);
…
}
1000
1004
1008
main:
2000
2004
sum:
int sum(int x, int y) {
return(x+y);
}
add $a0,$s0,$zero
add $a1,$s1,$zero
jal sum
...
add $v0,$a0,$a1
jr $ra
#x=a
#y=b
#$ra=1012, jump to sum
Non-Leaf Procedures
main() {
int a, b;
sum2(a,b);
…
}
1000
1004
1008
main:
add $a0,$s0,$zero
add $a1,$s1,$zero
jal sum2
...
int sum2(int x, int y) {
return(sum(x,x) + y);
}
2000
2004
2008
2012
int sum(int p, int q){
return(p+q);
}
4000
4004
sum2: add $a1,$a0,$0
jal sum
add $v0, $v0, $a1
jr $ra
…
sum: add $v0, $a0, $a1
jr $ra
1000
main:
1004
1008
add $a0,$s0,$zero
add $a1,$s1,$zero
jal sum2
...
2000
2004
2008
2012
sum2:
4000
4004
sum:
add $a1,$a0,$0
jal sum
add $v0, $v0, $a1
jr $ra
…
add $v0, $a0, $a1
jr $ra
Instr.A $ra
ddr
$a0
1000
a
1004
1008
$v0
b
1012
2000
2004
$a1
a
2008
4000
a+a
4004
2008
a+a+a
2012
2008
We need to do some bookkeeping!
We need to save registers before rewriting them.
Where should we save them?
a+a+a+a
Memory Organization
$sp
Reserved
Stack
Dynamic Data
0x80000000
0x10040000
•$sp ($29) points to the top
of the stack
0x10000000
•To push a word on stack,
decrement $sp by 4, and
use sw
Static Data
Text
Reserved
•Stack grows from Hi addr
to Lo addr
0x00400000
•To pop a word from stack,
increment $sp by 4
Saving registers
• Following registers should be spilled to the
stack
– $ra ($31)
– $a0-$a3 ($4-$7)
– $t0-$t7 ($8-$15)
– $s0-$s7 ($16-$23)
– $fp ($30)
Saved by caller on stack
before jal and restored after
returning from jal; done only
for registers used after jal
Saved by called procedure
before rewriting and then
restored back before
returning
1000
main:
1004
1008
add $a0,$s0,$zero
add $a1,$s1,$zero
jal sum2
...
2000
2004
2008
2012
sum2:
4000
4004
sum:
add $a1,$a0,$0
jal sum
add $v0, $v0, $a1
jr $ra
…
add $v0, $a0, $a1
jr $ra
Instr.A $ra=y
ddr
$a0
1000
a
1004
1008
4000
$v0
b
1012
2000
2004
$a1
a
2008
a+a
4004
2008
a+a+a
2012
2008
a+a+a+a
1000
main: add $a0,$s0,$zero
1004
1008
1012
1016
1020
1024
1028
add $a1,$s1,$zero
addi $sp, $sp, -4
sw $ra, 0($sp)
jal sum2
lw $ra, 0($sp)
addi $sp, $sp, 4
jr $ra
2000
2004
2008
2012
2016
2020
2024
2028
2032
2036
4000
4004
sum2: addi $sp, $sp, -8
sw $ra, 4($sp)
sw $a1, 0($sp)
add $a1,$a0,$0
jal sum
lw $a1, 0($sp)
lw $ra, 4($sp)
add $sp, $sp, 8
add $v0, $v0, $a1
jr $ra
…
sum: add $v0, $a0, $a1
jr $ra
Addr
1000
1004
1008
1012
1016
2000
2004
2008
2012
2016
4000
4004
2020
2024
2028
2032
2036
1020
1024
1028
$ra=y $a0 $a1 $v0
a
b
$sp=x $sp
$sp y
x-4
1020
$sp b
1020
x-12
a
Lo addr
2020
2a
b
1020
x-4
2a+b
y
x
Recursive functions
main()
{
fact(2);
}
int fact(int n)
{
if (n < 1)
return(1);
else
return(n*fact(n-1));
}
1000
1004
1008
1012
1016
1020
1024
main:
addi $a0, $0, 2
addi $sp, $sp, -4
sw $ra, 0($sp)
jal fact
lw $ra 0($sp)
addi $sp, $sp, 4
jr $ra
2000
2004
2008
2012
fact:
slti $t0, $a0, 1
beq $t0, $0, L1
addi $v0, $0, 1
jr $ra
2016
2020
2024
2028
2032
2036
2040
2044
2048
2052
L1:
addi $sp, $sp, -8
sw $ra, 4($sp)
sw $a0, 0($sp)
addi $a0, $a0, -1
jal fact
lw $a0, 0($sp)
lw $ra, 4($sp)
add $sp, $sp, 8
mul $v0, $a0, $v0
jr $ra
1000 main: addi $a0, $0, 2
1004
addi $sp, $sp, -4
1008
sw $ra, 0($sp)
1012
jal fact
1016
lw $ra 0($sp)
1020
addi $sp, $sp, 4
1024
jr $ra
2000 fact: slti $t0, $a0, 1
2004
beq $t0, $0, L1
2008
addi $v0, $0, 1
2012
jr $ra
2016 L1: addi $sp, $sp, -8
2020
sw $ra, 4($sp)
2024
sw $a0, 0($sp)
2028
addi $a0, $a0, -1
2032
jal fact
2036
lw $a0, 0($sp)
2040
lw $ra, 4($sp)
2044
add $sp, $sp, 8
2048
mul $v0, $a0, $v0
2052
jr $ra
Addr $ra=y $a0
1000
2
1004
1008
1012 1016
2000
2004
2016
2020
2024
2028
1
2032 2036
2000
2004
2016
2020
2024
2028
0
2032 2036
2000
2004
2008
2012
2036
1
2040 2036
2044
2048
2052
2036
2
2040 1016
2044
$t0
$v0 $sp=x
x-4
$sp
4 bytes
hi $sp y
1016
0
$sp 2
x-12
2036
$sp 1
0
lo
x-20
1
1
x-12
1
x-4
Argument Passing
• Recall: arguments to a procedure
passed through $a0-$a3
• What if the procedure has > 4
arguments?
hi
x7
x6
x5
– First four arguments are put in $a0-$a3
– Remaining arguments are put on stack by the
caller
• Example: silly7(int x0, int x1, …, int x7)
– Caller places arguments x0-x3 in $a0-$a3
– Caller places arguments x4-x7 on stack
$sp x4
lo
Return Values
• Recall: return values from a procedure passed
through $v0-$v1
• What if the procedure has > 2 return values?
– First two return values put in $v0-$v1
– Remaining return values put on stack by the
procedure
– The remaining return values are popped from the
stack by the caller
Variables
• Memory for Global variables is allocated
using assembler directives like .space,
.word, .halfword, .byte, etc.
• Memory allocated is in the static data
portion if MIPS memory
• What about local variables?
Local Variables in procedures
• Example
int sillyfunc(int i, int j)
{
int k, l, m, n, stuff[3];
….
}
Hi addr
stuff[2]
stuff[1]
stuff[0]
n
m
l
$sp k
• How to acess stuff[2]?
• How to access stuff[m]?
Lo addr
24
20
16
12
8
4
0
Local Variables in procedures
• Example
int sillyfunc(int i, int j)
{
int k, l, m, n, stuff[3];
….
}
Hi addr
stuff[2]
stuff[1]
stuff[0]
n
m
• How to acess k?
• Say, sillyfunc() calls another function and
saves $t0 on stack before this call
• What will be the offset of k with respect
to $sp now?
l
$sp k
$sp $t0
Lo addr
24
20
16
12
8
4
0
Frame Pointers
• Use register $30 ($fp)
• At entry the called procedure
Hi addr
$sp
$fp Old $fp
– Saves old $fp on stack
– sets $fp = $sp – 4
stuff[2]
stuff[1]
• During the procedure execution, $fp
does not change
– Address of m is always -20($fp)
– Set $sp = $fp + 4
– Restore old $fp value from stack and set $fp
= old $fp
-8
-12
n
-16
l
$sp k
$sp $t0
Lo addr
-4
stuff[0]
m
• Before return
0
-20
-24
-28
Dynamic Memory Allocation
• Memory allocated on heap
• In PCSPIM, do the following to dynamically
allocate memory
– Set $v0 = 9
– Set $a0 = number of bytes you want to allocate
– syscall
Download