Day 18
I. Last Time:
Hw #5 Posted - Due TUES!
Lab #1 - Don't Forget Demo Times!!!
Lab #2 Posted: Early Bird Special:
+1% Extra for each weekday early up to +5%
In My Mailbox Wed Morn: +1
Tues +2, Mon +3 Fri +4 Thurs +5
Register for 235 NEXT SEMESTER!!! - Last chance to take it!
(Talk to your advisor!)
A. Misc. Pseudo-Ops to make life easier:
You can use 1 constant in mul, div, rem, branches:
beq $a0,' ', ...
If a character constant doesn't work, then hex will:
blt $a0,0x41, ...
Can do the same with mul:
mul $t0,$t0,12
B. Functions / Calling Functions:
I ask you to write a "max" function:
int max(int *array)
I want to use your function:
...
la $a0, array
jal max
... Might have changed here?
Whick Registers did max use?
Register Conventions:
The Golden Rule:
When a function is "done" the only registers that
should have changed are the t-registers and the
v-registers. (And the $ra, but it is changed by
the caller and not further changed by the callee)
$sp must be unchanged (For VERY god reason!)
Function Callers:
Whenever we call a function we must assume that
all of the t-reg and v-regs will change...
Even if we wrote the function, to really be "proper"
we need to assume that the t and v regs may change.
Function Writers:
We should only work with the t/v regs if possible.
often we must change some other regs too though -
in this case we need to "save" the original values
someplace safe and "restore" them before finishing up.
(We can really cheat and change anything, but we must
"restore" it before we're completly done)
Ex: if our function must call another function, we will
almost always need to change the a0 reg...we need
to put the original value back in before completing.
Q. Where do we backup?
A. The only "local"/"private" space we have - the stack.
Cheating:
We can change anything we want, as long as
we put it back before anyone knows...
Main is a function:
Should use $ra to return
Should only change v and t regs!
C. The Stack rules:
The stack is a stack of frames or activation records.
(Act rec - the "active info." in a function...
Frame because of it's shape/drawing)
Why:
a. Minimum space use / recycle memopry (Fib later)
b. Support functions / share registers without conflict
c. Large / more than 4 arguments
d. Recursion
The frame is essentially 3 parts:
Local Variables
Register back-up space (and we know know when to backup)
Space for callees
Rules for creating:
If we call another function, we must set aside
the bottom 16 bytes for it to use (backup a0-a3)
We must have whatever "local" space we need
(backup regs and local variables)
We must round up to the nearest multiple of 8.
(The MIPS designers tell us this)
Functions:
1. Create frame and backup:
Using addu $sp, -X to create
and sw to backup
2. Perform actual work (May use stack)
3. "Cleanup" and put everything except t & v regs
back to original value and return.
Some functions don't need the stack:
Leaf function - a function at the bottom of a call tree
(Doesn't call anything else)
May not need the stack if it only uses t and v regs.
All other functions must use the stack!
II. Everything you ever wanted to know about Fibannoci,
but were afraid to ask...
DETAILED, SLOW Fibannoci example.
If you pay attention/understand, the next Hw will be a breeze
(take ~1hr) if NOT, it will take a lot longer)
A. Definition:
Note: This problem is 800 years old - proposed by Fibonacci
in 1202.
Suppose that you have a pair of rabbits - every month the
rabbits breed and have a pair of offspring, who will begin
the breeding process themselves in two months.
Month 1 - 1 Pair - New Born (NB)
Month 2 - 1 Pair - Ready to Breed (RTB)
Month 3 - 2 Pair (1 breeding (B), 1 NB)
Month 4 - 3 Pair (1 B, 1 RTB, 1 NB)
Month 5 - 5 Pair (2 B, 1 RTB, 2 NB)
Month 6 - 8 Pair (3 B, 2 RTB, 3 NB)
Notice that each term is the sum of the 2 proceeding.
(I.e. month 6 = month 5+month 4)
As a function:
F(0)=1
F(1)=1
F(N)=F(N-1)+F(N-2)
Notice that this is a function with 2 base cases,
and a single "recursive" case which recurses in
2 "directions".
NOTE: Solving this with recursion is (in my opinion),
the WORST possible way to solve the problem.
(Closed Form is best, Iteration second best)
We do this merly to gain experience with the
stack.
B. Solution - in C++:
unsigned Fib(unsigned n)
{
if(n<=1) // Neat observation based on seq
return n; // Base Case
else
return Fib(n-1)+Fib(n-2);
}
Notes on C++ Conversion:
n will be in $a0
We may need temp places to store Fib(n-1) & Fib(n-2)
($t0, $t1)
C. Solution in ASM:
All ASM routines have 3 parts -
a begining, a middle, and an end
fib:
# Allocate Stack Space
subu $sp,$sp,32 # (let's try 32)
# Store Registers that may be changed by called functions:
sw $a0,32($sp)
sw $ra,28($sp)
bgt $a0,1,fib_recurse # Check Base Case
move $v0,$a0 # Put return value in ret val reg
j fib_end
fib_recurse: # Recursive Case
addiu $a0,$a0,-1 # Setup for fib(n-1)
jal fib # call fib(n-1)
sw $v0,24($sp) # deal with return value
addiu $a0,$a0,-1 # setup for fib(n-2)
jal fib # call fib(n-2)
lw $t0,24($sp) # retreive fib(n-1)
add $v0,$v0,$t0 # v0=fib(n-1)+fib(n-2)
fib_end: # Clean-up/return to caller
lw $ra, 28($sp) # Restore ra for caller
lw $a0, 32($sp) # Restore a0
addu $sp,$sp,32 # Restore stack
jr $ra # return to caller
D. A sample Run:
Memory Address Instruction(s)
-------------- -------------------------------------------
[0x00400020] subu $sp,$sp,32 # (let's try 32)
[0x00400024] sw $a0,32($sp)
[0x00400028] sw $ra,28($sp)
[0x0040002c] bgt $a0,1,fib_recurse
[0x00400030] (beq $1, $0, 12 [fib_recurse-0x00400030])
[0x00400034] move $v0,$a0
[0x00400038] j fib_end
[0x0040003c] addiu $a0,$a0,-1 # Setup for fib(n-1)
[0x00400040] jal fib
[0x00400044] sw $v0,24($sp)
[0x00400048] addiu $a0,$a0,-1 # setup for fib(n-2)
[0x0040004c] jal fib
[0x00400050] lw $t0,24($sp)
[0x00400054] add $v0,$v0,$t0
[0x00400058] lw $ra, 28($sp)
[0x0040005c] lw $a0, 32($sp)
[0x00400060] addu $sp,$sp,32
[0x00400064] jr $ra
What happens during fib(1)?
fib(2)?
fib(5)?
E. Summary:
Stack is used to implement locally scoped variables and to
"re-use" memory for local variables so we don't have to
waste space for variables not currently in use.
Stack allows recursion.
Some accounting info. must be stored on the stack: args & ra.
III. Next Time:
A. Larg Args and Return Values