Created
September 19, 2012 03:35
-
-
Save dcalacci/3747521 to your computer and use it in GitHub Desktop.
simple factorial program in MIPS assembly
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.globl main | |
.data | |
msgprompt: .word msgprompt_data | |
msgres1: .word msgres1_data | |
msgres2: .word msgres2_data | |
msgprompt_data: .asciiz "Positive integer: " | |
msgres1_data: .asciiz "The value of factorial(" | |
msgres2_data: .asciiz ") is " | |
# every function call has a stack segment of 12 bytes, or 3 words. | |
# the space is reserved as follows: | |
# 0($sp) is reserved for the initial value given to this call | |
# 4($sp) is the space reserved for a return value | |
# 8($sp) is the space reserved for the return address. | |
# calls may manipulate their parent's data, but parents may not | |
# manipulate their child's data. | |
# i.e: if we have a call A who has a child call B: | |
# B may run: | |
# sw $t0, 16($sp) | |
# which would store data from $t0 into the parent's return value register | |
# A, however, should not(and, in all cases I can think of, cannot) manipulate | |
# any data that belongs to a child call. | |
.text | |
main: | |
# printing the prompt | |
#printf("Positive integer: "); | |
la $t0, msgprompt # load address of msgprompt into $t0 | |
lw $a0, 0($t0) # load data from address in $t0 into $a0 | |
li $v0, 4 # call code for print_string | |
syscall # run the print_string syscall | |
# reading the input int | |
# scanf("%d", &number); | |
li $v0, 5 # call code for read_int | |
syscall # run the read_int syscall | |
move $t0, $v0 # store input in $t0 | |
move $a0, $t0 # move input to argument register $a0 | |
addi $sp, $sp, -12 # move stackpointer up 3 words | |
sw $t0, 0($sp) # store input in top of stack | |
sw $ra, 8($sp) # store counter at bottom of stack | |
jal factorial # call factorial | |
# when we get here, we have the final return value in 4($sp) | |
lw $s0, 4($sp) # load final return val into $s0 | |
# printf("The value of 'factorial(%d)' is: %d\n", | |
la $t1, msgres1 # load msgres1 address into $t1 | |
lw $a0, 0($t1) # load msgres1_data value into $a0 | |
li $v0, 4 # system call for print_string | |
syscall # print value of msgres1_data to screen | |
lw $a0, 0($sp) # load original value into $a0 | |
li $v0, 1 # system call for print_int | |
syscall # print original value to screen | |
la $t2, msgres2 #load msgres2 address into $t1 | |
lw $a0, 0($t2) # load msgres_data value into $a0 | |
li $v0, 4 # system call for print_string | |
syscall # print value of msgres2_data to screen | |
move $a0, $s0 # move final return value from $s0 to $a0 for return | |
li $v0, 1 # system call for print_int | |
syscall # print final return value to screen | |
addi $sp, $sp, 12 # move stack pointer back down where we started | |
# return 0; | |
li $v0, 10 # system call for exit | |
syscall # exit! | |
.text | |
factorial: | |
# base case - still in parent's stack segment | |
lw $t0, 0($sp) # load input from top of stack into register $t0 | |
#if (x == 0) | |
beq $t0, 0, returnOne # if $t0 is equal to 0, branch to returnOne | |
addi $t0, $t0, -1 # subtract 1 from $t0 if not equal to 0 | |
# recursive case - move to this call's stack segment | |
addi $sp, $sp, -12 # move stack pointer up 3 words | |
sw $t0, 0($sp) # store current working number into the top of the stack segment | |
sw $ra, 8($sp) # store counter at bottom of stack segment | |
jal factorial # recursive call | |
# if we get here, then we have the child return value in 4($sp) | |
lw $ra, 8($sp) # load this call's $ra again(we just got back from a jump) | |
lw $t1, 4($sp) # load child's return value into $t1 | |
lw $t2, 12($sp) # load parent's start value into $t2 | |
# return x * factorial(x-1); (not the return statement, but the multiplication) | |
mul $t3, $t1, $t2 # multiply child's return value by parent's working value, store in $t3. | |
sw $t3, 16($sp) # take result(in $t3), store in parent's return value. | |
addi $sp, $sp, 12 # move stackpointer back down for the parent call | |
jr $ra # jump to parent call | |
.text | |
#return 1; | |
returnOne: | |
li $t0, 1 # load 1 into register $t0 | |
sw $t0, 4($sp) # store 1 into the parent's return value register | |
jr $ra # jump to parent call |
It works for any number smaller than 13 but doesnot work for anything greater than 13.
Can you please let us know how to handle the issue for larger number?
thank you so much
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
that is kul, can I please have a complete tutorial for dummies on Assemble Language Programming