Recursive function using MIPS assembly - recursion

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.

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 Recursion function to reverse order of the linked list

I am trying to do recursion function to reverse a linkedlist in MIPS. The part createLinkedList does'nt belont to me. I am trying to add Display_Reverse_Order_Recursively function to this code. I don't understand how to pass the linked list address in $a0 and I can't use the Display_Reverse_Order_Recursively function properly. Plez help me
#
li $a0, 10 #create a linked list with 10 nodes
jal createLinkedList
# Linked list is pointed by $v0
move $a0, $v0 # Pass the linked list address in $a0
jal printLinkedList
move $a0 , $v0
jal Display_Reverse_Order_Recursively
# Stop.
li $v0, 10
syscall
createLinkedList:
# $a0: No. of nodes to be created ($a0 >= 1)
# $v0: returns list head
# Node 1 contains 4 in the data field, node i contains the value 4*i in the data field.
# By 4*i inserting a data value like this
# when we print linked list we can differentiate the node content from the node sequence no (1, 2, ...).
addi $sp, $sp, -24
sw $s0, 20($sp)
sw $s1, 16($sp)
sw $s2, 12($sp)
sw $s3, 8($sp)
sw $s4, 4($sp)
sw $ra, 0($sp) # Save $ra just in case we may want to call a subprogram
move $s0, $a0 # $s0: no. of nodes to be created.
li $s1, 1 # $s1: Node counter
# Create the first node: header.
# Each node is 8 bytes: link field then data field.
li $a0, 8
li $v0, 9
syscall
# OK now we have the list head. Save list head pointer
move $s2, $v0 # $s2 points to the first and last node of the linked list.
move $s3, $v0 # $s3 now points to the list head.
sll $s4, $s1, 2
# sll: So that node 1 data value will be 4, node i data value will be 4*i
sw $s4, 4($s2) # Store the data value.
addNode:
# Are we done?
# No. of nodes created compared with the number of nodes to be created.
beq $s1, $s0, allDone
addi $s1, $s1, 1 # Increment node counter.
li $a0, 8 # Remember: Node size is 8 bytes.
li $v0, 9
syscall
# Connect the this node to the lst node pointed by $s2.
sw $v0, 0($s2)
# Now make $s2 pointing to the newly created node.
move $s2, $v0 # $s2 now points to the new node.
sll $s4, $s1, 2
# sll: So that node 1 data value will be 4, node i data value will be 4*i
sw $s4, 4($s2) # Store the data value.
j addNode
allDone:
# Make sure that the link field of the last node cotains 0.
# The last node is pointed by $s2.
sw $zero, 0($s2)
move $v0, $s3 # Now $v0 points to the list head ($s3).
# Restore the register values
lw $ra, 0($sp)
lw $s4, 4($sp)
lw $s3, 8($sp)
lw $s2, 12($sp)
lw $s1, 16($sp)
lw $s0, 20($sp)
addi $sp, $sp, 24
jr $ra
#=========================================================
printLinkedList:
# Print linked list nodes in the following format
# --------------------------------------
# Node No: xxxx (dec)
# Address of Current Node: xxxx (hex)
# Address of Next Node: xxxx (hex)
# Data Value of Current Node: xxx (dec)
# --------------------------------------
# Save $s registers used
addi $sp, $sp, -20
sw $s0, 16($sp)
sw $s1, 12($sp)
sw $s2, 8($sp)
sw $s3, 4($sp)
sw $ra, 0($sp) # Save $ra just in case we may want to call a subprogram
# $a0: points to the linked list.
# $s0: Address of current
# s1: Address of next
# $2: Data of current
# $s3: Node counter: 1, 2, ...
move $s0, $a0 # $s0: points to the current node.
li $s3, 0
printNextNode:
beq $s0, $zero, printedAll
# $s0: Address of current node
lw $s1, 0($s0) # $s1: Address of next node
lw $s2, 4($s0) # $s2: Data of current node
addi $s3, $s3, 1
# $s0: address of current node: print in hex.
# $s1: address of next node: print in hex.
# $s2: data field value of current node: print in decimal.
la $a0, line
li $v0, 4
syscall # Print line seperator
la $a0, nodeNumberLabel
li $v0, 4
syscall
move $a0, $s3 # $s3: Node number (position) of current node
li $v0, 1
syscall
la $a0, addressOfCurrentNodeLabel
li $v0, 4
syscall
move $a0, $s0 # $s0: Address of current node
li $v0, 34
syscall
la $a0, addressOfNextNodeLabel
li $v0, 4
syscall
move $a0, $s1 # $s0: Address of next node
li $v0, 34
syscall
la $a0, dataValueOfCurrentNode
li $v0, 4
syscall
move $a0, $s2 # $s2: Data of current node
li $v0, 1
syscall
# Now consider next node.
move $s0, $s1 # Consider next node.
j printNextNode
printedAll:
# Restore the register values
lw $ra, 0($sp)
lw $s3, 4($sp)
lw $s2, 8($sp)
lw $s1, 12($sp)
lw $s0, 16($sp)
addi $sp, $sp, 20
jr $ra
Display_Reverse_Order_Recursively:
subi $sp, $sp, 8 #push (save) the list pointer and return adress parameter to the stack
sw $a0, 0($sp)
sw $ra, 4($sp)
bne $a0, $zero, recursiveCase #if list pointer is not null: recurse
#baseCase:
addi $sp, $sp, 8 #do nothing in the base case, filled the stack
jr $ra
recursiveCase:
lw $a0, 0($a0) #update to the successor
jal Display_Reverse_Order_Recursively #recurse
lw $a0, 0($sp)
lw $ra, 4($sp)
addi $sp, $sp, 8 #push (save) the list pointer and return adress parameter to the stack
lw $a0, 4($a0) #print the item on the top of the stack
li $v0, 1
syscall
la $a0, seperator #print a space
li $v0, 4
syscall
lw $a0, 0($sp)
jr $ra #return to the caller
#=========================================================
.data
line:
.asciiz "\n --------------------------------------"
nodeNumberLabel:
.asciiz "\n Node No.: "
addressOfCurrentNodeLabel:
.asciiz "\n Address of Current Node: "
addressOfNextNodeLabel:
.asciiz "\n Address of Next Node: "
dataValueOfCurrentNode:
.asciiz "\n Data Value of Current Node: "
seperator: .asciiz " " ````
printLinkedList is not a function, it does not return a value.
So, this code doesn't make sense:
jal printLinkedList
move $a0 , $v0 # <<--- nothing interesting in $v0 here
jal Display_Reverse_Order_Recursively
This code sequence at the end of Display_Reverse_Order_Recursively fails to undo the stack frame that it created upon entry.
lw $a0, 0($sp)
jr $ra #return to the caller
You have to retain the value stored in $v0 before calling printLinkedList, since this is what holds the address of the linked list, which needs to be passed to the other function. By convention $v0 is not assumed to have the same value after a function call, nor is $a0. And if you look through printLinkedListed you will see that a. neither register is stored on the stack but b. both registers' values change. So you cannot just move $v0 to $a0 again.
What you could do is move $s0, $v0 before calling printLinkedList, and then move $a0, $s0 afterwards, since $s0 is a saved register. Or you could push $v0 onto the stack before making that call, then pop it off afterword.

