MIPS Palindrome that does not care about punctuation - recursion

.data
input:.space 80 #buffer space for input
built:.space 80 #buffer space for built string from looping
#string values to call when printing
message: .asciiz "Please enter a string:"
newline: .asciiz "\n"
ispaly: .asciiz "\n This is a palindrome"
notpaly: .asciiz "\n This is not a palindrome"
.text
main:
la $a0, message # user input message
li $v0, 4 #mips to print string
syscall #call return values
la $a0, input #users input
li $a1, 80 #allocating space for the buffer of size 80
li $v0, 8 #reading the buffer
syscall #call return values
secondinput:
la $t1,built #creating a new buffer string while going through the loop
loop:
lb $t5,($a0) #loading the byte into the buffer
beq $t5, 10, check # if it has a new line
bgt $t5, 47, digittest #and has value greater then ascii 47
jal dontbuild #if it is not then we increment to next character
digittest:
blt $t5, 58, dobuild #proceeding from above, if it is less then ascii 58(digits)
bgt $t5, 64, capital #and greater then ascii 64 we dont build it into our new buffer(built)
jal dontbuild #jump to dontbuild function
capital:
blt $t5, 91, dobuild #buffer being (built) is less than ascii 91 its a capital letter
bgt $t5, 96, punctuation #if its greater then 96 its is a lowercase
j dontbuild #jump to dontbuild
dobuild:
bgt $t5, 96, makelow #built value byte is already lowercase
j lower #go to lower function
punctuation:
blt $t5,123, dobuild #buffer being built has a value less then 123 and passed previous functions it is a capital and we make it lower
j dontbuild #otherwise we dont add to buffer(built)
makelow:
addi $t5,$t5, -32 #if value is lower subtract 32 to make it capital
j lower #jump to lower function and increment
lower:
sb $t5,($t1) #store the byte so it does not get modified
addi $a0,$a0, 1 #increment for comparison
addi $t1,$t1,1 #increment for comparison
j loop #go back up to loop
dontbuild:
addi $a0,$a0,1 #increment to next character
j loop #jump to loop
check:
la $t4, built #buffer that was built
sb, $zero,($a0) #store the byte in argument
addi $t1,$t1,-1 #decrement from the end of our $t1 register
loop2:
lb $t3,($t4) #load byte into temporary register
lb $t2,($t1) #load byte into temporary register
beq $t3,$t2,next #check if each byte is equal
j notp #if they are not go to not a palindrome
next:
jal test #if they are equal
addi $t4,$t4,1 #increment through the string
addi $t1,$t1,-1 #decrement through the string
j loop2 #go through the loop
j notp #if it runs into a non equal value its not a palindrome
test:
beq $t4,$t1,isp #if all values are equal it calls palindrome
addi $t1,$t1,-1
beq $t4,$t1,isp #do we need to check any other values
addi $t1,$t1,1
jr $ra #return to os
isp:
la $a0, input # the users input
li $v0, 4
syscall #call return values
li $v0, 4 #print a new line
la $a0, newline
syscall
la $a0,built
li $v0, 4
syscall
la $a0,ispaly #string that it is a palindrome
syscall #call return values
j exit #end
notp:
la $a0, input #users input
li $v0, 4
syscall #call return values
li $v0, 4 #print a new line
la $a0, newline
syscall
la $a0,built
li $v0, 4
syscall
la $a0, notpaly #string that it is not a palindrome
syscall #call return values
j exit
exit:
li $v0, 10 #end program
syscall #call return values
This code compiles but I am having some errors with my output.
At the line addi $t5,$t5, -32 to make an uppercase value lowercase. It makes everything uppercase.
Here is a test output.
Please enter a string:A man, a plan, a canal --Panama!
A man, a plan, a canal --Panama!
AMANAPLANACANALPANAMA
This is a palindrome
The output that I need is
amanaplanacanalpanama
In ascii characters you have to add 32 to go from uppercase to lowercase
for example A=65 so 65+32= 97 which = a.
When i try to do the opposite in my code
subi $t5,$t5, 32
I get the same output with uppercase values
If i change it to
addi $t5,$t5, 32
The output is
Please enter a string:A man, a plan, a canal --Panama!
A man, a plan, a canal --Panama!
A■■■■■■■■■■■■■■■■P■■■■■
This is not a palindrome
Basically every lowercase value is a square.
And the last issue is that my test loop is not seen as recursion. Is this true?

