MIPS find end of string - mips32

I have the following mips code (running it in QTSPIM), that is supposed to count the number of characters in a string and print them.
The logic behind it is very simple but is does not work as it should. Everything goes well until it reaches the end of the string and then it continues counting even though I compare each element to $zero to find the end of string (\0).
Is there something wrong with my condition to exit the loop, or my_string does not contain \0 in the end so it won't exit?
.data
endl: .asciiz "\n"
my_string: .asciiz "thisisastring"
star: .asciiz "*"
str_end: .word 0
space: .asciiz " "
.text
.globl main
main:
la $a0, my_string
li $v0, 4
syscall
la $a0, endl
li $v0, 4
syscall
la $t0, my_string # load mystring to $t0
li $t1, 0 # make $t1 = 0, character counter
lb $t2, ($t0) # make $t2 point to the first character of "my_string"
li $t3, 1 # $t3 is the ++ register to go to the next character
li $t4, 0 # character counter
la $t5, str_end
cont:
beqz $t0, print # if \0 is found print and exit
addi $t4, $t4, 1 # increase the counter
lbu $a0, ($t0) # print current character
li $v0, 11
syscall
addi $t0, $t0, 1 # go to next char
#move $t2, $t0
j cont
print:
move $a0, $t4
li $v0, 1
syscall
j exit
exit:
li $v0, 10
syscall

The problem is in the order of the instructions, the logic of the code.
Here is the corrected version with no redundant code:
.data
endl: .asciiz "\n"
my_string: .asciiz "thisisastring"
str_end: .word 0
.text
.globl main
main:
la $a0, my_string
li $v0, 4 # print the string
syscall
la $a0, endl # print endl
li $v0, 4
syscall
la $t0, my_string # load mystring to $t0
li $t1, 0 # make $t1 = 0, character counter
lb $t2, 0($t0) # make $t2 point to the first character of "my_string"
la $t5, str_end
cont:
lb $a0, 0($t0) # print current character
beqz $a0, print # if \0 is found print and exit
addi $t1, $t1, 1 # increase the counter
addi $t0, $t0, 1 # go to next char
li $v0, 11
syscall
j cont
print:
move $a0, $t1
li $v0, 1
syscall
j exit
exit:
li $v0, 10
syscall

Related

Runtime exception at 0x0040002c: address out of range 0x00000001 in MIPS Assembler for ceasar encryption

The Programm compiles just fine but as soon as i give input this error is thrown:
"Error in line 28: Runtime exception at 0x0040002c: address out of range 0x00000001
Processing terminated due to errors."
Here ist the code for my programm:
.data
line: .space 80
.text
main:
# read line from stdin
li $v0, 8
la $a0, line
li $a1, 80
syscall
# call caesar_line
li $a0, 1
jal caesar_line
# return 0
li $v0, 0
jr $ra
caesar_line:
# save start of line
move $t0, $a0
# loop through line
loop:
# load the character from memory
move $t1, $a0
lb $a0, 0($t1)
beqz $a0, end_loop
jal caesar_char
sb $v0, 0($t1)
addi $t1, $t1, 1
move $a0, $t1
j loop
end_loop:
# print line
li $v0, 4
move $a0, $t0
syscall
jr $ra
caesar_char:
# check if c is lowercase
blt $a0, 'a', upper
bgt $a0, 'z', not_alpha
addi $a1, $a1, 'a'
jal caesar_helper
j done
upper:
# check if c is uppercase
blt $a0, 'A', not_alpha
bgt $a0, 'Z', not_alpha
addi $a1, $a1, 'A'
jal caesar_helper
j done
not_alpha:
# not an alphabetical character
move $v0, $a0
j done
caesar_helper:
# subtract base from c
sub $t0, $a0, $a2 # $t0 = c - base
# add distance + 26 to c
addi $t0, $t0, 26 # $t0 += 26
add $t0, $t0, $a1 # $t0 += distance
# calculate c % 26
li $t1, 26 # $t1 = 26
div $t0, $t1 , $t1 # $lo = c % 26
mflo $t0
# add base to c
add $v0, $t0, $a2 # $v0 = c + base
done:
jr $ra
Not even ChatGBT could find an error.
The code should shift all chars of an string by a certain amount, but as soon as it is run the error above is thrown.

Mips blank space on address

So I have a string of chars. I need to check if a character is blank space " "/ ascii 32. How can I give an address ascii value of blank space so I can use it in if/else?
.data
userInput: .space 40
.text
main:
li $v0, 8
la $a0, userInput
li $a1, 40
syscall
li $t1,0
la $t0,userInput
loop:
li $a3, 32 #can i give this address 32 ascii value?
lb $a0,0($t0)
beqz $a0,done
addi $t0,$t0,1 #going true the characters
bne $t0, $a3, L1 # branch if ! ( char == ' ' )
addi $t1,$t1,1 #add blank space
L1: addi $t2,$t2,1 #add characters
j loop
done:
li $v0,1
addi $t1, $t1, -1
add $a0, $0,$t1
syscall
li $a0, 32
li $v0, 11
syscall
li $v0,1
addi $t2, $t2, -1
add $a0, $0,$t2
syscall
li $v0,10
syscall
.data
blankSpace: .ascii " "
.text
main:
la $a3, blankspace
lb $t3,0($a3)
Alternative you can directly load the ASCII value for space which is 0x20 in ASCII table.
li $a3, 0x20

