A MIPS palindrome - mips

The current code that I have looks as such. It can successfully read if a string is a palindrome when punctuation is not entered.
.data
buffer: .space 80
input: .asciiz "Enter a string: "
output: .asciiz "Your string: "
paly: .asciiz "This is a palindrome "
notp: .asciiz "This is not a palindrome"
.text
main:
li $v0, 4 # system call code for print_str
la $a0, input # address of string to print
syscall # print the input
li $v0, 8 # code for syscall read_string
la $a0, buffer # tell syscall where the buffer is
li $a1, 80 # tell syscall how big the buffer is
syscall
la $a0, buffer # move buffer into a0
li $v0, 4 # print buffer
syscall
la $t1, buffer # begining of the string
la $t2, buffer # end of the string
li $t0, 0
loop:
lb $t3,($t2) # load the byte of the end of the string
beqz $t3,endl # if its equal to 0 then branch out of the loop
addu $t2, $t2,1 # if in loop the increment to next character
jal loop # repeat the loop
upper:
addi $t4,$t4,32
j lowered
lowered:
addi $t0,$t0,1
sb $t4, 0($a0)
addi $a0,$a0,1
j loop
endl:
subu $t2, $t2, 2 # subtracting 2 to move back from \0 and \n
check:
#lb $t4, 0($a0)
#beqz $t4, after
#beq $t4, 10, after
#slti $t2, $t4, 91
#li $t3, 1
#beq $t2, $t3, upper
bge $t1, $t2, palindrome # if both sides are equal then its a palindrome
# call palindrome
lb $t3, ($t1) # load the byte into register t3
lb $t4, ($t2) # load the end byte into register t4
bne $t3, $t4, notpaly # if the two register bytes are not equal its it not a palindrome
addu $t1, $t1, 1 # increment the beginning of the string to next char
subu $t2, $t2, 1 # decrement end of string to next char to compare
jal check # repeat the loop
palindrome:
la $a0, paly # calling paly from data
li $v0, 4 # call for reading string
syscall
jal exit # jump to end
notpaly:
la $a0,notp # calling notp from data
li $v0, 4 # call for reading string
syscall
jal exit # jump to end
after:
li $v0, 4
la $a0, output
syscall
la $a0, buffer
li $v0, 4
syscall
exit:
li $v0 ,10 # call to end program
syscall # call os
Now I know I need to implement code such as to make uppercase lowercase, and to remove punctuation.
With my already stored bits in check: I have some commented code, and this would be to to test if a character is uppercase, then jump to the function and lower it by adding 32. But it does not compile correctly and i am assuming this is because I am not storing the bits correctly.
#lb $t4, 0($a0)
#beqz $t4, after
#beq $t4, 10, after
#slti $t2, $t4, 91
#li $t3, 1
#beq $t2, $t3, upper

Related

Printing an hourglass in mips32

