Fibonacci recursion function in Mips - recursion

I am trying to pratice how recursion works in Mips. So I tried to write a fibonacci function fib.
At first I had addi $a0, $a0, n to write a general solution, but I thought that if I want to check my results in Qtspim , maybe i need to add a real number as an argument. I do not want a full answer , if the thought behind the code is wrong, but some help in order to run it in Qtspim, and find my mistakes (logic mistakes) on my own
This is my code:
.globl main
.text
main:
addi $a0, $a0, 4
fib:
addi $sp, $sp, -8
sw $ra, 4($sp)
sw $a0, 0($sp)
slti $t0, $a0, 1
beq $t0, 1, L2 #if n<1
beq $a0, 1, L2 # if n=1
beq $t0, 0, L1 # if n>1
#what to do when n<=1
L2:
addi $v0, $v0, 1
jr $ra
#what to do when n>1
L1:
addi $a0, $a0, -1
jal fib
lw $a0, 0($sp)
lw $ra, 4($sp)
addi $sp, $sp, 8
lw $t1, 0($v0)
add $v0, $t1, $v0
jr $ra
li $v0,10
syscall
I get an error message as such:
Bad address in data/stack read: 0x00000000

.text
main:
addi $a0, $a0, 4
#### you've place fib inline inside main,
#### you should have all of main here, and "call" fib using jal instruction
#### and the syscall for exit goes up here as well
fib:
addi $sp, $sp, -8 # you will want one more word of stack space
sw $ra, 4($sp)
sw $a0, 0($sp)
slti $t0, $a0, 1 # i would have use 2 here instead of 1
beq $t0, 1, L2 #if n<1 # this is ok, but better to use bne $t0, $0, L2
beq $a0, 1, L2 # if n=1 # and then this would not be needed
beq $t0, 0, L1 # if n>1 # this doesn't need to be conditional, if the program reaches here then L1 is the thing to do next.
#what to do when n<=1
L2:
addi $v0, $v0, 1 # here you want to return just 1 not v0+1
jr $ra
#what to do when n>1
L1:
addi $a0, $a0, -1
jal fib # fib(n-1), good
lw $a0, 0($sp) # this reloads $a0 the original n
lw $ra, 4($sp)
addi $sp, $sp, 8
lw $t1, 0($v0) # after a call to fib $v0 holds fib(n)
# an integer value but you're treating it like a pointer and dereferencing it
add $v0, $t1, $v0 # here doing fib(n-1) + n
# you want fib(n-1) + fib(n-2) instead
# so you're missing a fib(n-2)
jr $ra
li $v0,10 # this is part of main, so move it to where main is
syscall # realize that code located here is unreachable (aka dead)
# anything after an unconditional branch (here the jr $ra just above)
# and without a label is very suspicious as unreachable

update , some improved (i hope ) code
.globl main
.text
main:
addi $a0, $a0, 4
jal fib
li $v0, 10
syscall
fib:
addi $sp, $sp, -8
sw $ra, 4($sp)
sw $a0, 0($sp)
slti $t0, $a0, 2
beq $t0, 1, L2
#what to do when n<=1
L2:
addi $v0, $v0, 1
jr $ra
#what to do when n>1
L1:
addi $a0, $a0, -1 # a0 -> n-1
jal fib # fib(n-1)
lw $a0, 0($sp) #load word from memory adress 0($sp) to register $a0
lw $ra, 4($sp) #load word from memory adress 4($sp) to register $ra
addi $sp, $sp, 8
add $t1, $zero, $v1 # in register $t1 store current $v1
add $v0, $t2, $v0 # v0_ n+1 =v0 _n + v0_n-1
add $t2, $t1, $zero # in $t2 save the previous value of v1

