using recursive to compute fibonalci sequence (mips code) - recursion

i have this c code for fibonalcci sequence using recursive:
int fib(int n)
{
if (n==0) return 0;
if (n==1) return 1;
else return fib(n-1)+fib(n-2);
}
and i want to translate that c code into mips code (register a0 contain the value of n and register s0 contain the value of fib(n) )
here is what i have done:
F: bne $a0,$zero,L
addi $s0,$zero,0
addi $s1,$zero,1
jr $ra
L: addi $sp,$sp,-4
sw $ra,0($sp)
addi $a0,$a0,-1
jal F
addi $t0,$s1,0
add $s1,$s0,$s1
addi $s0,$t0,0
lw $ra,0($sp)
addi $sp,$sp,4
jr $ra
but it seem not do exactly what the c code do and i want to fix the mips code to let it do exactly like the c code. How do i fix that mips code?

Related

MIPS Assembly - how to calculate the square of n recursively

I want to write a program that calculates the square of n using recursion based on the equation n^2 = (n - 1)^2 + 2(n - 1) + 1 But I don't know how to write the nonbasecase: part. Can anyone help?
A python program would be
def square(n) {
if (n==0):
return 0
else:
return square(n-1) + 2*(n-1) + 1
}
Here is what I got so far.
start:
li $a0, 0x0003 #$a0 contains the number to be squared
jal square # recursive call
square:
subi $sp, $sp, 8 # decrement the stack pointer $sp
sw $ra, 4($sp) # push the return address register $ra
sw $a0, 0($sp) # push argument register $a0
li $t0, 0x0001 # load $t0 with 1 as part of test for base case
bne $a0, $t0, nonbasecase # branch if not the base case
li $v0, 0x0001 # return base result in $v0
addi $sp, $sp 8 # recover stack space
jr $ra # jump to return address in $ra
nonbasecase:
#not sure how to write when it is not the base case
jr $ra # jump to contents of return address register $ra
Write the function so that it inputs n2 and n and returns n2+2*n+1 and n+1.

When exactly are non-preserved registers cleared in MIPS?