I'm having problems solving this question. I want to print an hourglass using mips32. n is an integer given by user as input and the hourglass must be printed in n lines. For example, for n = 5 the output is:
*****
***
*
***
*****
Here is my code for the first part (the triangle top of the hourglass). The problem is that it prints only the first line of stars and then exits. By running my code line by line in Mars, I understood that the first line of the backToLoop1 label is run every time loop3 is run! So it causes the program to end after the first line. I really can't realize why this happens.
.data
newLine: .asciiz "\n"
.text
main:
li $v0, 5 # read n
syscall # call sysetem
addi $t2, $v0, 0 # moves n to $t2
li $t0, 1 # i= 1
loop1:
blt $t2, $t0, Exit # if n<i exit
la $a0, newLine # go to next line
addi $v0, $0, 4 # 4 represents printing string
syscall # call system
# loop2 bounds
li $t1, 1 # k= 1
subi $t3, $t0, 1 # $t3= i-1 upper bound for loop2
# loop3 bounds
li $t5, 1 # j= 1
addi $t6, $t2, 1 # t6= n+1
sub $t6, $t6, $t0 # $t6= n+1-i upper bound for loop3
loop2:
blt $t3, $t1, loop3
li $a0, ' ' # load space to $a0
la $v0, 11 # 11 represents printing character
syscall # call system
addi $t1, $t1, 1 # k++
ble $t1, $t3, loop2 # if <= i-1 loop2 again
loop3:
blt $t6, $t5, backToLoop1 # back to loop1
li $a0, '*' # load star to $a0
la $v0, 11 # 4 represents printing character
syscall # call system
addi $t5, $t5, 1 # j++
ble $t5, $t6, loop3 # if j <= n-i+1 loop3 again
backToLoop1:
addi $t0, $t0, 1 # i++
ble $t0, $t2, loop1 # if i<=n loop1 again
blt $t2, $t0, Exit
Exit: # Terminate the program
li $v0, 10 # 10 represents exit
syscall # call system
You're off to a good start. However, there doesn't appear to be a clear strategy for slanting the right side of the hourglass. Ideally we can write logic to handle drawing the bottom half without duplicating most of the logic.
My default approach for this sort of pattern is to use two pointers, a left starting at 0 and right starting at n - 1. These represent the index bounds for the asterisk characters for each row. Per row iteration, decrement the right pointer and increment the left pointer, essentially drawing an "X" pattern on the n by n grid.
This strategy gets us 95% of the way there. The last step is to temporarily swap the left and right pointers if left > right, which handles drawing the bottom half without too much spaghetti.
.data
prompt: .asciiz "enter a number: "
.text
main:
la $a0 prompt # collect n
li $v0 4
syscall
li $v0 5
syscall
move $s3 $v0 # n
li $s0 0 # left index
move $s1 $s3 # right index = n - 1
addi $s1 $s1 -1
row_loop:
bltz $s1 exit # while right-- >= 0
li $s2 0 # column index
col_loop:
beq $s2 $s3 row_loop_done # for 0..n
# if left > right, swap temporarily
move $t0 $s0
move $t1 $s1
blt $t0 $t1 pick_char
move $t2 $t0
move $t0 $t1
move $t1 $t2
pick_char:
# '*' if left <= i <= right else ' '
blt $s2 $t0 pick_space
bgt $s2 $t1 pick_space
li $a0 42 # print '*'
j print_char
pick_space:
li $a0 32 # print ' '
print_char:
li $v0 11
syscall
addi $s2 $s2 1 # column index++
j col_loop
row_loop_done:
li $a0 10 # print newline
li $v0 11
syscall
addi $s1 $s1 -1 # right--
addi $s0 $s0 1 # left++
j row_loop
exit:
li $v0 10
syscall

How do you properly read an integer input in MIPS?