comparing a string in MIPS

Could someone tell me what is wrong with my code so far. I am trying to make a program that takes input from the user (roman numerals) and then converts it to integers. So far this is what I have:
.data
buffer: .space 20
onlyCaps: .asciiz "Please enter only Capital Numbers\n"
enter1: .asciiz "Number out of range. Please enter another number\n"
enter2: .asciiz "Please enter your roman numeral: "
debug: .asciiz "reach"
M: .asciiz "1000"
D: .asciiz "500"
C: .asciiz "100"
L: .asciiz "50"
X: .asciiz "10"
V: .asciiz "5"
I: .asciiz "1"
.text
main:
la $a0, onlyCaps # "Enter Only Capital numbers"
li $v0, 4
syscall
la $a0, enter2 #prompt user with "Please enter a roman numeral:"
li $v0, 4
syscall
la $a0, buffer #load byte space into address
li $a1, 3 # allot the byte space for string
li $v0, 8 #read user input, j
syscall
li $t4, 1
loop:
lb $t0, 0($a0) # Save $v0 value to $t0
beqz $t4, done # if it is equal to zero end the loop
add $a0, $a0, $t4 #increment the address
j mCheck
#while loop ends here
mCheck:
beq $t0, 'M', mChar # if $t0 equal M go to mChar
bne $t0, $t1, dCheck # move to see if equals D
dCheck:
beq $t0, 'D', dChar # if $t0 equal D go to dChar
bne $t0, $t1, cCheck
cCheck:
beq $t0, 'C', cChar # if $t0 equal C go to cChar
bne $t0, $t1, lCheck
lCheck:
beq $t0, 'L', lChar # if $t0 equal L go to lChar
bne $t0, $t1, xCheck
xCheck:
beq $t0, 'X', xChar # if $t0 equal X go to xChar
bne $t0, $t1, vCheck
vCheck:
beq $t0, 'V', vChar # if $t0 equal V go to vChar
bne $t0, $t1, iCheck
iCheck:
beq $t0, 'I', iChar # if $t0 equal I go to iChar
bne $t0, $t1, error
mChar:
la $a0, M #puts one hundred in $t3
li $v0, 4
syscall
j loop
dChar:
la $a0, D # prints out 500
li $v0, 4
syscall
j loop
cChar:
la $a0, C # prints out 500
li $v0, 4
syscall
j loop
lChar:
la $a0, L # prints out 500
li $v0, 4
syscall
j loop
xChar:
la $a0, X # prints out 500
li $v0, 4
syscall
j loop
vChar:
la $a0, V # prints out 500
li $v0, 4
syscall
j loop
iChar:
la $a0, I # prints out 500
li $v0, 4
syscall
j loop
error:
la $a0, enter1 # Print error meg. then back to main
li $v0, 4
syscall
j done
done:
li $v0, 10 # Exit
syscall
My question is how can you take input from the user and put it in $a0, and then use a while loop after that? I can't get the bytes to go to the next spot (i.e. MXX to go from M to X.) currently the program reads M, but not X. Eventually I will switch the program to sum these numbers and to also check to see if the number before is less (i.e. IV) to account for those roman numerals but I need help with the while loop first.

Case sorting in mips

