You are on page 1of 28

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
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:

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:

Loops in C/Assembly
There are three types of loops in C:
dowhile 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?

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:

sum:

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); }

int sum(int x, int y) { return(x+y); }

1000 1004 1008 1012 2000 2004

main:

sum:

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); }

int sum(int x, int y) { return(x+y); }

1000 1004 1008 1012 2000 2004

main:

sum:

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); }

int sum(int x, int y) { return(x+y); }

1000 1004 1008 2000 2004

main:

sum:

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); } int sum2(int x, int y) { return(sum(x,x) + y); } 1000 1004 1008 main: add $a0,$s0,$zero add $a1,$s1,$zero jal sum2 ...

2000 2004 2008 2012 4000 4004

int sum(int p, int q){ return(p+q); }

sum2: add $a1,$a0,$0 jal sum add $v0, $v0, $a1 jr $ra sum: add $v0, $a0, $a1 jr $ra

1000 1004 1008

main:

add $a0,$s0,$zero add $a1,$s1,$zero jal sum2

Instr.A $ra ddr 1000 1004

$a0 a

$a1

$v0

...
2000 2004 2008 2012 4000 4004 sum2: add $a1,$a0,$0 jal sum add $v0, $v0, $a1 jr $ra add $v0, $a0, $a1 jr $ra

1008
2000 2004 4000 4004

1012
a 2008 a+a

sum:

2008
2012 2008

a+a+a
a+a+a+a

We need to do some bookkeeping! We need to save registers before rewriting them. Where should we save them?

Memory Organization
$sp

Reserved

Stack

0x80000000

Stack grows from Hi addr to Lo addr


$sp ($29) points to the top of the stack

Dynamic Data Static Data

0x10040000

0x10000000

Text

To push a word on stack, decrement $sp by 4, and use sw To pop a word from stack, increment $sp by 4

Reserved

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

1000 1004 1008

main:

add $a0,$s0,$zero add $a1,$s1,$zero jal sum2

Instr.A $ra=y ddr 1000 1004

$a0 a

$a1

$v0

...
2000 2004 2008 2012 4000 4004 sum2: add $a1,$a0,$0 jal sum add $v0, $v0, $a1 jr $ra add $v0, $a0, $a1 jr $ra

1008
2000 2004 4000 4004

1012
a 2008 a+a

sum:

2008
2012 2008

a+a+a
a+a+a+a

1000

main: add $a0,$s0,$zero

1004 1008 1012 1016 1020 1024 1028


2000 2004 2008 2012 2016 2020 2024 2028 2032 2036 4000 4004

add $a1,$s1,$zero addi $sp, $sp, -4 sw $ra, 0($sp) jal sum2 lw $ra, 0($sp) addi $sp, $sp, 4 jr $ra
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 x-12

1020
$sp b

a 2020 2a b 1020 x-4 2a+b y x Lo addr

Recursive functions
main() { fact(2); } 1000 1004 1008 1012 1016 1020 1024 2000 2004 2008 2012 2016 2020 2024 2028 2032 2036 2040 2044 2048 2052 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 slti $t0, $a0, 1 beq $t0, $0, L1 addi $v0, $0, 1 jr $ra 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

fact:

int fact(int n) { if (n < 1) return(1); else return(n*fact(n-1)); }

L1:

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 x-12

$sp 2

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?
First four arguments are put in $a0-$a3 Remaining arguments are put on stack by the caller
hi
x7 x6 x5
$sp x4

Example: silly7(int x0, int x1, , int x7)


Caller places arguments x0-x3 in $a0-$a3 Caller places arguments x4-x7 on stack

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

24 20 16

12
8 4 0

How to acess stuff[2]? How to access stuff[m]?


Lo addr

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?
Lo addr Hi addr

stuff[2]
stuff[1] stuff[0] n m l
$sp k

24 20 16

12
8 4 0

$sp $t0

Frame Pointers
Use register $30 ($fp) At entry the called procedure
Saves old $fp on stack sets $fp = $sp 4
Hi addr
$sp

$fp Old $fp

0 -4

stuff[2] stuff[1]

During the procedure execution, $fp does not change


Address of m is always -20($fp)

-8
-12 -16 -20 -24 -28

stuff[0] n m l
$sp k
$sp $t0

Before return
Set $sp = $fp + 4 Restore old $fp value from stack and set $fp = old $fp

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

You might also like