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
Related
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
I am a bit new to mips and am trying to set a .asciiz variable equal to another, then print it. This is what I have:
.data
s: .asciiz "I never could get the hang of Thursdays."
s2: .space 50
.text
main:
la $t0, s
la $t1, s2
lbu $t2, 0($t0)
sb $t2, 0($t1)
la $a0, s2
li $v0, 4
syscall
li $v0, 10
syscall
However, I am only able to print one byte at a time. How can I print the whole string?
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.
I'm stuck on an exercise, and am unsure how to proceed. This is the exercise:
Write a MIPS assembly language procedure, Test, that accepts 2 integers as arguments and
returns 0 if the integers are equal, 1 if the first is less than the second, and 2 if the first is greater
than the second.
Write a MIPS assembly language program that reads in 2 integers, calls the procedure Test, then
outputs one of the following messages:
The integers are equal
The first integer is less than the second
The first integer is greater than the second
What would be an example to carry this out? Mips is very confusing to me, as I'm used to Java. Thank you.
EDIT: Here is the program I am using as a foundation, since I am unsure where to start:
.data
str1: .asciiz "Please Enter Integer 1: " # a
str2: .asciiz "Please Enter Integer 2: " # a
str3: .asciiz "The sum is " # a
newline: .asciiz "\n" # g
.text
main: addi $v0, $zero, 4
la $a0, str1
syscall
addi $v0, $zero, 5
syscall
add $s0, $zero, $v0
addi $v0, $zero, 4
la $a0, str2
syscall
addi $v0, $zero, 5
syscall
add $s1, $zero, $v0
L1: beq $s1, $zero, cont
addi $v0, $zero, 1
add $a0, $s0, $zero
addi $s1, $s1, -1
syscall
j L1
cont: addi $v0, $zero, 4
la $a0, newline
syscall
addi $v0, $zero, 10
syscall
jr $ra
To check whether one register's value is smaller than another register's value, we can use the
set-on-less-than instruction, which also has a set-on-less-than-immediate counterpart.
slt $r0, $r3, $r4
()if r3 < r4, r0 is set to 1
else r0 is set to 0
slti $r0, $r3, 10
()if r3 < 10, r0 is set to 1
else r0 is set to 0
slt and slti are similar to beq or bne, however, there are two differences. First, they test
whether one value is smaller than another value and, second, they don't branch to some
address, but, instead, set a flag, stored in the first operand.
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