In ascii characters you have to add 32 to go from uppercase to
lowercase for example A=65 so 65+32= 97 which = a.
You're substracting 32 in both cases, not adding. addi $t5,$t5, -32 (adding -32) is the same as subi $t5,$t5, 32 (substracting 32).
Basically every lowercase value is a square.
Because you're adding 32 to lowercased characters and you end up with non-printable characters, which are shown as squares.
And the last issue is that my test loop is not seen as recursion. Is
this true?
I don't see where test is looped. Anyways, you have no recursion in your code, only loops. Recursion is when a function calls itself and you have no functions in your code.

Related

Calculate score as a percentage in MIPS using division

I am making a little math quiz program that asks the player basic math questions and keeps a tally of their total score. At the end I want to calculate and display their total score as a percent. Meaning what percent of total questions asked, were answered correctly. However, I have wracked my brain trying to figure out how to get that percentage to display correctly. The math to calculate the percent is all being done in the exit function but I am attaching the entire program for context. Its heavily noted. Please advise on what I could do to make that final result correct.
Also, as an aside, is there a better way to do the division question? Currently the only way i can do it to have the answer be the quotient with no remainder... this is obviously a crappy solution.
.data
startMsg: .asciiz "Hello, welcome to MathQuiz, here is your first problem:\nEnter -100 to exit\n"
qf1: .asciiz "What is "
qf2: .asciiz "? "
a1: .asciiz "Correct!\n"
a2: .asciiz "Incorrect!\n"
emf1: .asciiz "You solved "
emf2: .asciiz " math problems and got "
emf3: .asciiz " correct and "
emf4: .asciiz " incorrect, for a score of "
emf5: .asciiz "%.\nThanks for playing!"
operator1: .asciiz " + "
operator2: .asciiz " - "
operator3: .asciiz " * "
operator4: .asciiz " % "
totalCount: .word -1
correctCount: .word 0
incorrectCount: .word 0
scoreCalc: .word 0
correctAnswer: .word 0
wrongAnswer: .word 0
derp: .word 0
.text
.globl main
main:
li $v0, 4 # greet the user
la $a0, startMsg
syscall
calc:
# the primary function that handles most of the calculations.
li $s5, -100 #use register s5 as the exit program value.
# operator reference table
li $t2, 0
li $t3, 1
li $t4, 2
li $t5, 3
li $a1, 21 # set range for random number to 0-20
li $v0, 42 # generate random number, saved in $a0
syscall
move $s1, $a0 # Move random number to register s1
li $a1, 21 # set range for random number to 0-20
li $v0, 42 # generate random number, saved in $a0
syscall
move $s2, $a0 # Move random number to register s2
li $a1, 4 # set range for random number to 0-3
li $v0, 42 # generate random number, saved in $a0
syscall
move $t1, $a0 # Move random number to register s2
# operator table
beq $t1, $t2, addition
beq $t1, $t3, subtraction
beq $t1, $t4, multiplication
beq $t1, $t5, division
addition:
li $v0,4 # output an ascii string
la $a0, qf1 # load the ascii string qf1 for output to screen
syscall
li $v0,1 # output an int
move $a0, $s1
syscall
li $v0,4 # output an ascii string
la $a0, operator1 # load the ascii string qf1 for output to screen
syscall
li $v0,1 # output an int
move $a0, $s2
syscall
li $v0,4 # output an ascii string.
la $a0, qf2 # load the ascii string qf2 for output to screen.
syscall
li $v0, 5 # read an integer from the command line, result saved in $v0.
syscall
move $s4, $v0 # move the user input to a register for comparison.
add $s3, $s1, $s2 # perform the addition of the 2 random numbers.
lw $t1, totalCount # load the current value of totalCount into a register.
add $t2, $t1, 1 # add 1 to the value in the register for totalCount.
sw $t2, totalCount # save the iterated value of totalCount back to the memory space of the variable.
beq $s4, $s5, exit # if the user input matches -1, jump to "exit" function.
beq $s4, $s3, correct # if user input matches the correct answer, jump to the "correct" function.
j incorrect # if the answer is wrong AND not "-1", jump to the "incorrect" function.
subtraction:
li $v0,4 # output an ascii string
la $a0, qf1 # load the ascii string qf1 for output to screen
syscall
li $v0,1 # output an int
move $a0, $s1
syscall
li $v0,4 # output an ascii string
la $a0, operator2 # load the ascii string qf1 for output to screen
syscall
li $v0,1 # output an int
move $a0, $s2
syscall
li $v0,4 # output an ascii string.
la $a0, qf2 # load the ascii string qf2 for output to screen.
syscall
li $v0, 5 # read an integer from the command line, result saved in $v0.
syscall
move $s4, $v0 # move the user input to a register for comparison.
sub $s3, $s1, $s2 # perform the subtraction of the 2 random numbers.
lw $t1, totalCount # load the current value of totalCount into a register.
add $t2, $t1, 1 # add 1 to the value in the register for totalCount.
sw $t2, totalCount # save the iterated value of totalCount back to the memory space of the variable.
beq $s4, $s5, exit # if the user input matches -1, jump to "exit" function.
beq $s4, $s3, correct # if user input matches the correct answer, jump to the "correct" function.
j incorrect # if the answer is wrong AND not "-1", jump to the "incorrect" function.
multiplication:
li $v0,4 # output an ascii string
la $a0, qf1 # load the ascii string qf1 for output to screen
syscall
li $v0,1 # output an int
move $a0, $s1
syscall
li $v0,4 # output an ascii string
la $a0, operator3 # load the ascii string qf1 for output to screen
syscall
li $v0,1 # output an int
move $a0, $s2
syscall
li $v0,4 # output an ascii string.
la $a0, qf2 # load the ascii string qf2 for output to screen.
syscall
li $v0, 5 # read an integer from the command line, result saved in $v0.
syscall
move $s4, $v0 # move the user input to a register for comparison.
mul $s3, $s1, $s2 # perform the addition of the 2 random numbers.
lw $t1, totalCount # load the current value of totalCount into a register.
add $t2, $t1, 1 # add 1 to the value in the register for totalCount.
sw $t2, totalCount # save the iterated value of totalCount back to the memory space of the variable.
beq $s4, $s5, exit # if the user input matches -1, jump to "exit" function.
beq $s4, $s3, correct # if user input matches the correct answer, jump to the "correct" function.
j incorrect # if the answer is wrong AND not "-1", jump to the "incorrect" function.
division:
li $v0,4 # output an ascii string
la $a0, qf1 # load the ascii string qf1 for output to screen
syscall
li $v0,1 # output an int
move $a0, $s1
syscall
li $v0,4 # output an ascii string
la $a0, operator4 # load the ascii string qf1 for output to screen
syscall
li $v0,1 # output an int
move $a0, $s2
syscall
li $v0,4 # output an ascii string.
la $a0, qf2 # load the ascii string qf2 for output to screen.
syscall
li $v0, 5 # read an integer from the command line, result saved in $v0.
syscall
move $s4, $v0 # move the user input to a register for comparison.
div $s1, $s2 # perform the addition of the 2 random numbers.
mflo $s3
lw $t1, totalCount # load the current value of totalCount into a register.
add $t2, $t1, 1 # add 1 to the value in the register for totalCount.
sw $t2, totalCount # save the iterated value of totalCount back to the memory space of the variable.
beq $s4, $s5, exit # if the user input matches -1, jump to "exit" function.
beq $s4, $s3, correct # if user input matches the correct answer, jump to the "correct" function.
j incorrect # if the answer is wrong AND not "-1", jump to the "incorrect" function.
correct:
# produce the incorrect answer response and adjust counter.
li $v0,4 # output an ascii string.
la $a0, a1 # load the ascii string qf1 for output to screen.
syscall
lw $t1, correctCount # load the value of the correctCount variable into a register.
add $t2, $t1, 1 # add 1 to the value for correctCount in the register.
sw $t2, correctCount # save the iterated value of correctCount back into the memory space of the variable.
j calc # jump back to the calc function to ask another question.
incorrect:
# produce the incorrect answer response and adjust counter.
li $v0,4 # output an ascii string.
la $a0, a2 # load the ascii string qf1 for output to screen.
syscall
lw $t1, incorrectCount # load the value of the incorrectCount variable into a register.
add $t2, $t1, 1 # add 1 to the value for incorrectCount in the register.
sw $t2, incorrectCount # save the iterated value of incorrectCount back into the memory space of the variable.
j calc # jump back to the calc function to ask another question.
exit:
# perform the calculations needed to produce the final output to the user.
lw $t1, totalCount # load the totalCount value into a register
lw $t2, correctCount # load the correctCount value into the register
li $t5, 100 # set a register to 100 for use in the percentage conversion process.
div $t2, $t1 # calculate the players total correct score percentage using division.
mflo $t3 # move the lo register value to $t3 for further calculations.
mul $t6, $t3, $t5 # multiply the score value by 100 to convert to a whole number for output.
# Assemble the output
li $v0, 4 # output an ascii string
la $a0, emf1 # load end message fragment 1 into the registr for output.
syscall
lw $a0, totalCount # load the value of totalCount to register a0 for output.
li, $v0, 1 # output an int
syscall
li $v0, 4 # output an ascii string
la $a0, emf2 # load end message fragment 2 into the registr for output.
syscall
lw $a0, correctCount # load the value of correctCount to register a0 for output.
li, $v0, 1 # output an int
syscall
li $v0, 4 # output an ascii string
la $a0, emf3 # load end message fragment 3 into the registr for output.
syscall
lw $a0, incorrectCount # load the value of incorrectCount to register a0 for output.
li, $v0, 1 # output an int
syscall
li $v0, 4 # output an ascii string
la $a0, emf4 # load end message fragment 4 into the registr for output.
syscall
move $a0, $t6
li, $v0, 1 # output an int
syscall
li $v0, 4 # output an ascii string
la $a0, emf5 # load end message fragment 5 into the registr for output.
syscall
li $v0, 10 #exits the program on syscall
syscall
When you do the integer division, you always get 0. Subsequently multiplying by 100 cannot recover the lost fraction. The easiest solution is to multiply by 100 first and then divide.
To round to the nearest whole percent, multiply the number correct by 100, add half of the number of questions, then divide by the number of questions. For example, if there are 12 questions and 8 are correct, (8 x 100 + 6) / 12 = 67%.
If you want a fraction of a percent, such as 66.7%, then it can be done using only integer operations, but it is probably simpler to use floating point.

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.

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.

