280 likes | 436 Views
CDA 3101 Discussion Section 03. MIPS Assembly Language Programming (2). Basic Instructions. Manipulate data: ADD SUB MUL DIV AND OR XOR … ADDI SLL … Memory Instruction: LW SW LB SB Branches J BNE BEQ BGE …. Decisions: C if Statements. 2 kinds of if statements in C
E N D
CDA 3101 Discussion Section 03 MIPS Assembly Language Programming (2)
Basic Instructions • Manipulate data: • ADD SUB MUL DIV AND OR XOR … • ADDI SLL … • Memory Instruction: • LW SW • LB SB • Branches • J • BNE BEQ BGE …
Decisions: C if Statements • 2 kinds of if statements in C • if (condition) statement-block • if (condition) statement-block1 elsestatement-block2 • 2nd statement can be rewritten as: if (condition) goto L1;statement-block2;goto L2; L1: statement-block1; L2:
Example: Compiling C if into MIPS 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: • C Code if (i == j) f=g+h; else f=g-h;
Loops in C/Assembly • There are three types of loops in C: • do…while • while • for
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;
Procedure • What is procedure?
main() { int a, b; sum(a,b); … } int sum(int x, int y) { return(x+y); } Steps: Caller places parameters in a place where the procedure can access them Transfer control to the procedure Acquire storage resources required by the procedure Execute the statements in the procedure Called function places the result in a place where the caller can access it Return control to the statement next to the procedure call Example Code
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 = a add $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 = a1004add $a1,$s1,$zero # y = b1008addi $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 = a1004add $a1,$s1,$zero # y = b1008addi $ra,$zero,1016 #$ra=1016 1012 j sum #jump to sum ... 2000 sum: add $v0,$a0,$a12004 jr $ra # new instruction • MIPS provides a single instruction called ‘jal’ to • Load $ra with addr of next instruction • 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 = a1004add $a1,$s1,$zero # y = b1008 jal sum #$ra=1012, jump to sum ... 2000 sum: add $v0,$a0,$a12004 jr $ra
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); } main: add $a0,$s0,$zero 1004 add $a1,$s1,$zero 1008 jal sum2 ... sum2: add $a1,$a0,$0 2004 jal sum 2008 add $v0, $v0, $a1 2012 jr $ra … sum: add $v0, $a0, $a1 4004 jr $ra Non-Leaf Procedures
1000main: add $a0,$s0,$zero • 1004 add $a1,$s1,$zero • 1008 jal sum2 ... • sum2: add $a1,$a0,$0 • 2004 jal sum • 2008 add $v0, $v0, $a1 • 2012 jr $ra • … • sum: add $v0, $a0, $a1 • 4004 jr $ra We need to do some bookkeeping! We need to save registers before rewriting them. Where should we save them?
$sp Memory Organization 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 0x10040000 0x10000000 0x00400000
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
1000main: add $a0,$s0,$zero • 1004 add $a1,$s1,$zero • 1008 jal sum2 ... • sum2: add $a1,$a0,$0 • 2004 jal sum • 2008 add $v0, $v0, $a1 • 2012 jr $ra • … • sum: add $v0, $a0, $a1 • 4004 jr $ra
$sp $sp $sp Lo addr • Addr $ra=y $a0 $a1 $v0 $sp=x • a • 1004 b • x-4 • 1012 • 1020 • 2000 x-12 • 2004 • 2008 • a • 2020 • 4000 2a • 4004 • b • 1020 • x-4 • 2a+b • 2036 • y • x • 1028 • 1000main: add $a0,$s0,$zero • add $a1,$s1,$zero • addi $sp, $sp, -4 • 1012 sw $ra, 0($sp) • 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 • jal sum • lw $a1, 0($sp) • lw $ra, 4($sp) • 2028 add $sp, $sp, 8 • 2032 add $v0, $v0, $a1 • 2036 jr $ra • … • sum: add $v0, $a0, $a1 • 4004 jr $ra y 1020 b
main() { fact(2); } int fact(int n) { if (n < 1) return(1); else return(n*fact(n-1)); } 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 Recursive functions
$sp $sp $sp $sp • main: addi $a0, $0, 2 • 1004 addi $sp, $sp, -4 • 1008 sw $ra, 0($sp) • 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 $t0 $v0 $sp=x • 2 • 1004 x-4 • 1008 • 1012 1016 • 2000 0 • 2004 • x-12 • 2020 • 2024 • 2028 1 • 2032 2036 • 2000 0 • 2004 • 2016 x-20 • 2020 • 2024 • 2028 0 • 2032 2036 • 2000 1 • 2004 • 2008 1 • 2012 • 1 • 2036 • 2044 x-12 • 1 • 2 • 1016 • 2044 x-4 • 2 • 2052 • 1008 4 bytes hi y 1016 2 2036 1 lo
$sp hi x7 x6 x5 x4 lo 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
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?
$sp Local Variables in procedures • Example int sillyfunc(int i, int j) { int k, l, m, n, stuff[3]; …. } • How to acess stuff[2]? • How to access stuff[m]? Hi addr stuff[2] stuff[1] stuff[0] n m l k 24 20 16 12 8 4 0 Lo addr
$sp $sp Local Variables in procedures • Example int 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? Hi addr stuff[2] stuff[1] stuff[0] n m l k $t0 24 20 16 12 8 4 0 Lo addr
$sp $sp $sp $fp 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 Hi addr Old $fp stuff[2] stuff[1] stuff[0] n m l k $t0 0 -4 -8 -12 -16 -20 -24 -28 Lo addr
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