The following program 1. Prints out the array 2. Given a lower and upper bound input by user, determines the min and min index within that range
It runs the print array function.
However, I tried tracing the registers in QTSPIM, it does not correctly assign the lower bound and upper bound to $a0 and $a1 respectively. In fact, $v0 does not seem to even scan anything. To move the scanned input from $v0 to $t0, tried using "move $t0, $v0" instead. The problem still occurs.
# Ask the user for two indices
li $v0, 5 # System call code for read_int
syscall
add $t0, $v0, $zero # store input in $t0
sll $t0, $t0, 2 # relative address position (lower bound)
add $a0, $t9, $t0 # array pointer (lower bound)
li $v0, 5 # System call code for read_int
syscall
add $t0, $v0, $zero # store input in $t0
sll $t0, $t0, 2 # relative address position (upper bound)
add $a1, $t9, $t0 # array pointer (upper bound)
The full code is below. Can anyone enlighten me if there's anything wrong?
# arrayFunction.asm
.data
array: .word 8, 2, 1, 6, 9, 7, 3, 5, 0, 4
newl: .asciiz "\n"
.text
main:
# Print the original content of array
# setup the parameter(s)
la $a0, array # base address of array
add $t9, $a0, $zero # store base address
la $a1, 10 # number of elements in array
# call the printArray function
jal printArray # call function
# Ask the user for two indices
li $v0, 5 # System call code for read_int
syscall
add $t0, $v0, $zero # store input in $t0
sll $t0, $t0, 2 # relative address position (lower bound)
add $a0, $t9, $t0 # array pointer (lower bound)
li $v0, 5 # System call code for read_int
syscall
add $t0, $v0, $zero # store input in $t0
sll $t0, $t0, 2 # relative address position (upper bound)
add $a1, $t9, $t0 # array pointer (upper bound)
# Call the findMin function
# setup the parameter(s)
# call the function
jal findMin # call function
# Print the min item
# place the min item in $t3 for printing
addi $t3, $t1, 0
# Print an integer followed by a newline
li $v0, 1 # system call code for print_int
addi $a0, $t3, 0 # print $t3
syscall # make system call
li $v0, 4 # system call code for print_string
la $a0, newl
syscall # print newline
#Calculate and print the index of min item
la $a0, array
add $t3, $v0, $a0
srl $t3, $t3, 2
# Place the min index in $t3 for printing
# Print the min index
# Print an integer followed by a newline
li $v0, 1 # system call code for print_int
addi $a0, $t3, 0 # print $t3
syscall # make system call
li $v0, 4 # system call code for print_string
la $a0, newl #
syscall # print newline
# End of main, make a syscall to "exit"
li $v0, 10 # system call code for exit
syscall # terminate program
#######################################################################
### Function printArray ###
#Input: Array Address in $a0, Number of elements in $a1
#Output: None
#Purpose: Print array elements
#Registers used: $t0, $t1, $t2, $t3
#Assumption: Array element is word size (4-byte)
printArray:
addi $t1, $a0, 0 #$t1 is the pointer to the item
sll $t2, $a1, 2 #$t2 is the offset beyond the last item
add $t2, $a0, $t2 #$t2 is pointing beyond the last item
l1:
beq $t1, $t2, e1
lw $t3, 0($t1) #$t3 is the current item
li $v0, 1 # system call code for print_int
addi $a0, $t3, 0 # integer to print
syscall # print it
addi $t1, $t1, 4
j l1 # Another iteration
e1:
li $v0, 4 # system call code for print_string
la $a0, newl #
syscall # print newline
jr $ra # return from this function
#######################################################################
### Student Function findMin ###
#Input: Lower Array Pointer in $a0, Higher Array Pointer in $a1
#Output: $v0 contains the address of min item
#Purpose: Find and return the minimum item
# between $a0 and $a1 (inclusive)
#Registers used: $t0 (counter), $t1 (max add), $t2 (min), $v0 (min pos), $t3 (current item)
#Assumption: Array element is word size (4-byte), $a0 <= $a1
findMin:
lw, $t2, 0($a0) # initialise min (value) to the lower bound
addi $t0, $a0, 0 # initialise $t0 (current pointer) to lower bound
addi $t1, $a1, 0 # initialise $t1 (add of end of array) to upper bound
Loop: slt $t4, $t1, $t0
bne $t4, $zero, End # branch to end if upper < lower
lw, $t3, 0($a0) # store the content of the lower array pointer
slt $t4, $t3, $t2 # if current ($t3) < min ($t2), store 1 in $t4
beq $t4, $zero, LoopEnd # if it is 0, go to LoopEnd
addi $t2, $t3, 0 # store content ($t3) as minimum ($t2)
addi $v0, $t0, 0 # store the address of min
LoopEnd: addi, $t0, 4 # increments current pointer lower bound
j Loop # Jump to loop
End:
jr $ra # return from this function
You read in the integers properly. The problems are elsewhere
In findMin function you use lw, $t3, 0($a0), but you should use it with $t0 instead of $a0.
After you return from this function you accidentally save $t1 as min value rather then $t2 which actually holds it.
Also you do not save $v0 which holds the pointer for the min value, so you use some garbage data later on, not the intended one.
When you calculate the index of the min from the pointer you use add, but it should be sub.
Also as it was mentioned in the comments at LoopEnd the add is syntactically wrong. It should be addi $t0, $t0, 4. But this maybe just some copy paste error.
Here is the fixed code. Changed lined marked with ERROR.
# arrayFunction.asm
.data
array: .word 8, 2, 1, 6, 9, 7, 3, 5, 0, 4
newl: .asciiz "\n"
.text
main:
# Print the original content of array
# setup the parameter(s)
la $a0, array # base address of array
add $t9, $a0, $zero # store base address
la $a1, 10 # number of elements in array
# call the printArray function
jal printArray # call function
# Ask the user for two indices
li $v0, 5 # System call code for read_int
syscall
add $t0, $v0, $zero # store input in $t0
sll $t0, $t0, 2 # relative address position (lower bound)
add $a0, $t9, $t0 # array pointer (lower bound)
li $v0, 5 # System call code for read_int
syscall
add $t0, $v0, $zero # store input in $t0
sll $t0, $t0, 2 # relative address position (upper bound)
add $a1, $t9, $t0 # array pointer (upper bound)
# Call the findMin function
# setup the parameter(s)
# call the function
jal findMin # call function
# Print the min item
# place the min item in $t3 for printing
addi $t3, $t2, 0 # ERROR: min is in $t2 not $t1
addi $t4, $v0, 0 # ERROR: not saving the pointer to the min element
# Print an integer followed by a newline
li $v0, 1 # system call code for print_int
addi $a0, $t3, 0 # print $t3
syscall # make system call
li $v0, 4 # system call code for print_string
la $a0, newl
syscall # print newline
#Calculate and print the index of min item
la $a0, array
sub $t3, $t4, $a0 # ERROR: sub should used not add
srl $t3, $t3, 2
# Place the min index in $t3 for printing
# Print the min index
# Print an integer followed by a newline
li $v0, 1 # system call code for print_int
addi $a0, $t3, 0 # print $t3
syscall # make system call
li $v0, 4 # system call code for print_string
la $a0, newl #
syscall # print newline
# End of main, make a syscall to "exit"
li $v0, 10 # system call code for exit
syscall # terminate program
#######################################################################
### Function printArray ###
#Input: Array Address in $a0, Number of elements in $a1
#Output: None
#Purpose: Print array elements
#Registers used: $t0, $t1, $t2, $t3
#Assumption: Array element is word size (4-byte)
printArray:
addi $t1, $a0, 0 #$t1 is the pointer to the item
sll $t2, $a1, 2 #$t2 is the offset beyond the last item
add $t2, $a0, $t2 #$t2 is pointing beyond the last item
l1:
beq $t1, $t2, e1
lw $t3, 0($t1) #$t3 is the current item
li $v0, 1 # system call code for print_int
addi $a0, $t3, 0 # integer to print
syscall # print it
addi $t1, $t1, 4
j l1 # Another iteration
e1:
li $v0, 4 # system call code for print_string
la $a0, newl #
syscall # print newline
jr $ra # return from this function
#######################################################################
### Student Function findMin ###
#Input: Lower Array Pointer in $a0, Higher Array Pointer in $a1
#Output: $v0 contains the address of min item
#Purpose: Find and return the minimum item
# between $a0 and $a1 (inclusive)
#Registers used: $t0 (counter), $t1 (max add), $t2 (min), $v0 (min pos), $t3 (current item)
#Assumption: Array element is word size (4-byte), $a0 <= $a1
findMin:
lw, $t2, 0($a0) # initialise min (value) to the lower bound
addi $t0, $a0, 0 # initialise $t0 (current pointer) to lower bound
addi $t1, $a1, 0 # initialise $t1 (add of end of array) to upper bound
Loop:
slt $t4, $t1, $t0
bne $t4, $zero, End # branch to end if upper < lower
lw, $t3, 0($t0) # store the content of the lower array pointer, ERROR: t0 should be used not a0
slt $t4, $t3, $t2 # if current ($t3) < min ($t2), store 1 in $t4
beq $t4, $zero, LoopEnd # if it is 0, go to LoopEnd
addi $t2, $t3, 0 # store content ($t3) as minimum ($t2)
addi $v0, $t0, 0 # store the address of min
LoopEnd:
addi $t0, $t0, 4 # increments current pointer lower bound
j Loop # Jump to loop
End:
jr $ra # return from this function

