Day 16
I. Last Time:
Hw #5 Posted
Lab #1 Due next time
A. Insts so far:
add, addu, sub, subu, addi, addiu
lw, sw, lb, sb
beq, bne, j, slt, sltu,
syscall

Pseudo-Ops make reading/writing code easier:
(Helps explain "why"/logic)
li, la, move
blt, bltu, bgt, bgtu, ble, bleu, bge, bgeu
bnez, beqz,
mul, div, rem

   B. How does a program do IO/talk to hardware/get memory? OS!
      How does the computer contact the OS? 
      In Many os's through syscalls (There are other mechanisms 
      though like jump gates)

Ex: What if I want to print the int in $t7?

   C. How the assembler uses memory
       1. Memory is divided into "segments" (See A-9)
       2. Each of these segments has a specific use:
          Reserved: ? OS/Hardware/whatever. We can't use it.
          Text Segment: For the program ("text")
              This is where the actual instructions are 
              stored. Remember that they are word aligned.
              If you see an address in this range - it's 
              refering to an instruction!
          Data Segment: Static and Dynamic:
              Static: For "static" (global) variables 
                 and "constant" arrays.
                 Ex: .asciiz "Hi ..." 
                 In a C prog. and initialized arrays 
                 initial values. NOT the array itself, 
                 just the stuff to initialize it with.
              Dynamic: the "Heap" - where the new/alloc 
                 memory comes from. (Free store)
                 Note: This can "Grow" Upward
          Stack: A "stack" used for functions.

          Memory "MAP" / Usage Notes:
       0->0x400,000 Reserved:
                  Probably part of the OS instruction/Hardware
                  Memory Mapped Hardware
       0x400,000->0x10,000,000 Text Segment
                  This is where ALL instructions of your 
                  programs are placed.
                  (Program Must have less than 66 Million Insts?)
                  We can think of "constants" being stored here too.

      0x10,000,000-> Static Data Segment -"Load" Time allocated space
                      The things that exist for the entire
                      lifetime (global scope) of the program:
                      C/C++: Global Variables, 
                         Local Static Variables,
                         Initializers for arrays, classes
                         Char Constants (E.g.: "Hello")
                      ASM: 
                      Anything following a .data directive
                    Dynamic Data Segment - Run Time allocated space
                     C/C++: Space allocated while the program 
                      is running: new/malloc/alloc/realloc
                      ("Free Store"/"Heap")
                      This stuff is typically dynamically 
                      allocate because it's space isn't 
                      known in advance.
                    ASM: Anything allocated with the 
                         sbrk syscall 
               Note: This can "Grow" Upward
       0x7fffffff-> Stack Segment - Where all "local" variables
                   will be created/destroyed
                   Local Variables to functions (ALL Functions)
                   C/C++: ALL locally scopped (non-static) variables.
                     I.e. almost all variables declared in functions.

       Assembler reads through program and packs into approp.
       segments

       As it finds labels they are added to a table and later
       the actual numeric address is filled in.
This is actually somwhat helpful to understand
when you're de-bugging c/c++ programs.
Remeber that c/c++ is converted to ASM,
so it'll use the same segmentation.

D. j / beq data stored
j - store 26 bits (upper 26) direct address of location
beq/bne - store 16-bit displacement (how far to go)
Both change the PC register (I.e. the CPUs inst. bookmark)

II. New Stuff:   
A. Other useful assembler directives:
Declaring Space/Data (Uninitialized):
.space n - Set aside N bytes of space

Initialized Space:
.word w1,,,,wn - Put the following words in memory
.asciiz "..." - Put the following text in memory and
NULL terminate it
.ascii "..." - Put the following text in memory and
DON'T NULL terminate it.
.byte b1,,,,bn - Put the following bytes in memory
.float f1,,,,fn - Put the following floating point
numbers in memory
.half h1,,,,hn- Store Half words

Misc.
.align N - Force the following items to be aligned
to a N-bit boundary
I.e. .align 2 forces word alignment

B. LAB - MISC
Don't assume regsiters are initialized for you (just like in C)

Showing test runs:
Create Test Runs
File -> Save Log File As (Create a "log" of runs)
Edit this file and copy out the "Console" section
which will show the Console IO

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

4. 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)
5. MIPS functions:
It's name is a "label"
Shouldn't "step on" variables being used by main prog.
(I.e. they can only freely use the t registers....)
Must "return" to the right position in the calling program.

          jr - Return to the address provided in a specific reg
Ex: jr $ra # Return to the "return point" in the caller.
return value in $v0

Example Function:
Write a function to add 4 arguments.
Ex: a=add_args(b,c,d,e);
... (What happens next?...what's changed?)
(a=b+c+d+e)

add_args:
add $v0,$a0,$a1
add $t0,$a2,$a3
add $v0,$v0,$t0
jr $ra

Function Call:
li $a0,1
li $a1,2
li $a2,3
li $a3,4
jal add_args
move $s0,$v0
...

    D. This isn't enough...Local variables and recursion:
Example: Factorial Function & fact(5)
Factorial = N*(N-1)*(N-1)*...*1

       (Silly Example - "better" iterative solution and approximation)
unsigned fact(unsigned n)
{
if(n<1)
return 1; // base case of recursion
else
return n*fact(n-1);
}

       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?

    E. 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 Instructions:
           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
        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.

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