the answer is always wrong in this MIPS recursion . got 10, supposed to be 55

This code is supposed to print the sum of numbers from 10 to 0. It should be printing 55, but is printing 10 instead. Can you help me figure out where it's going wrong?
main:
# initialize values to 3 registers
addi $a0,$zero,10
jal sum # call method
# Print out the summation upto 10
li $v0,1 # print integer
add $a1,$v0,$zero # load return value into argument
syscall
li $v0,10 # Exit
syscall
sum:
addi $sp,$sp,-8 # allocate space on stack
sw $ra,0($sp) # store the return address
sw $a0,4($sp) # store the argument
slti $t0,$a0,1 # check if n > 0
beq $t0,$0,recurse # n > 0 case
add $v0,$0,$0 # start return value to 0
addi $sp,$sp,8 # pop 2 items off stack
jr $ra # return to caller
recurse:
addi $a0,$a0,-1 # calculate n-1
jal sum # recursively call sum(n-1)
lw $ra,0($sp) # restore saved return address
lw $a0,4($sp) # restore saved argument
addi $sp,$sp,8 # pop 2 items off stack
add $v0,$a0,$v0 # calculate n + sum(n-1)
jr $ra # return to caller
Functions return their value in $v0; the print integer syscall expects its argument in $a0.
You need to move $a0 to $v0 before you do the print, otherwise you'll be printing whatever happened to be in $a0 (which in the case is the last value that you recursively added; i.e. 10).