Why does my string length subroutine give an infinity loop?

I want my code to print the length of a string, but instead it seems to enter an infinity loop. I cannot understand where my error is.
.data
STR_str:
.asciiz "Hello"
#################################
main:
la $a0, STR_str
jal string_length
add $a0, $v0, $zero
li $v0, 1
syscall
############################################
string_length:
li $v0, 0 # initialize the count to zero
str_lenght_loop:
lb $t2, 0($a0) # load the next character into t2
loop_strlen: beqz $t2, exit # check for the null character
addi $a0, $a0, 1 # increment the string pointer
addi $v0, $v0, 1 # increment the count
j loop_strlen # return to the top of the loop
exit:
jr $ra

MIPS - Printing a certain number of characters from a string

If given a number, I want to print out the first 'x' number of letters from the alphabet. I've setup a counter to determine the number of iterations the loop goes through, but I do not know how to extract the correct number of letters from the alphabet string.
Here's what I've done so far:
.data
alphabet:
.space 28
msg1: .ascii " Please enter an integer from 1-26:"
msg2: .ascii "abcdefghijklmnopqrstuvwxyz"
.text
.globl main
main:
li $v0, 5 # syscall for read_int
syscall
add $a0, $v0, $zero
li $t0, 0
li $t1, 26 # loop will start from zero and iterate to 26
loop:
la $t2, 0($a0)
beq $t0, $t2, end # once $t1 and $a0 are equal, loops stops
#li $t2, 1
#blt $t1, $t2, nomodify # do nothing if int less than 0
#li $t2, 26
#bgt $t0, $t2, nomodify # do nothing if int greater than 25
addi $t0, $t0, 1 # add 1 to $t1
j loop # jump back to top
end:
# Here is where I want to take 'x' number of iterations and convert it to
# the string of 'x' letters
li $v0, 10
syscall
Any help would be appreciated.
Having all the characters in a string is unnecessary for this task. Characters are integers, so you can just start at 'a' and count upwards:
# Assuming the loop count is in $t0
li $a0, 'a' # start at character 'a'
print_chars:
li $v0, 11
syscall # syscall 11 = print_character
addiu $a0, $a0, 1 # set $a0 to the next character
addiu $t0, $t0, -1
bne $t0, $zero, print_chars

