## LSU EE 4720
#
 ## Recursion example.
#
#   Factorial procedure written recursively. (Inefficient, but easy to
#   understand.)
#
#   Presented in class  1 October 2004

# Linkage (register usage) Rules for this Example:
#
# Caller Save:  $tX, $fX, $aX   (if caller will need values after return).
# Callee Save:  $ra, $sX

        .data
ONE:
        .double 1.0
MSG:
        .asciiz "%/s0/d! = %/f0/.0f\n"

        .text
        .globl __start
__start:

        addi $s0, $0, 0
MAINLOOP:
        mtc1 $s0, $f2
        jal fact
        cvt.d.w $f2, $f2
        la $a0, MSG
        addi $v0, $0, 11
        syscall
        slti $t0, $s0, 20
        bne $t0, $0, MAINLOOP
        addi $s0, $s0, 1
        addi $v0, $0, 10
        syscall


################################################################################
## fact: Factorial
#
#  Load constant 1.0 into register f4 and call fact1, which computes factorial.
#

fact:
        ## Register Usage
        #
        # CALL VALUE:   $f2/$f2  Number, n, double.
        # RETURN VALUE: $f0/$f1  n! (0! = 1! = 1), double.

        # Save $ra on the stack.
        #
        sw $ra, -4($sp)
        addi $sp, $sp, -4  # Move stack pointer above saved registers.

        la $t0, ONE
        jal fact1
        ldc1 $f4, 0($t0)

        # Restore $ra from stack and restore stack pointer.
        #
        addi $sp, $sp, 4
        lw $ra, -4($sp)
        jr $ra
        nop


################################################################################
## fact1: Factorial
#
#  Return $f2! in $f0.
#

fact1:
        ## Register Usage
        #
        # CALL VALUE:   $f2/$f3  Number, n, double.
        # CALL VALUE:   $f4/$f5  1.0, double.  (Used as a constant.)
        # RETURN VALUE: $f0/$f1  n! (0! = 1! = 1)

        #
        # Save $ra and $f2 on stack.
        #
        # $f4 is not saved because we know the called routine (this one)
        #   won't modify it.
        #
        sdc1 $f2, -8($sp)
        sw $ra, -12($sp)
        addi $sp, $sp, -12

        #
        # If n <= 1 return a 1. (Assume n is 0 or 1.)
        #
        c.le.d $f2, $f4
        bc1t F1DONE
        mov.d $f0, $f4

        #
        # Recursive call and factorial computation.
        #
        jal fact1
        sub.d $f2, $f2, $f4    # n_for_called_routine = n - 1
        ldc1 $f2, 4($sp)       # Get "our" value of n from stack.
        mul.d $f0, $f0, $f2

F1DONE:
        #
        # Restore $ra and $sp.
        #
        # (Register $f2 was restored above, where needed.)
        #
        addi $sp, $sp, 12
        lw $ra, -12($sp)
        jr $ra
        nop