.data
prompt: .ascii "Fibonacci Program\n"
.asciiz "Enter N value: "
results: .asciiz "\nFibonacci of N = "
n: .word 0
answer: .word 0
.text
.globl main
.ent main
main:
# Read n value from user
li $v0, 4 # print prompt string
la $a0, prompt
syscall
li $v0, 5 # read N (as integer)
syscall
sw $v0, n
# Call Fibonacci function.
lw $a0, n
jal fib
sw $v0, answer
# Display result
li $v0, 4 # print prompt string
la $a0, results
syscall
li $v0, 1 # print integer
lw $a0, answer
syscall
# Done, terminate program.
li $v0, 10 # terminate
syscall # system call
.end main
# Fibonacci function
# Recursive definition:
# = 0 if n = 0
# = 1 if n = 1
# = fib(n-1) + fib(n-2) if n > 2
# Arguments
# $a0 - n
# Returns
# $v0 set to fib(n)
.globl fib
.ent fib
fib:
subu $sp, $sp, 8
sw $ra, ($sp)
sw $s0, 4($sp)
move $v0, $a0 # check for base cases
ble $a0, 1, fibDone
move $s0, $a0 # get fib(n-1)
sub $a0, $a0, 1
jal fib
move $a0, $s0
sub $a0, $a0, 2 # set n-2
move $s0, $v0 # save fib(n-1)
jal fib # get fib(n-2)
add $v0, $s0, $v0 # fib(n-1)+fib(n-2)
fibDone:
lw $ra, ($sp)
lw $s0, 4($sp)
addu $sp, $sp, 8
jr $ra
.end fib

Related

Mips Recursive Assignment

