MIPS Assembly Language Programming (2)
description
Transcript of MIPS Assembly Language Programming (2)
1
MIPS Assembly Language
Programming (2)
CDA 3101 Discussion Section 03CDA 3101 Discussion Section 03
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
4
•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,$s2Fin:
Loops in C/Assembly
• There are three types of loops in C:– do…while– while– for
5
Case-Switch Statement
• C codeswitch(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); …}
int sum(int x, int y) {return(x+y);
}
main: add $a0,$s0,$zero # x = aadd $a1,$s1,$zero # y = b addi $ra,$zero,? #$ra=?j sum #jump to sum
...sum: add $v0,$a0,$a1
jr $ra # new instruction
In MIPS, all instructions are 4 bytes, and stored in memory just like data.
main(){ int a, b; sum(a,b); …}
int sum(int x, int y) {return(x+y);
}
1000 main: add $a0,$s0,$zero # x = a1004 add $a1,$s1,$zero # y = b 1008 addi $ra,$zero,? #$ra=?1012 j sum #jump to sum ...2000 sum: add $v0,$a0,$a12004 jr $ra # new instruction
main(){ int a, b; sum(a,b); …}
int sum(int x, int y) {return(x+y);
}
1000 main: add $a0,$s0,$zero # x = a1004 add $a1,$s1,$zero # y = b 1008 addi $ra,$zero,1016 #$ra=10161012 j sum #jump to sum ...2000 sum: add $v0,$a0,$a12004 jr $ra # new instruction
MIPS provides a single instruction called ‘jal’ to1. Load $ra with addr of next instruction2. Jump to the procedure.
main(){ int a, b; sum(a,b); …}
int sum(int x, int y) {return(x+y);
}
1000 main: add $a0,$s0,$zero # x = a1004 add $a1,$s1,$zero # y = b 1008 jal sum #$ra=1012, jump to sum ...2000 sum: add $v0,$a0,$a12004 jr $ra
Non-Leaf Procedures
main() { int a, b; sum2(a,b);…}
int sum2(int x, int y) {return(sum(x,x) + y);
}
int sum(int p, int q){return(p+q);
}
1000 main: add $a0,$s0,$zero
1004 add $a1,$s1,$zero
1008 jal sum2
...
2000 sum2: add $a1,$a0,$0
2004 jal sum
2008 add $v0, $v0, $a1
2012 jr $ra
…
4000 sum: add $v0, $a0, $a1
4004 jr $ra
1000 main: add $a0,$s0,$zero
1004 add $a1,$s1,$zero
1008 jal sum2
...
2000 sum2: add $a1,$a0,$0
2004 jal sum
2008 add $v0, $v0, $a1
2012 jr $ra
…
4000 sum: add $v0, $a0, $a1
4004 jr $ra
Instr.Addr
$ra $a0 $a1 $v0
1000 a
1004 b
1008 1012
2000 a
2004 2008
4000 a+a
4004
2008 a+a+a
2012
2008 a+a+a+aWe need to do some bookkeeping!
We need to save registers before rewriting them.
Where should we save them?
Memory Organization
Reserved
Stack
Dynamic Data
Static Data
Text
Reserved0x00400000
0x10000000
0x10040000
0x80000000 •Stack grows from Hi addr to Lo addr
•$sp ($29) points to the top of the stack
•To push a word on stack, decrement $sp by 4, and use sw
•To pop a word from stack, increment $sp by 4
$sp
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: add $a0,$s0,$zero
1004 add $a1,$s1,$zero
1008 jal sum2
...
2000 sum2: add $a1,$a0,$0
2004 jal sum
2008 add $v0, $v0, $a1
2012 jr $ra
…
4000 sum: add $v0, $a0, $a1
4004 jr $ra
Instr.Addr
$ra=y $a0 $a1 $v0
1000 a
1004 b
1008 1012
2000 a
2004 2008
4000 a+a
4004
2008 a+a+a
2012
2008 a+a+a+a
Lo addr
1000 main: add $a0,$s0,$zero
1004 add $a1,$s1,$zero
1008 addi $sp, $sp, -4
1012 sw $ra, 0($sp)
1016 jal sum2
1020 lw $ra, 0($sp)
1024 addi $sp, $sp, 4
1028 jr $ra
2000 sum2: addi $sp, $sp, -8
2004 sw $ra, 4($sp)
2008 sw $a1, 0($sp)
2012 add $a1,$a0,$0
2016 jal sum
2020 lw $a1, 0($sp)
2024 lw $ra, 4($sp)
2028 add $sp, $sp, 8
2032 add $v0, $v0, $a1
2036 jr $ra
…
4000 sum: add $v0, $a0, $a1
4004 jr $ra
Addr $ra=y $a0 $a1 $v0 $sp=x1000 a1004 b1008 x-410121016 10202000 x-12200420082012 a2016 20204000 2a4004 2020 b2024 10202028 x-42032 2a+b20361020 y• x1028
$sp
y
1020
b
$sp
$sp
Recursive functionsmain(){ fact(2);}
int fact(int n){ if (n < 1)
return(1); else
return(n*fact(n-1));}
1000 main: addi $a0, $0, 21004 addi $sp, $sp, -41008 sw $ra, 0($sp)1012 jal fact1016 lw $ra 0($sp)1020 addi $sp, $sp, 41024 jr $ra
2000 fact: slti $t0, $a0, 12004 beq $t0, $0, L12008 addi $v0, $0, 12012 jr $ra
2016 L1: addi $sp, $sp, -82020 sw $ra, 4($sp)2024 sw $a0, 0($sp) 2028 addi $a0, $a0, -12032 jal fact2036 lw $a0, 0($sp)2040 lw $ra, 4($sp)2044 add $sp, $sp, 82048 mul $v0, $a0, $v02052 jr $ra
1000main: addi $a0, $0, 21004 addi $sp, $sp, -41008 sw $ra, 0($sp)1012 jal fact1016 lw $ra 0($sp)1020 addi $sp, $sp, 41024 jr $ra
2000fact: slti $t0, $a0, 12004 beq $t0, $0, L12008 addi $v0, $0, 12012 jr $ra
2016L1: addi $sp, $sp, -82020 sw $ra, 4($sp)2024 sw $a0, 0($sp)2028 addi $a0, $a0, -12032 jal fact2036 lw $a0, 0($sp)2040 lw $ra, 4($sp)2044 add $sp, $sp, 82048 mul $v0, $a0, $v02052 jr $ra
Addr $ra=y $a0 $t0 $v0 $sp=x1000 21004
x-410081012 10162000 020042016 x-
12202020242028 12032 20362000 020042016 x-
202020 20242028 02032 20362000 120042008 120122036 12040 20362044 x-122048 12052 2053 22040 10162044 x-42048 220521008
$sp
$sp
hi y
1016
2
2036
1
$sp
lo
4 bytes
$sp
Argument Passing
• Recall: arguments to a procedure passed through $a0-$a3
• What if the procedure has > 4 arguments?– 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
x7
x6
x5
x4$sp
lo
hi
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
• Exampleint sillyfunc(int i, int j)
{int k, l, m, n, stuff[3];….
}
• How to acess stuff[2]?• How to access stuff[m]?
stuff[2]
stuff[1]
stuff[0]
n
m
l
k$sp
Lo addr
Hi addr
0
4
8
12
16
20
24
Local Variables in procedures
• Exampleint sillyfunc(int i, int j)
{int k, l, m, n, stuff[3];….
}
• 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?
stuff[2]
stuff[1]
stuff[0]
n
m
l
k
$t0
$sp
Lo addr
Hi addr
0
4
8
12
16
20
24
$sp
Frame Pointers
• Use register $30 ($fp) • At entry the called procedure
– Saves old $fp on stack– sets $fp = $sp – 4
• During the procedure execution, $fp does not change– Address of m is always -20($fp)
• Before return– Set $sp = $fp + 4– Restore old $fp value from stack and set $fp
= old $fp
Old $fp
stuff[2]
stuff[1]
stuff[0]
n
m
l
k
$t0
$sp
Lo addr
Hi addr
-24
-20
-16
-12
-8
-4
0
$sp
$sp
$fp
-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