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