MIPS where to put recursive calls in a palindrome problem

I am writing a program that accepts a user given strings and will output 1 if it is a palindrome or 0 if it isn't. It has to use recursion, however I am having trouble figuring out how to format the jal and jr statements so that recursion works properly.
main:
la $a0, askForString #simple text asking for user input
li $v0, 4
syscall
li $v0, 8
la $a0, userInput #points a0 to space allocated to get user input
li $a1, 41 #allows the user to enter input up to 40 characters
syscall
la $a0, userInput
li $v0, 4
syscall
lw $s0, userInput
j palindrome
palindrome:
la $a1, userInput
addu $a1,$a1,$s1
lbu $a0,($a1) # read the character in $s1 spot of the user inputted word
addi $sp, $sp, -4
sw $a0, 0($sp) #add the specific character to the stack so it can be looked at later
addi $s1, $s1, 1 #advance the count to look at the next character
jal palindrome
lw $t0, 0($sp) #load the last letter of the user given word from the stack
addi $sp, $sp, 4
la $a1, userInput
addu $a1,$a1,$s2
lbu $a0,($a1) # read the character in $s2 spot of the user inputted word
addi $s2, $s2, 1 #advance the count to look at the next character
bne $a0, $t0, fail #if the letters are not equal, print 0, not a palindrome
jr $ra
success:
la $a0, '1'
li $v0, 11
syscall
j end
fail:
la $a0, '0'
li $v0, 11
syscall
j end
end:
li $v0, 10 #op code to exit the program
syscall
I know the palindrome part of the program almost definitely does not work and has no way of knowing where the end of the word is, but if anyone could me with simply the recursion part that would be extremely helpful.

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```

Resources