I have a program that will capitalize all lowercase letters and lowercase all the uppercase letters entered in a string by the user. It does this by adding or subtracting 32 from the character value to get the desired character. My problem is that it doesn't change anything in the string. Any suggestions on what to change?
.data
prompt: .asciiz "\n\nEnter an string of characters: "
result: .asciiz "\n\nHere is the string you entered: "
after_sort: .asciiz "\n\nHere is the string after the case sorting: "
buffer: .space 80
.text
main:
#Prints the prompt string
li $v0, 4
la $a0, prompt
syscall
#reads string from user and saves in $a0
li $v0, 8
la $a0, buffer
li $a1, 80
syscall
#Prints the result string
li $v0, 4
la $a0, result
syscall
#Prints the string entered by the user
la $a0, buffer
li $v0, 4
syscall
li $t0, 0 # t0 = i = 0
for_loop:
slti $t1, $t0, 80 # t1 = 1 if and only if t0 < 80
beq $t1, $0, for_loop_done
slti $t2, $a0, 91
li $t3, 1
beq $t2, $t3, upper #if the character value is less than 91 branch to upper addition
bne $t2, $t3, lower
upper:
addi $a0, $a0, 32 #adds 32 to the character value to lowercase it
lower:
subi $a0, $a0, 32 #subtracts 32 from the character value to capitalize it
addi $t0, $t0, 1
j for_loop
for_loop_done:
#Prints the result string
li $v0, 4
la $a0, after_sort
syscall
#Prints the string entered by the user
la $a0, buffer
li $v0, 4
syscall
exitProgram: li $v0, 10 # system call to
syscall # terminate program
You are using $a0as a character, such as here:
slti $t2, $a0, 91
but it is never filled with the character. At the moment, it contains a memory address, not a character.
You should load the character using lb and store it back after making it upper/lowercase using sb.
Feel free to add a comment if you want a code example.
Edit: the changes in the relevant part of the code:
...
li $t0, 0 # t0 = i = 0
for_loop:
slti $t1, $t0, 80 # t1 = 1 if and only if t0 < 80
beq $t1, $0, for_loop_done
lb $t4, 0($a0)
beqz $t4, for_loop_done
beq $t4, 10, for_loop_done
slti $t2, $t4, 91
li $t3, 1
beq $t2, $t3, upper #if the character value is less than 91 branch to upper addition
bne $t2, $t3, lower
upper:
addi $t4, $t4, 32 #adds 32 to the character value to lowercase it
j done
lower:
addi $t4, $t4, -32 #subtracts 32 from the character value to capitalize it
done:
addi $t0, $t0, 1
sb $t4, 0($a0)
addi $a0, $a0, 1
j for_loop
for_loop_done:
#Prints the result string
...
It's easy to forget that in assembly, you can't do this:
if something
do this
else
do that
There is no "else", only shudder Goto.
So in this code:
slti $t2, $a0, 91
li $t3, 1
beq $t2, $t3, upper #if the character value is less than 91 branch to upper addition
bne $t2, $t3, lower
upper:
addi $a0, $a0, 32 #adds 32 to the character value to lowercase it
lower:
subi $a0, $a0, 32 #subtracts 32 from the character value to capitalize it
addi $t0, $t0, 1
When you branch to upper, it adds 32. Then it subtracts 32, because execution progressed to the next line. So your code capitalizes lower case, but does nothing to uppercase.
You need to add a jump to the first instruction after your if/then/else equivalent:
upper:
addi $a0, $a0, 32 #adds 32 to the character value to lowercase it
j done # No, I don't want to subtract it again!
lower:
subi $a0, $a0, 32 #subtracts 32 from the character value to capitalize it
done:
addi $t0, $t0, 1
In fact, you should probably get rid of the bne altogether - it's redundant. If beq doesn't branch, then it's not equal. So this would be the finished product:
slti $t2, $a0, 91
li $t3, 1
beq $t2, $t3, upper #if the character value is less than 91 branch to upper addition
# Otherwise, it's lower
subi $a0, $a0, 32 #subtracts 32 from the character value to capitalize it
j done
upper:
addi $a0, $a0, 32 #adds 32 to the character value to lowercase it
done:
addi $t0, $t0, 1
Hope that helps!
(Edit: #Patrik is right too, you need to "dereference" $a0. My example doesn't take that into account.)
here is my code:
it works perfectly
.data
theString:
.space 20
prompt: .asciiz "Enter a string of characters: "
.text
main:
li $v0, 4
la $a0, prompt
syscall
li $v0, 8
la $a0, theString
li $a1, 20
syscall
li $v0, 4
syscall
la $t1,theString
for: lb $a0, 0($t1)
beqz $a0,out #to find out end of string
beq $a0,10,out #to find out end of string
slti $t2, $a0,91 #if $a0<91 $t2=1
beq $t2,1,small
beq $t2,0,capital
capital:
subu $a0, $a0, 32
li $v0,11
syscall
addi $t1,$t1,1
j for
small:
addi $a0, $a0, 32
li $v0,11
syscall
addi $t1,$t1,1
j for
out:
li $v0, 10
syscall

Load byte on mips32

I'm starting with mips32 and I'm getting stuck when trying to get a letter from a string to print it. The code should get the string, print it character by character and when it finds an i print iiing.
.data
msg: .asciiz "testing"
i: .asciiz "iiing"
.text
.globl main
main:
la $t0, msg
la $t1, i
li $t2, 0
loop:
bneq $t0, 105, end #$t0=i?
lb $a0, ($t0)
li $v0, 4
syscall
addi $t0, $t0, 1
b loop
end:
move $a0, $t1
li $v0, 4
syscall
Where is the problem?
You have a few problems.
You are comparing $t0, which is the address of the current character, not the character itself. Move that test below the lb line and test against $a0.
105 in ASCII is E, not i. Try 151 (or to be more normal, 0x69).
You want to compare with beq, not bneq.
Inside the loop, you should use syscall 11, which prints a single character, rather than the current syscall 4 you're using, which prints a string.
Your program doesn't make an exit syscall (10) at the end.
You can look at this link for a list of syscalls.
Here's a complete working program for reference:
.data
msg: .asciiz "testing"
i: .asciiz "iiing"
.text
.globl main
main:
la $t0, msg
la $t1, i
li $t2, 0
loop:
lb $a0, ($t0)
beq $a0, 0x69, end
li $v0, 11
syscall
addi $t0, $t0, 1
b loop
end:
move $a0, $t1
li $v0, 4
syscall
li $v0, 10
syscall

Resources