Below is the Fibonacci value expressed in MIPS.
fib: addi $sp, $sp, -24
sw $ra, 16($sp)
sw $a0, 20(sp) # recursive calls will overwrite original $a0
sw $s0. 0($sp) # holds fib(n-1)
# end prologue
slti $t0, $a0, 4 # fib(i) = i for i = 1, 2, 3; fib(0) = 0 by C code
beq $t0, $zero, L1
addi $v0, $a0, 0 # see prior comment (assumes $a0 non-negative integer)
j exit
# fib(n) = fib(n-1) + fib(n-2)
L1: addi $a0, $a0, -1
jal fib
addi $s0, $v0, 0 # $s0 = fib(n-1) <-----how can use $v0?
addi $a0, $a0, -1
jal fib # upon return, $v0 holds fib(n-2)
add $v0, $v0, $s0
exit: # unwind stack and return
lw $s0, 0($sp)
lw $a0, 20($sp)
lw $ra, 16($sp)
addi $sp, $sp, 24
jr $ra
But there is something I don't quite understand here. As far as I know, the values ​​of the registers other than $s disappear when the function ends.
Looking at the fib function, when n is 1 or 0, 1 or 0 is stored in the value of $v0. After that, when the function ends, shouldn't the value of $v0 be deleted too? So, before calling fib(n-2), the return value of fib(n-1) is deleted, so I thought that the code to be saved in $s should be written in the fib function.
However, in the code above, the return value of the fib(n-1) function is used by the next fib(n-2) function. I don't know how this is possible.
Exactly how long are non preserved registers preserved and when will they be deleted?
Please be aware that the fib you're quoting is following custom and non-standard calling convention.  I don't recommend it for learning about call preserved vs. call clobbered registers.
In this section here:
L1: addi $a0, $a0, -1
jal fib
addi $s0, $v0, 0 # $s0 = fib(n-1) <-----how can use $v0?
addi $a0, $a0, -1 <------------- **HERE** --------
jal fib # upon return, $v0 holds fib(n-2)
At the line marked **HERE**, the code expects $a0 to have survived the function call.  This non-standard, and a disingenuous illustration of the proper MIPS calling convention.
While this code works, it does not follow the MIPS calling convention register usage.  It has made a custom alteration, that is only possible by knowing the implementation of both caller and callee.  Thinking this way is false for the general case.
exit: # unwind stack and return
lw $s0, 0($sp)
lw $a0, 20($sp) <----------- **ALSO**
lw $ra, 16($sp)
addi $sp, $sp, 24
jr $ra
This part marked **ALSO** is where the code is restoring $a0 for the caller!  This is unconventional and in the general case not to be relied upon.  In the general case, no one shall rely on $a0 being preserved, and so no one should bother to restore it.
Here's a proper (and more efficient) version of recursive fib:
fib:
beq $a0, $0, return0 # goto return 0 if n == 0
li $v0, 1 # load $v0 with 1 for comparison and return
beq $a0, $v1, return # if n == 1 return leaving 1 in $v0
addiu $sp, $sp -8 # allocate two words of stack space
sw $ra, 4($sp) # save $ra
sw $a0, 0($sp) # save n
addi $a0, $a0, -1
jal fib # fib(n-1)
lw $a0, 0($sp) # restore $a0 for next call to fib
sw $v0, 0($sp) # store return value of fib(n-1) in stack
addi $a0, $a0, -2
jal fib # fib(n-2)
lw $t0, 0($sp) # reload return value from fib(n-1)
add $v0, $t0, $v0 # fib(n-1)+fib(n-2)
lw $ra, 4($sp) # restore our return address
addiu $sp, $sp, 8 # release stack
jr $ra # and use return address
return0:
li $v0, 0
return:
jr $ra
This version actually follows the MIPS calling convention.  It does not convert $a0 into a call preserved register, instead reloading $a0 before the 2nd recursive call instead of in epilogue.
This version does not use $s registers, as they are actually a disadvantage in the circumstances of this particular function.  Stack memory is used instead.  An $s register version would be (just slightly) longer, because the same number of loads & stores would be involved (but for different purpose of preserving $s register) though a extra register-to-register copy instruction would be needed making it longer.
As far as I know, the values ​​of the registers other than $s disappear when the function ends.
All the registers are permanent and accessible to all machine code in the program, and that includes both $t, $a, $v, and $s registers, for example.
The register values only change by executing machine code instructions that target them.  Whether you're allowed (or supposed) to do that is a matter of software convention, which tells us how to share a mere 31 registers in a program that may have thousands of functions.
By software agreement, $a0 is used to pass the first (integer or pointer) parameter, and $v0 is used to return a function's (integer or pointer) return value.  Once a register is set it doesn't change unless some machine code instruction changes it.  Thus, register values have continuity and are under total control of the machine code program.

MIPS recursive function not working properly

I'm doing a factorial recursive function in MIPS. Here is the code:
fact: #a1 = n a2 = res
addi $t1,$zero,1
beq $a1,$t1,end # if n == 1 return res
#else
mul $a2,$a2,$a1
subi $a1,$a1,1
jal fact
end:
sb $a2,res
jr $ra
The problem is, this code only works when i write j fact instead of jal fact, with jal fact the code run infinitely for some reason.
fact: #a1 = n a2 = res
addi $t1,$zero,1
beq $a1,$t1,end # if n == 1 return res
#else
addi $sp, $sp, 8
sw $a1, 0($sp) # in the top of the stack store the argument you called fact
sw $ra, 4($sp) # ra holds the return adress ( I do not know whether you know it)
mul $a2,$a2,$a1
subi $a1,$a1,1
jr $ra
jal fact
lw $a1, 0($sp) # load the value from memory adress that the top stack pointer shows to back to the register a1
lw $ra, 4($sp)
addi $sp, $sp, 8 # delete current top , top-1 from the stack
jr $ra
end:
sb $a2,res
jr $ra

