MIPS where to put recursive calls in a palindrome problem - recursion

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.

Related

Sum calculator in MIPS

I am fairly new to MIPS and am trying to write a code which calculates the sum of an integer which was entered by the user. I am using recursion in my code but am not sure if theres an easier way to do this. My code runs fairly well for the most part however it keeps adding 1 to the final sum. For example, sum of 10 is 55 but it gives me 56.
.data
#messages
sumMessage: .asciiz "\Enter a number to find its Sum: "
sumMessage1: .asciiz "\nSum is: "
sumInput: .word 0
sumAns: .word 0
.text
.globl main
main:
#read promtMessage
li $v0, 4
la $a0, sumMessage
syscall
#take input
li $v0,5
syscall
sw $v0, sumInput#storing input
#call sumCalc function
lw $a0, sumInput
jal sumCalc
sw $v0, sumAns#returns value from function
#display sum
li $v0, 4
la $a0, sumMessage1
syscall
li $v0, 1
lw $a0, sumAns
syscall
#end main
li $v0, 10
syscall
#sumCalc Function
.globl sumCalc
sumCalc:
subu $sp, $sp, 8
sw $ra, ($sp)#storing value of returning address in the stack
sw $s0, 4($sp)#4 bites apart from the value stored above in the stack
#base case
li $v0, 1
beq $a0, 0, exit
#find factorial n-1
move $s0, $a0
sub $a0, $a0, 1
jal sumCalc
add $v0, $s0, $v0
exit:
lw $ra, ($sp)
lw $s0,, 4($sp)
addu $sp, $sp, 8
jr $ra
Any help would be appreciated!
Using recursion here makes the processing cumbersome and of little interest because we can calculate the sum directly. The sum of an integer is given to us using the following mathematical formula: n * (n + 1) / 2 or else n * (n + 1) then a right shift which is comparable to a division by 2.
.data
#messages
sumMessage: .asciiz "\Enter a number to find its Sum: "
sumMessage1: .asciiz "\nSum is: "
sumInput: .word 0
sumAns: .word 0
.text
.globl main
main:
#read promtMessage
li $v0, 4
la $a0, sumMessage
syscall
#take input
li $v0,5
syscall
sw $v0, sumInput#storing input
#call sumCalc function
lw $a0, sumInput
jal sumCalc
sw $s2, sumAns#returns value from function
#display sum
li $v0, 4
la $a0, sumMessage1
syscall
li $v0, 1
lw $a0, sumAns
syscall
#end main
li $v0, 10
syscall
#sumCalc Function
.globl sumCalc
sumCalc:
subu $sp, $sp, 8
sw $ra, ($sp)#storing value of returning address in the stack
sw $s0, 4($sp)#4 bites apart from the value stored above in the stack
li $s2,1 # storing the final result
move $s3,$v0
addi $s3,$s3,1 # $s3 = $v0+1
mul $s2,$v0,$s3 # $s2 = $v0 * ($v0 +1)
div $s2,$s2,2 # $s2 = $s2/2
exit:
lw $ra, ($sp)
lw $s0,4($sp)
addu $sp, $sp, 8
jr $ra

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.

Hexadecimal to decimal in MIPS. I'm getting really strange and negative output from $s3 could really use some help for I am all out of ideas