I hope everyone is okay in these covid-19 times. I am working on an assignment and I'm hoping someone could point out where I'm going wrong. I'm taking in a number in a MIPS program that will be put in a recursive function that returns the following:
Guidelines are:
The recursive function accepts a single positive integer as an input argument and is defined as:
recurse(n) = 1 if n=0
recurse(n) = n * Recurse(n-1) + 1 if n >0
My recursing is going alright, but I feel like I'm getting lost in the returns when the function unwinds. I'm also pretty sure that a lot of what I'm doing might look very messy as I'm a novice with MIPS. Here is my version:
Here is my code:
PRINT_STRNG = 4
PRINT_INT = 1
PRINT_CHAR = 11
READ_CHAR = 12
READ_STRNG = 8
READ_INT = 5
TERMINATE = 10
NEWLINE = 10
.data
prompt1: .asciiz "\nPlease enter a decimal integer between 1 and 12 (or 0 to stop): "
terminating: .asciiz "\nTerminating!"
recursing: .asciiz "recursing "
returning: .asciiz "returning "
newLine: .asciiz "\n"
.text
main:
jal clearRegs
li $t0, 4
jal promptNumber
move $a1, $v0
beq $a1, $zero, exit
move $t2, $a1 # $t2 has n
mul $t1, $a1, $t0 # $t1 has the spaces
jal factPlusOne
j main
promptNumber:
# Prompt the user for first decimal
li $v0, PRINT_STRNG
la $a0, prompt1
syscall
# Get the user's first decimal
li $v0, READ_INT
syscall
# Print new line after
li $v0, PRINT_STRNG
la $a0, newLine
syscall
jr $ra
printRecursingSpaces:
# $ra now points to below print spaces
# Prints the spaces before the recursing messages
blez $t1, printRecursing
li $a0, 32
li $v0, 11 # syscall number for printing character
syscall
addi $t1, $t1, -1
j printRecursingSpaces
printReturningSpaces:
# Prints the spaces before the returning messages
blez $t1, printReturning
li $a0, 32
li $v0, 11 # syscall number for printing character
syscall
addi $t1, $t1, -1
j printReturningSpaces
factPlusOne:
# Tests to enter recursion or end recursion
move $s0, $ra
jal printRecursingSpaces
bgtz $a1, recurse
li $t3, 1
jr $s0
recurse:
addi $sp, $sp, -8
sw $ra, 4($sp)
sw $a1, 0($sp)
addi $a1, $a1, -1
mul $t1, $a1, $t0
jal factPlusOne
lw $v1, 0($sp)
mul $t4, $t3, $v1
addi $t4, $t4, 1 # $t3 has n * Recurse(n-1) + 1
mul $t1, $t4, $t0
jal printReturningSpaces
lw $ra, 4($sp)
addi $sp, $sp, 8
jr $ra
printRecursing:
# Prints the recursing message
li $v0, PRINT_STRNG
la $a0, recursing
syscall
# Print the n
li $v0, PRINT_INT
addi $a0, $a1, 0
syscall
# Prints a new line
li $v0, PRINT_STRNG
la $a0, newLine
syscall
jr $ra
printReturning:
# Prints the returning message
li $v0, PRINT_STRNG
la $a0, returning
syscall
# Print the n
li $v0, PRINT_INT
addi $a0, $t4, 0
syscall
# Prints a new line
li $v0, PRINT_STRNG
la $a0, newLine
syscall
jr $ra
clearRegs:
sub $v0, $v0, $v0
sub $v1, $v1, $v1
sub $a0, $a0, $a0
sub $a1, $a1, $a1
sub $t0, $t0, $t0
sub $t1, $t1, $t1
sub $t2, $t2, $t2
sub $t3, $t3, $t3
sub $t4, $t4, $t4
sub $s0, $s0, $s0
jr $ra
exit:
# Show terminating message and exit program
li $v0, PRINT_STRNG
la $a0, terminating
syscall
li $v0, TERMINATE
syscall
Gonna be hacking at it for the next few hours. I appreciate any assistance and hope everyone is having a good Sunday. Thank you!
I did end up fixing this, I just had to grasp the concept that anywhere you need to save the value of $ra, make a stack variable. Working code below:
PRINT_STRNG = 4
PRINT_INT = 1
PRINT_CHAR = 11
READ_STRNG = 8
READ_INT = 5
TERMINATE = 10
NEWLINE = 10
.data
prompt1: .asciiz "\nPlease enter a decimal integer between 1 and 6 (or 0 to stop): "
terminating: .asciiz "\nTerminating!"
recursing: .asciiz "recursing "
returning: .asciiz "returning "
newLine: .asciiz "\n"
theNumber: .word 0
.text
main:
li $t0, 4
jal promptNumber
lw $a1, theNumber
bgt $a1, 6, main # If >6 is entered
beq $a1, $zero, exit # If 0 is entered
blez $a1, main # If <0 is entered
mul $t1, $a1, $t0 # $t1 has the spaces
jal factPlusOne
jal printReturningSpaces # for the last result
j main
promptNumber:
# Prompt the user for first decimal
li $v0, PRINT_STRNG
la $a0, prompt1
syscall
# Get the user's first decimal
li $v0, READ_INT
syscall
sw $v0, theNumber
# Print new line after
li $v0, PRINT_STRNG
la $a0, newLine
syscall
jr $ra
printRecursingSpaces:
# Prints the spaces before the recursing messages
blez $t1, printRecursing
li $a0, 32
li $v0, 11 # syscall number for printing character
syscall
addi $t1, $t1, -1
j printRecursingSpaces
printReturningSpaces:
# Prints the spaces before the returning messages
blez $t1, printReturning
li $a0, 32
li $v0, 11 # syscall number for printing character
syscall
addi $t1, $t1, -1
j printReturningSpaces
factPlusOne:
# Tests to enter recursion or end recursion, saves $ra
addi $sp, $sp, -4
sw $ra, 0($sp)
jal printRecursingSpaces
lw $ra, 0($sp)
addi $sp, $sp, 4
bgtz $a1, recurse
li $t3, 1
jr $ra
recurse:
# wind up recursion
addi $sp, $sp, -8
sw $ra, 4($sp)
sw $a1, 0($sp)
addi $a1, $a1, -1
mul $t1, $a1, $t0
jal factPlusOne
# unwind recursion
lw $v1, 0($sp)
jal printReturningSpaces
mul $t1, $v1, $t0
mul $t3, $t3, $v1
addi $t3, $t3, 1
lw $ra, 4($sp)
addi $sp, $sp, 8
jr $ra
printRecursing:
# Prints the recursing message
li $v0, PRINT_STRNG
la $a0, recursing
syscall
# Print the n
li $v0, PRINT_INT
addi $a0, $a1, 0
syscall
# Prints a new line
li $v0, PRINT_STRNG
la $a0, newLine
syscall
jr $ra
printReturning:
# Prints the returning message
li $v0, PRINT_STRNG
la $a0, returning
syscall
# Print the n
li $v0, PRINT_INT
addi $a0, $t3, 0
syscall
# Prints a new line
li $v0, PRINT_STRNG
la $a0, newLine
syscall
jr $ra
exit:
# Show terminating message and exit program
li $v0, PRINT_STRNG
la $a0, terminating
syscall
li $v0, TERMINATE
syscall

Double Recursion in Assembly works until secondary recursion becomes larger than the base case