Recursive function using MIPS assembly

I'm having some trouble on an assignment and would appreciate some help. I'm not asking for the answer, I prefer to put two and two together to figure it out myself, but I know so little about MIPS its hard for me to know where to start.
Here is what I started with
.data
.text
main:
addi $sp, $sp, -16 #prepare stack for 4 items
sw $s0, 0($sp)
sw $s1, 4($sp)
sw $s2, 8($sp)
sw $ra, 12($sp)
move $s0, $a0
move $s1, $a1
add $s2, $s0, $s1 #add two previous numbers and store result in $s2
move $v0, $s2 #put answer into $v0
lw $s0, 0($sp)
lw $s1, 4($sp)
lw $s2, 8($sp)
lw $ra, 12($sp)
addi $sp, $sp, 16
jr$ra
Essentially we are to use a recursive function to calculate the fibonacci numbers and a loop to print out the first 10 numbers of the fibonacci sequence.
I have looked up many examples but they all use instructions that we haven't learned yet so I can't make sense of it and I can only assume we aren't expected to use them. In the code above I'm essentially creating a stack to store the $ra along with three values, the two numbers to be added and the sum. Part of my problem is understanding where the function starts and ends and what the totality of the work being done is.
We were also given that to print you use the following
li $v0, 1
move $a0, $s0
syscall
Am I correct in thinking this is printing the value stored in $v0?
Here is the code for your function. I know you are not looking for the answer but sometimes looking for an example and seeing how it works gets you more easily to the point where you understand how it really works.
.data
msg1: .asciiz "Give a number: "
.text
.globl main
main:
li $v0, 4
la $a0, msg1
syscall # print msg
li $v0, 5
syscall # read an int
add $a0, $v0, $zero # move to $a0
jal fib # call fib
add $a0, $v0, $zero
li $v0, 1
syscall
li $v0, 10
syscall
fib:
# $a0 = y
# if (y == 0) return 0;
# if (y == 1) return 1;
# return fib(y - 1) + fib(y - 2);
#save in stack
addi $sp, $sp, -12
sw $ra, 0($sp)
sw $s0, 4($sp)
sw $s1, 8($sp)
add $s0, $a0, $zero
addi $t1, $zero, 1
beq $s0, $zero, return0
beq $s0, $t1, return1
addi $a0, $s0, -1
jal fib
add $s1, $zero, $v0 # $s1 = fib(y - 1)
addi $a0, $s0, -2
jal fib # $v0 = fib(n - 2)
add $v0, $v0, $s1 # $v0 = fib(n - 2) + $s1
exitfib:
lw $ra, 0($sp) # read registers from stack
lw $s0, 4($sp)
lw $s1, 8($sp)
addi $sp, $sp, 12 # bring back stack pointer
jr $ra
return1:
li $v0,1
j exitfib
return0:
li $v0,0
j exitfib
Like Gusbro said in order to use recursion in mips you will have to do 2 things. jal (jump and link) to the name of the function but first always store the return address into a stack, $ra, so in the future if you want to return back to the beginning you will be able to using jr $ra. If you don't save a return address and try to access it via jr you will most likely get an invalid program counter error.
Here goes some hints:
You have to write a recursive function, but you are not writing a function at all.
To write this function in MIPS assembler I suggest you first write it in a higher level language (C).
So it would go something like this:
int fib(int n)
{
if(n == 0 or n == 1)
return n;
else return fib(n-1) + fib(n-2);
}
The first line checks whether you are in a base case of the recursion (n=0 or n=1). If thats the case, fib(n) returns n.
Otherwise the recursion step goes which returns the sum of fib(n-1) plus fib(n-2).
So you will have to write a function, define the input/output parameters (which register will held n and which will return fib(n).
The manually compile the C code.
To start a function, just add a label
fib:
then put your stack management code there.
then translate the IF-THEN-ELSE to MIPS assemble.
to issue the recursive call, use jal instruction.
Before returning from the function with jr $ra restore the saved values from the stack.
Your main program will load the input parameter (the register used for input argument n), then jal fib.
This explains how to implement the Fibonacci function in MIPS as well as how to translate a MIPS function back to equivalent C code, it's well detailed : Fibonacci function in MIPS by illinois.edu
The code for the base case:
fib:
bgt $a0, 1, recurse
move $v0, $a0
jr $ra
Convert the code for the base case.
fib:
bgt $a0, 1, recurse
move $v0, $a0
jr $ra
Save callee- and caller-saved registers on the stack.
recurse:
sub $sp, $sp, 12 # We need to store 3 registers to stack
sw $ra, 0($sp) # $ra is the first register
sw $a0, 4($sp) # $a0 is the second register, we cannot assume $a registers will not be overwritten by callee
Call fib recursively:
addi $a0, $a0, -1 # N-1
jal fib
sw $v0, 8($sp) # store $v0, the third register to be stored on the stack so it doesn’t get overwritten by callee
Call fib recursively again:
lw $a0, 4($sp) # retrieve original value of N
addi $a0, $a0, -2 #N-2 jal fib
Write a recursive version of 𝑟add() in C or C++, then use this program to develop a MIPS
program that gets as input two integers 0<𝑎 ≤255, and 0<𝑏 ≤255, and returns the
result of 𝑟add(𝑎,𝑏) in $v1.

Mips recursion sum of digits

So I understand the logic behind how to calculate the sum of digits. I was just wondering whether this recursive function is correct. Assume that the user already entered the number which he or she wants the digit sum for and is stored in $v0.
Sum2:
li $s0, 0
move $a1, $v0
li $s1, 0
li $s2, 10
# I am adjusting the stack frame size to store 3 words
addi $sp, $sp,-12
# These are the sum value, the return address, and the number
sw $s1, 0($sp)
sw $ra, 4($sp)
sw $a1, 8($sp)
Loop2: bne $s0, $a1, SUM3
move $a0, $s1
li $v0, 1
syscall
lw $s1, 0($sp)
lw $ra, 4($sp)
lw $a1, 8($sp)
addi $sp, $sp 12
jr $ra
SUM3:
div $t0, $a1, $s2
mfhi $t0
add $s1, $s1, $t0
div $t1, $a1, $s2
mflo $a1
j Loop2
If the logic isn't clear I am first checking to see if the number doesn't equal zero and if it doesn't I will then get the modulus of the number divided by 10 and add it to the sum which is initially 0 and then divide the user input number by 10 and continue to call the function till the number eventually becomes zero. I also had one quick last question. In Mips would a recursive function or iterative function execute faster?
Your implementation corresponds to something like this:
int sum_digits(int n) {
int res = 0;
while (n != 0) {
res += n % 10;
n /= 10;
}
return res;
}
Actually you're just printing the result rather than returning it, but that's beside the point. It's clearly an iterative function.
A recursive implementation would look something like this:
int sum_digits(int n) {
return (n >= 10) ? ((n % 10) + sum_digits(n / 10)) : (n % 10);
}
I'll leave it to you to translate that into MIPS assembly now that you know what the algorithm looks like.
Proper implementation of recursion to do sum of digits:
.data
n: .word 1965
s: .word 0
.text
main:
lw $t0,n
addi $t1,$zero,10
add $t4,$zero,$zero #the result
recursion:
div $t0,$t1 #n/10 and n%10
mflo $t0 #n=n/10
mfhi $t3 #digit=n%10
add $t4,$t4,$t3 #s=s+digit
bne $t0,$zero,recursion #if n!=0
end:
sw $t4,s
li $v0,10
syscall

Resources