GCD of two numbers in MIPS- recursive

I am trying to find the GCD of two numbers with recursion.
This code is what I've done so far but apparently it gets into an infinite loop and i can't understand why and how to solve this problem.
I would appreciate some help
.data
string1: .asciiz "Enter the first number: "
string2: .asciiz "Enter the second number: "
string3: .asciiz "GCD is : "
.text
li $v0,4
la $a0,string1
syscall
li $v0, 5
syscall
add $s0,$v0,$zero #s0 = first number
li $v0,4
la $a0,string2
syscall
li $v0, 5
syscall
add $s1,$v0,$zero #s1= second number
slt $t0,$s0,$s1
beq $t0,$zero,L # if first number < second number , swap
add $t1,$s0,$zero
add $s0,$s1,$zero
add $s1,$t1,$zero
L:
add $a0,$s0,$zero # put first number in $a0 as input argument
add $a1,$s1,$zero # put second number in $a1 as input argument
jal GCD
GCD:
addi $sp,$sp,-4
sw $ra,0($sp)
bne $a1,$zero,L1 # base case condition
add $v0,$zero,$a0 # if base case is true
addi $sp,$sp,4
jr $ra
L1:
div $a0,$a1
add $a0,$a1,$zero
mfhi $a1
jal GCD
lw $ra,0($sp)
addi $sp,$sp,4
jr $ra
add $s3,$v0,$zero # put result in $s3
li $v0,4
la $a0,string3
syscall
li $v0,1
add $a0,$s3,$zero
syscall
So your program starts execution at the beginning of the .text segment and continues straight onto the line jal GCD after the L label.
Next your program jumps to the GCD label where it executes until the jr $ra which makes it return to the jal which has as its next instruction of course GCD. This causes the infinite loop.
So the problem here is that you have inserted the GCD function in the middle of your main function. Generally speaking it is always an error to jal to the next line.
So you should move the definition of GCD elsewhere and consider what it is that you would like to run after returning from this function.

Resources