MIPS prompt for a string and exchange the case of each character

I am writing a MIPS program that prompts the user for a string and then parse the string exchanging the case of each character.
for example ->
Hey You becomes hEY yOU.
My question is, how do i make it do nothing if it encounters a space ? Any help would be great!
.data
string4:.space 82 # space for input string
strPrompt:.asciiz "Please enter a string: "
.text
.globl main
main:
la $a0, strPrompt # print prompt
li $v0, 4
syscall
la $a0, string4 # read string
li $a1, 80
li $v0, 8
syscall
la $a0, string4 # print string
li $v0, 4
syscall
la $t0, string4 # $t0 = &string4[0]
li $t1, 0
loop4:
lb $t1, 0($t0)
nop
nop
beqz $t1, done4 # if $t1 == NUL, we are done
bgt $t1, 90, else # if char > 90 its a lower case
nop
addi $t1, $t1, 0x20 # if < 90 its upper case add 32
sb $t1, 0($t0)
addi $t0, $t0, 1 # add 1 to pointer
j loop4 # jump back to loop
nop
else:
addi $t1, $t1, -0x20
sb $t1, 0($t0)
addi $t0, $t0, 1
j loop4
nop
done4:
Here's a branchless way of changing the case of a character in $t1 if it's in the range A..Z or a..z, and do nothing if it's outside that range:
# if (upper($t1) >= 'A' && upper($t1) <= 'Z') $t2 = 1; else $t2 = 0;
andi $t3,$t1,0xDF # clear bit 5, if $t1 was an alphabetic character $t3 will now be uppercase
li $t2,'A'-1
sltu $t2,$t2,$t3
sltiu $t3,$t3,'Z'+1
and $t2,$t2,$t3
sll $t2,$t2,5 # $t2 = 0x20, or 0
xor $t1,$t1,$t2 # either swap case or do nothing