Day 17
I. Last Time:
Hw #5 Posted
Lab #1 Due NOW!
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

A. Functions in MIPS
Functions - What is a function/subroutine?
A "self contained" set of instructions that does some work
It normally requires some input (arguments) and produces
some output (return value).
Why functions?
Code Re-use
Complexity reduction

1. MIPS function calls:
Much like syscalls:
a. Setup-Arguments
Save and "temp" data that the function may trounce!
b. "Call" the function
c. Use/store the return value

Arguments: The a0-a3 registers
(What if we need more?)

"Call": jal Jump AND Link for calling a function and 
              saving the way back to the caller.
              Go to a specific address AND save the current 
              IP/PC position so we can get back
              (leave a trail of bread crumbs)

II. New Stuff:   
A. Short Circuit Evaluation:
C does what is called "short circuit" evaluation.
I.e. it only does the minimum work nesc.
If something being ANDed is a 0 (false) the result
must be false, so stop checking.
If something being ORed is a !0 (true) the result
must be true, so stop checking.

if(a!=0 && b!=0 && c!=0)
{

}

beqz a, after
beqz b, after
beqz c, after
...

after:

if(a!=0 || b!=0 || c!=0)
{
}

bnez a, into
bnez b, into
beqz c, after
into:
...
after:
...


Although this can be confusing, it can also be helpful:
if(a && test(a))
{
...
}
The test function might be called but it might not.

if(a && a->test())
{
...
}
This can be good: if a is a valid pointer, the test function
will be called. if it's NOT, the function won't be called.
(Which would've resulted in an error)

P.S. this isn't considered good "style" by many -
that's a matter of personal preference.




B. Back to Fact()

       fact(5) = 5*fact(4) - 4*fact(3) - 3*fact(2) - 2*fact(1) - 1
                                                   - 2*1=2
                                         3*2=6
                             4*6=24
                 5*24=120
       
       Details of assembly Language:
          a single set of assembly instructions is being
          executed repreatedly?
          where/how does it return to the caller? WHICH Caller?
          how does it keep track/use local variables/registers?

    C. The Stack - Like a stack in C/C++, but simplier.
  The Stack is a Stack of Function FRAMES.
Whenever a function is called, it creates a FRAME for itself.
The Frame contains all the local information to the function -
things like local variables - both explicit (the ones you know about)
and some implicit (the compiler creates for you - Things like return
values and in some cases arguments to functions)
The Stack Operations: Push, Pop, "Peek"
Push/Pop - Stack Frames are being pushed/poped off the stack.
Peek - Whenver a function is running it may need to use the
space it has set aside for itself (I.e. peek at it's
data) 

       A stack is made of bytes
        Must be allocated in double word increments (multiple of 8)
        Must be used in a very consistent way to be complatible with C/C++
        (C will pass arguments and expect arguments to be passed in a very
         rigid format - we will be using this format)
        Grows DOWN in memory. I.e. to allocate space, subtract from $sp
It's a pointer, so use unsigned instructions (techincally)

The Stack:
       Why a stack? 
           To support recursion, more efficient use/re-use of space
           (localy scoped variables)

           Think:
              If every variable in every function had to actually 
              have space set aside for it in memory at the same time
              VERY inefficient - instead re-use parts of memory only
              for the currently executing function...
And ONLY ONE function can really run at a time...

           Implications:
              Local variables of functions are NOT implicitly
              initialized.
              Limited Recursion - Stack Overflow

           Alternatives:
              No Runtime stack - no recursion, static variables only
              Very Small stack - limited recursion
              Both are common in embedded applications
        
        1. Stack Frames/Activation Records
           When a function is called it creates a "frame" or activation 
           record
           Two purposes:  
              1. Space for local variables
              2. Space for any called functions to store caller's info. 
                 (Arguments and large return values typically)
          
        2. Special Stuff:
           jal - Jump AND Link for calling a function and 
                 saving the way back to the caller.
              Go to a specific address AND save the current 
              IP/PC position so we can get back
              (leave a trail of bread crumbs)
           jr - Return to the address provided in a specific reg
$sp - the "stack pointer" tells where the top of the stack is.

        3. What's Stored:
           Arguments, Local Variables and Return Points
(Args to other functions as well) 

       Stores "local" scopped variables for a specific instance
       of a function. I.e. a specific call. This info is called 
       the "frame" or activation record. and it is accessed via 
       the stack pointer ($sp)
       Advantages: Re-uses "space" - more efficient
       Potential Problems - Limited size - stack overflow
                            Stack variables are not implicitly 
                            initialized.

D. MIPS stack conventions:

What's in the Frame:
1. Space for callee argument (used for large arguments)
2. Space to backup registers (in numerical order)
3. "Local" Variables/space
Misc. Rules:
If a "leaf" function (doesn't call other functions):
Stack space may not be needed unless more than the 10 t-regs
are required
If a "non-leaf" function (call's something else)
Must allocate at least 16 bytes for callee's a0-a3.
Must allocate at least 4 bytes for ra
All frames size should be a multiple of 8

A function:
1. Function setup (Pushing)
a. Sets aside "frame" space
b. Saves any registers that it's going to change
2. Performs computation / calls other functions / etc.
(sets up return value)
3. Prepares to return to caller (Poping)
a. Restores changed registers
b. releases frame
c. returns to caller (jr $ra)

III. 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.

VI. Next Time:
A. More Mips Memory and Functions
B. MIPS memory segmentation
C. Using SPIM