I am trying to code a Assembly program that will ask for an integer and perform a recursive function: if n>5 f(n) = n*f(n-1)-f(n-3)+n-23 else n<=5 f(n)=15-2n I managed to get the first instance of recursion of the n*f(n-1)but when it goes for the second recursion of f(n-3) it performs the second portion improperly.
During the calculations, if I input 8 as the integer, the result should be 20 which I get but, when I input anything greater than 8 because then the second recursion hits an integer larger than 5 (the base case) I get an incorrect answer. Basically any input larger than 8 doesn't work
For example the correct answers are:
f(9) = 162
f(10) = 1602
f(11) = 17590
The answers I get
f(9)= 27
f(10)=22
f(11)=23
Here is my code:
```#data declarations: declare variable names used in program, storage allocated in RAM
.data
prompt1: .asciiz "\nEnter an Integer:\n" #Ending Index
message1: .asciiz "\nThe Solution is:\n"
answer: .word 0
#program code is contained below under .text
.text
.globl main #define a global function main
# the program begins execution at main()
main:
la $a0, prompt1 #load address of prompt1
li $v0, 4 #prepare print string
syscall
li $v0, 5 #prepare receive int
syscall
move $a0, $v0
addi $sp, $sp, -4
sw $ra, 0($sp)
jal Function
sw $v0, answer #move returned answer to a new memory
lw $ra, 0($sp)
addi $sp, $sp, 4
la $a0, message1 #load address of message1
li $v0, 4 #prepare print string
syscall
lw $a0, answer
li $v0, 1
syscall
jr $ra
############################################################################
# Procedure/Function Function1
# Description: recursive math function
# parameters: $a0 = value of n,
# return value: $v0 = answer
# registers to be used: $s3 and $s4 will be used.
############################################################################
Function:
addi $sp, $sp, -12 #adjust stack pointer
sw $ra, 8($sp) #save return address
sw $a0, 4($sp) #save n
sw $s0, 0($sp) #save immediate value (used for storing function(n-1))
li $t2, 15
slti $t0, $a0, 6
beq $t0, $zero, GreaterThanFive
LessThanFive:
add $t1, $a0, $zero
add $t1, $t1, $a0
sub $t2, $t2, $t1
move $v0, $t2
j Conclusion
GreaterThanFive:
addi $a0, $a0, -1
jal Function
move $s0, $v0
lw $a0, 4($sp)
addi $a0, $a0, -3
jal Function
lw $a0, 4($sp)
mul $t3, $a0, $s0
sub $t4, $t3, $v0
add $t5, $t4, $a0
addi $t6, $t5, -23
move $v0, $t6
Conclusion:
lw $s1,0($sp) # restore intermediate value
lw $a0,4($sp)
lw $ra,8($sp)
addi $sp,$sp,12 # restore stack
jr $ra #return to caller```

Error in MIPS assembler regarding fetch address not being aligned

having some trouble with an assignment, not looking for solution code, just some answers to why I keep encountering this error.
The program asks the user for 10 digits and then displays the resulting sum (using the stack and recursion).
I know from debugging that the read: portion works fine, but I get the error "Runtime exception at 0x0040005c: fetch address not aligned on word boundary 0x00000001". The error refers to the line in summation: lw $t0, 0($a0)
Not sure what is wrong since I only ever increment by 4 bytes. I've checked other similar questions but couldn't find any clarification. Any help would be greatly appreciated.
.data
A1: .space 40
input: .asciiz "please enter a number: "
Str: .asciiz "the sum is: "
.text
main:
li $s1, 0
la $t0, A1
addi $s0, $zero, 0
read:
beq $s1, 10, prep
li $v0, 4
la $a0, input
syscall
li $v0, 5
syscall
sw $v0, ($t0)
addi $t0, $t0, 4
addi $s1, $s1, 1
j read
prep:
la $a0, A1
addi $a1, $a0, 40
jal summation
summation:
subi $sp, $sp, 8
sw $ra, 4($sp)
lw $t0, 0($a0)
sw $t0, 0($sp)
sgt $t1, $a0, $a1
beq $t1, $zero, L1
addi $v0, $zero, 0
addi $sp, $sp, 8
jr $ra
L1:
addi $a0, $a0, 4
jal summation
lw $a0, 0($sp)
lw $ra 4($sp)
addi $sp, $sp, 8
add $v0, $a0, $v0
jr $ra

implementing recursive function in MIPS

