# factorial.spim --- A recursive SPIM program.  Demonstrates function
#    call and return.


            .data
prompt:     .asciiz "Number: "
nl:         .asciiz "\n"
instr:      .asciiz "Enter 0 to exit.\n"
response:   .asciiz "Factorial: "


######################################################################
# main
######################################################################

            .text
            .globl main
main:
            sub $sp, $sp, 16     # Push frame & save registers.
            sw $fp, 16($sp)
            sw $ra, 12($sp)
            sw $s0,  8($sp)
            add $fp, $sp, 16

            li $v0, 4            # Print instruction.
            la $a0, instr
            syscall

            jal getnum           # Get a number from keyboard.

            sw $v0, -12($fp)     # Store locally.
            move $s0, $v0

while1:
            beqz $s0, endwhile1  # Compute until 0 entered.

            li $v0, 4            # Print response prompt.
            la $a0, response
            syscall

            move $a0, $s0        # Pass argument

            jal factorial        # Call

            move $a0, $v0        # Copy return value to print it
            li $v0, 1
            syscall

            li $v0, 4            # Prepare to read next number.
            la $a0, nl
            syscall

            jal getnum

            sw $v0, -12($fp)     # Store number just read.
            move $s0, $v0

            b while1

endwhile1:
            lw $s0,  8($sp)      # Restore registers and pop frame.
            lw $ra, 12($sp)
            lw $fp, 16($sp)
            add $sp, $sp, 16
            li $v0, 0
            jr $ra               # Exit.


######################################################################
# getnum --- returns integer read from keyboard through $v0.
######################################################################

            .text
getnum:
            sub $sp, $sp, 12     # push frame & save registers.
            sw $fp, 12($sp)
            sw $ra,  8($sp)
            add $fp, $sp, 12

            li $v0, 4
            la $a0, prompt
            syscall

            li $v0, 5
            syscall              # Value read left in $v0.

            sw $v0, -8($fp)

            lw $ra,  8($sp)      # restore registers & pop frame.
            lw $fp, 12($sp)
            add $sp, $sp, 12
            jr $ra


######################################################################
# factorial --- compute factorial of $a0 and return result through
#    $v0
######################################################################

            .text
factorial:
            sub $sp, $sp, 16
            sw $fp, 16($sp)
            sw $ra, 12($sp)
            sw $s0,  8($sp)
            add $fp, $sp, 16

            sw $a0, -12($fp)       # Our value n.
            move $s0, $a0

            bgt $s0, 1, recurse  # Base case.  Return 1
            li $v0, 1
            lw $s0, 8($sp)
            lw $ra, 12($sp)
            lw $fp, 16($sp)
            add $sp, $sp, 16
            jr $ra

recurse:    sub $a0, $a0, 1      # Recursive call.  Compute (n-1)!
            jal factorial
            mul $v0, $v0, $s0    # n * (n-1)!
            lw $s0, 8($sp)
            lw $ra, 12($sp)
            lw $fp, 16($sp)
            add $sp, $sp, 16
            jr $ra