Been trying to write this hex to decimal converter in MIPS. Should take in up to 8 arguments (string) from command line, all hex starting with "0x", 4 bytes long and terminated with null character after every argument.
$s1= number of args; $s0-->args(0).
For these Program Arguments: 0x1A 0xF1 0x0B3:
.data
buffer: .space 32
args: .asciiz "\nProgram arguments:\n"
space: .asciiz " "
d_rep: .asciiz "\n\nInteger values:\n"
newLine: .asciiz "\n"
maxVal: .asciiz "Maximum value:\n"
.text
main:
add $t9, $zero, $zero # t9 will be max value
add $s1, $a0, $0 # store number of program arguments
add $s2, $a1, $0 # store address of where program arguments are
addi $s0, $0, 0 # use s0 as index for looping
addi $s7, $zero, 0 # used as index for print loop
add $s6, $s1, $0 # store numArgs for printloop
add $s5, $s2, $0 # store address for printloop
addi $t5, $zero, 16
addi $t6, $zero, 0
la $a0, args # load and print "Program arguments" string
li $v0, 4 # print
syscall
printloop:
beq $s7, $s6, printInt # only print as many times as there are args
lw $a0, 0($s5) # get the first word
li $v0, 4 # print
syscall
la $a0, space # print a space between words
li $v0, 4 # print
syscall
addi $s5, $s5, 4 # increment to next word
addi $s7, $s7, 1 # increment printloop counter
j printloop # loop again if there are more args
printInt:
la $a0, d_rep # print "Decimal values:"
li $v0, 4 # print
syscall
while:
beq $s0, $s1, done # while $s0 <= numArgs
lb $t1, 2($s2) # load s2[2] into
addu $t2, $zero, $t1 # make a copy so we dont lose place
subiu $sp, $sp, 4
convert:
beqz $t2, postConv # while t2 != null
blt $t2, 65, convNumber # if less than value of A then got a num
subiu $t3, $t2, 0x37 # -55 for uppercase letter
sll $t3, $t3, 4 # sll by 4 is same as mult by 16
sw $t3, ($sp) # store word to do some addition
addiu $t2, $t2, 1 # increment t2
subiu $sp, $sp, 4 # increment sp
j convert # go back to convert
convNumber:
addu $t3, $zero, $t2 # put t2 into t3 for to do some math
subiu $t3, $t3, 0x30 # -48 for number
sll $t3, $t3, 4 # sll by 4 is same as mult by 16
sw $t3, ($sp)
addiu $t2, $t2, 1 # increment t1
addiu $sp, $sp, 4 # increment sp
j convert # jump back to convert
postConv:
addi $sp, $sp, 4 # load the second value
lw $s4, ($sp) # load the first value
addi $sp, $sp, 4
# sll $s4, $s4, 4
lw $s3 ($sp)
addu $s3, $s3, $s4 # add em up for converted decimal
move $a0, $s3 # move to a0 so they pint
li $v0, 1 # print
syscall
addiu $s0, $s0, 1 # increment loop counter
addiu $s2, $s2, 4 # increment to next word
ble $t9, $t6, newMax # check for a new max value
j while # jump back to loop
newMax:
addu $t9, $zero, $t6 # got a new max so save it
j while
done:
la, $a0, newLine
li $v0, 4
syscall
la, $a0, newLine
li $v0, 4
syscall
la, $a0, maxVal
li $v0, 4
syscall
move $a0, $t9
li $v0, 1
syscall
la, $a0, newLine
li $v0, 4
syscall
li $v0, 10 # end program
syscall
My output is this:
Program arguments:
0x1A 0xF1 0x0B3
Integer values:
-2121474836290
Maximum value:
0
-- program is finished running --
But it should be : 26 241 179. And maxValue should be: 241
I would be very grateful if someone could help me debug this. Thank you! :D
You should be able to debug this yourself.  Single stepping the code to find this error is trivial.  If you don't know how to debug code, then suggest you focus on learning that.  Check each instruction to make sure it is doing what you expect, and if not, that's where the problem is.
argv is a pointer to pointers to characters — if we consider that a pointer to characters is a string, then we can describe argv as a pointer to strings.  To get single character from argv we have to choose which of the strings, then choose a character from that string.
You are doing this correctly when printing the program arguments, but are not following that approach for accessing their bytes, instead you're accessing individual bytes from the pointers themselves, which of course makes no sense.  Put another way, you're missing an indirection aka dereference.
This kind of error should stand out to you like a flashing warning sign when you single step over the lb $t1, 2($s2) instruction — because you are expecting it to fetch the ascii 1, 0x31, but are getting an 0xff instead.  When you see that an instruction is not getting what you expect that's where and when to rethink things: it is doing what you told it to do but you can observe that is not what you want.

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

Why do i get an error in my MIPS code to convert Hexa to Binary?

Hello can someone please help fix my code or see where the error is to fix it? I'm trying to convert a hexadecimal number to binary in MIPS but I keep getting an error when I try running it and have no idea where the error is or how to fix it.
My code:
.data
buffer: .space 8
prompt: .asciiz "\nInput a hexadecimal number: "
asnwer: .asciiz "\nBinary number is: "
.text
main:
la $a0, prompt
li $v0, 4
syscall
li $v0, 8
la $a0, buffer
li $a1, 2
move $t0, $a0
syscall
hextodec:
slti $t0, $a0, 0x41
beq $t0, $zero, letter
addi $v0, $a0, -0x30
j end
letter:
addi $t0, $a0, -0x41
addi $v0, $t0, 10
end:
jr $a0
it says error occurred at PC = 0x10010004
You're doing jr $a0, not the usual jr $ra to return to the return-address in the link register.
The register-indirect jump sets PC = $a0, but $a0 is still pointing to buffer, from the la $a0, buffer.

Resources