I'm a bit confused on how to compile recursive functions in mips:
the following question was in a previous exam in my computer organization course:
the question asks us to compile:
int sum(int n){
if (n <= 1)
return 1;
else
return n + sum( sum(n-1) – sum(n-2) );
}
My attempt at tackling this problem:
sum: bgt $a0, 1, sum_recursive
add $v0, $0,1
jr $ra
sum_recursive: sub $sp, $sp, -12
sw $ra ,0($sp) # storing the return address
sw $a0, 4($sp) # storing the argument n
addi $a0, $a0, -1 # n-1
jal sum
sw $v0, 8($sp) # the return value of sum(n-1)
lw $a0, 4($sp) # a0=n
addi $a0, $a0, -2 # a0=n-2
jal sum
lw $t0, 8($sp) # the return value of sum (n-1)
sub $v0, $t0, $v0 # sum(n-1) - sum (n-2)
lw $a0, 4($sp)
add $a0, $v0, $0 # a0=sum (n-1)-sum (n-2)
jal sum
lw $a0, 4($sp)
add $v0, $v0, $a0 # $v0 = n+ sum (sum (n-1)- sum(n-2))
lw $ra, 0($sp)
lw $a0, 4 ($sp)
add $sp, $sp, 12
jr $ra
Thank you

Mips recursion that I am stuck at

Okay Im trying to do C(n, k) = C(n - 1, k - 1) + C(n - 1, k).
So far I have:
$a0 - n
$a1 - k
$v0 - C(n, k)
addi $sp, $sp, 8
sw $ra, 4($sp)
sw $s0, 0($sp)
addi $a0, $a0, -1
addi $a1, $a1, -1
lw $ra, 0($sp)
lw $s0, 4($sp)
Now Im lost on what to do next please help me out.
If I look right, it's about the binomial coefficient. Yes, the first steps into MIPS can be kinda confusing, but practice is the key to get better. I don't know if you are in any course or anything. I wrote up something for you, here with the extra feature of getting the input values for n and k. In the end, it prints out the result of C(n, k).
.TEXT
.GLOBL __MAIN
__MAIN:
LI $V0, 4 // print1 asking you for number (n).
LA $A0, PRINT1
SYSCALL
LI $V0,5 // do a syscall that reads an integer.
SYSCALL
MOVE $T0, $V0
LI $V0, 4 // print2 asking you for number (k).
LA $A0, PRINT2
SYSCALL
LI $V0,5 // do a syscall that reads an integer.
SYSCALL
MOVE $A0, $T0
MOVE $A1, $V0
JAL BINOMIALVAL
// this marks the end of procedure call. woo.
MOVE $T0, $V0
LI $V0, 4 // prints print3.
LA $A0, PRINT3
SYSCALL
MOVE $A0, $T0
LI $V0,1 // this prints your c(n,k)
SYSCALL
LI $V0,4 // this will print an eol. (end of line)
LA $A0, CR
SYSCALL
LI $V0,10 // exit here.
SYSCALL
// will display the result and exit.
BINOMIALVAL:
SLT $T0, $A0, $A1 // if n < k, then set t0 to 1.
BNE $T0, $ZERO, END1 // if t0 != 0, then branch to end1.
BEQ $A0, $A1, END2 // if n == k, then branch to end2
BEQ $A1, $ZERO, END2 // if n == 0, then branch to end2.
SW $FP, -4($SP)
ADDI $FP, $SP, 0
ADDI $SP, $SP, -12
SW $RA, 4 ($SP)
SW $A0, 0 ($SP)
ADDI $SP, $SP, -4
SW $T1, ($SP)
ADDI $A0, $A0, -1
JAL BINOMIALVAL
MOVE $T1, $V0
ADDI $SP, $SP, -4
SW $A1, ($SP)
ADDI $SP, $SP, -4
SW $RA, ($SP)
ADDI $A1, $A1, -1
JAL BINOMIALVAL
ADD $V0, $T1, $V0
LW $RA, ($SP)
ADDI $SP, $SP, 4
LW $A1, ($SP)
ADDI $SP, $SP, 4
LW $T1, ($SP)
ADDI $SP, $SP, 4
LW $A0, ($SP)
ADDI $SP, $SP, 4
LW $RA, ($SP)
ADDI $SP, $SP, 4
LW $FP, ($SP)
ADDI $SP, $SP, 4
J COMPLETE
END1: MOVE $V0, $ZERO
J COMPLETE
END2: ADDI $V0, $ZERO, 1
COMPLETE: JR $RA // return to normal routine.
.DATA
PRINT1: .asciiz "Enter your value for n "
PRINT2: .asciiz "Enter your value for k "
PRINT3: .asciiz "Value of c(n,k) = "
CR: .asciiz "\n"

Resources