I wrote this code in MIPS to count the # of lowercase letters input by a user:
.data
msg1: .asciiz
count_lower: .space 41
.text
.globl main
main:
la $a0, msg1 #load address of msg1 to store string
li $a1, 100 #msg1 is 100 bytes
li $v0, 8 #syscall for read str
syscall
add $s1, $0, $0 #interger to print later
la $t0, count_lower
sw $a0, 0($t0) #store input string in $t0
loop:
lb $t1, 0($t0) #load char from $t0
beqz $t1, exit #if no more chars, exit
blt $t1, 'a', else #This line and line below are for if char is not lowercase
bgt $t1, 'z', else
addi $s1, $s1, 1 #if char is lowercase, +1 to $s1
sll $t0, $t0, 8 #shift one byte to get to next char
sll $t1, $t1, 8 #shift one byte to get to next char
else:
sll $t0, $t0, 8 #shift one byte to get to next char
sll $t1, $t1, 8 #shift one byte to get to next char
j loop #jump back to loop
exit:
move $a0, $s1 #move interge to print into $a0
li $v0, 1 #print interger in $a0
syscall
li $v0, 10 #exit
syscall
But when I run it, all it does it print the integer "0" no matter what string is input. Can anyone help me troubleshoot? I wrote comments in the code to explain my thought proccess.
EDIT:
1 .data
2 msg1: .space 100
3 .text
4 .globl main
5 main:
6 li $v0, 8 #syscall for read str
7 la $a0, msg1 #load address of msg1 to store string
8 li $a1, 100 #msg1 is 100 bytes
9 move $t0, $a0 #save user input to $t0
10 syscall
11 add $s1, $0, $0 #interger to print later
12 add $t1, $0, $0 #initialize $t1
13 loop:
14 sb $t0, 0($t1) #store rightmost char into memory 0
15 lb $t1, 0($t0) #load char from memory 0 into $t1
16 beqz $t1, exit #if no more chars, exit
17 blt $t1, 'a', else #This line and line below are for if char is not
18 lowercase
19 bgt $t1, 'z', else
20 addi $s1, $s1, 1 #if char is lowercase, +1 to $s1
21 srl $t0, $t0, 8 #shift one byte to get to next char
22 add $t1, $0, $0 #re-initialize $t1
23 j loop #jump back to loop
24 else:
25 srl $t0, $t0, 8 #shift one byte to get to next char
26 add $t1, $0, $0 #re-initialize $t1
27 j loop #jump back to loop
28
29 exit:
30 move $a0, $s1 #move interge to print into $a0
31 li $v0, 1 #print interger in $a0
32 syscall
33 li $v0, 10 #exit
34 syscall
This doesn't do what you seem to think it does:
sw $a0, 0($t0) #store input string in $t0
That instruction only stores the address of the string at ($t0) (i.e. in the first 4 bytes of count_lower).
I really don't see why you need two buffers for this. Just read the characters from the same buffer that you specified for syscall 8.
Also, your declaration of msg1 is incorrect. Your comment says #msg1 is 100 bytes, but your declaration is msg1: .asciiz, which certainly doesn't reserve 100 bytes. That should be changed to msg1: .space 100.
Related
I am trying to write a program that gets a user string input and reverse that string in MIPS.
However, I must be doing something horribly wrong as it doesn't just display the user input in reverse but, it also reverses the prompt to the user. It seems that the user input is not identified with a null(zero?) character in the end.
.data
prompt: .asciiz "Please enter your name. You're only permitted 20 characters. \n"
userInput: .space 20 #user is permitted to enter 20 characters
.globl main
.text
main:
# user prompt
li $v0, 4
la $a0, prompt
syscall
# getting the name of the user
li $v0, 8
la $a0, userInput
li $a1, 20
syscall
add $t0, $a0, $0 # loading t0 with address of array
strLength:
lbu $t2, 0($t0)
beq $t2, $zero, Exit # if reach the end of array, Exit
addiu $t0, $t0, 1 # add 1 to count the length
j strLength
Exit:
add $t1, $t0, $0 # t1 = string length
li $t2, 0 # counter i = 0
li $v0, 11
reverseString:
slt $t3, $t2, $t1 # if i < stringlength
beq $t3, $0, Exit2 # if t3 reaches he end of the array
addi $t0, $t0, -1 # decrement the array
lbu $a0, 0($t0) # load the array from the end
syscall
j reverseString
Exit2:
li $v0, 10
syscall
Problem number 1:
add $t1, $t0, $0 #t1 = string length
What you're assigning to $t1 here isn't the length of the string; it's the address of the first byte past the end of the string.
Problem number 2 is that you never increment $t2 (or decrement $t1) within the reverseString loop.
I suggest that you make use of the debugging features in SPIM/MARS (like the ability to set breakpoints and single-step through the code), as that would've made finding these problems yourself fairly simple.
1 .data
2 msg1: .word 0:24
3 .text
4 .globl main
5 main:
6 li $v0, 8 #syscall for read str
7 la $a0, msg1 #load address of msg1 to store string
8 li $a1, 100 #msg1 is 100 bytes
9 syscall
10 lb $t0, 5($a0) #load the character into $t0
11 li $t1, 'a' #get value of 'a'
12 blt $t0, $t1, nomodify #do nothing if letter is less than 'a'
13 li $t1, 'z' #get value of 'z'
14 bgt $t0, $t1, nomodify #do nothing if letter is greater than 'z'
15 addi $t0, $t0, -0x20 #encap the letter
16 sb $t0, 5($a0) #store the new letter
17 nomodify:
18 li $v0, 4 #syscall for print str
19 syscall
20 li $v0, 10 #system call for exit
21 syscall # we are out of here.
First off, the purpose of this code is to get a string from the user and print the string back.
My first question:
In line 10, why is it loading a byte from $a0 + 5 specifically? I get that $a0 is the input string that is to be printed, but I don't understand why it's offset by 5.
Second question:
In lines 11 - 14, why does it branch to nomodify if the character is less than 'a' or if the character is greater than 'z'? Isn't that just saying to print the character if it's not in the range of a-z?
Third question:
In lines 11-16, if the character is neither less than 'a' nor greater than 'z', line 15 says to add an immediate value of -0x20 into $t0, which the comment says is to "encap the letter". What does that mean?
Lastly:
the continued use of the word "char" is confusing me. This code is to read/print a string right? Isn't a char just one character of the string?
1 .data
2 msg1: .word 0:24
3 .text
4 .globl main
5 main:
6 li $v0, 8 #syscall for read str
7 la $a0, msg1 #load address of msg1 to store string
8 li $a1, 100 #msg1 is 100 bytes
9 syscall
18 li $v0, 4 #syscall for print str
19 syscall
20 li $v0, 10 #system call for exit
21 syscall # we are out of here.
This would be the true code to simply read/write an input string. The code in the question (lines 10 - 17 specifically) I asked was doing extra things to the 6th character.
Hi i was wondering if there was a simple way to remove the spaces i allocated for a string to be entered, or perhaps a way to not compare the empty space after the word. This program is a palindrome detector. Any suggestions would be great.
Ex. output:
racecar, not a palindrome because it has a few empty spaces.
aaaaaaaaaa is a palindrome because it has no empty spaces...
again just need a hotfix to remove the spaces after the word is inputted, or a way to ignore the spaces after the word. Thank You.
.data
intro : .asciiz "Lets See If Your Word is a Palinfrome!\n"
question: .asciiz "Please Enter up to a 10 Character word: "
Y_P: .asciiz "Yes it is!"
N_P: .asciiz "No Its Not!"
str1: .space 10
.text
.globl main
main:
li $v0, 4
la $a0, intro
syscall
li $v0, 4
la $a0, question
syscall
li $v0, 8
la $a0,str1
addi $a1,$zero,10
syscall
move $t0, $a0
palindrome:
addi $t0, $0, 0 # j = 0
length: add $t2, $a0, $t0 # $t2 = &array[j]
lb $t2, 0($t2) # $t2 = array[j]
beq $t2, $0, done # end of string?
addi $t0, $t0, 1 # j = j+1
j length
done: addi $t0, $t0, -1 # j = j-1
addi $t1, $0, 0 # i = 0
loop: slt $t2, $t1, $t0 # $t2 = 1 if i < j
beq $t2, $0, yes # if !(i < j) return
add $t2, $a0, $t1 # $t2 = &array[i]
lb $t2, 0($t2) # $t2 = array[i]
add $t3, $a0, $t0 # $t3 = &array[j]
lb $t3, 0($t3) # $t3 = array[j]
bne $t2, $t3, no # is palindrome?
addi $t0, $t0, -1 # j = j-1
addi $t1, $t1, 1 # i = i+1
j loop
yes: # yes a palindrome
addi $v0, $0, 1
li $v0, 4
la $a0, Y_P
syscall
li $v0, 10
syscall
j yes
jr $ra
no: # not a palindrome
addi $v0, $0, 0
li $v0, 4
la $a0, N_P
syscall
li $v0, 10
syscall
j no
jr $ra
The following is my code for a MIPS assembly program that is intended to remove vowels from an input string and then print the new string. As it stands, the program simply does not remove the vowels and just reprints the same string that was input.
.text
.globl main
main:
# display prompt
li $v0, 4
la $a0, prompt
syscall
# accept input string
li $v0, 8
la $a0, str
li $a1, 82
syscall
li $t0, 0 # add a null to the bottom of the stack
subu $sp, $sp, 4
sw $t0, ($sp)
li $t1, 0 # initiate index
pushloop:
lbu $t0, str($t1) # (I think the program is placing a zero in $t0 here, thus causing it to branch immediately to poploop, which then branches to the end since only the null has been pushed onto the stack)
beqz $t0, poploop # once we reach null char, finish
subu $sp, $sp, 4
sw $t0, ($sp)
addiu $t1, $t1, 1
j pushloop
nop
# $t1 is not reset
poploop:
lw $t0, ($sp)
addu $sp, $sp, 4
beqz $t0, done # once we reach null char, finish
nop
# check if vowel
li $t2, 0x61 # a
beq $t0, $t2, vowel
nop
li $t2, 0x65 # e
beq $t0, $t2, vowel
nop
li $t2, 0x69 # i
beq $t0, $t2, vowel
nop
li $t2, 0x6F # o
beq $t0, $t2, vowel
nop
li $t2, 0x75 # u
beq $t0, $t2, vowel
nop
# if not a vowel, store it at current index in string
sb $t0, str($t1)
j decrement
nop
vowel: # if vowel, remove character
li $t0, 0
sb $t0, str($t1)
decrement:
addiu $t1, $t1, -1 # decrement index
j poploop
nop
done:
li $v0, 4
la $a0, str
syscall
li $v0, 10 # exit program
syscall
nop
.data
str: .space 82
prompt: .asciiz "Input a string:\n"
So. I took a look at what you've writen and I've fixed it.
My first thought is I don't know what you are doing with the stack and stack pointer ($sp). It didn't seem necessary so I took it out.
Next is that the approach is wrong. Your approach is to search the string and replace every lower-case vowel (or at least 'a', 'e', 'i', 'o' and 'u') with a 0. This will not work.
If you think about a typical C string, they are delimeted by a 0, so if you take the string My name is Jeoff and apply your algorithm you will get My n\0m\0 \0s J\0\0ff which of course will print as My n.
So instead, I chose a separate algthm that chooses to not store anything in the case of a vowel and instead shift all following characters over by 1. In so doing we can easily remove all vowels from a string without requiring a secondary buffer.
Take a look below:
.text
.globl main
main:
# display prompt
li $v0, 4
la $a0, prompt
syscall
# accept input string
li $v0, 8
la $a0, str
li $a1, 82
syscall
li $t1, 0 # initiate index
li $t3, 0 # vowel count
poploop:
lb $t0 str($t1)
# check if vowel
li $t2, 'a' # a
beq $t0, $t2, vowel
nop
li $t2, 'e' # e
beq $t0, $t2, vowel
nop
li $t2, 'i' # i
beq $t0, $t2, vowel
nop
li $t2, 'o' # o
beq $t0, $t2, vowel
nop
li $t2, 'u' # u
beq $t0, $t2, vowel
nop
# if not a vowel, store it at current index in string less vowel count
sub $t2, $t1, $t3
sb $t0, str($t2)
j next
nop
vowel: # if vowel, inc count
addi $t3, $t3, 1
next:
addi $t1, $t1, 1
beqz $t0, done # once we reach null char, finish
nop
j poploop
nop
done:
li $v0, 4
la $a0, str
syscall
li $v0, 10 # exit program
syscall
nop
.data
str: .space 82
prompt: .asciiz "Input a string:\n"
I am trying to write code that uses the MARS (my MIPS simulator) pseudorandom number generator to pick a random char in the string, take it out of memory and into a register, and replace that char in memory with an asterisk, '*'.
So far, it only scrambles part of the word, and it's driving me insane. I can't find what in this code isn't working. I don't even need a direct answer, just hints/tips would be SO helpful.
Here is the code:
#this loop extracts a char at random from a string in memory, stores it in a register, and replaces the char in the string with an asterisk '*'
.data
.align 2
string0: .ascii "Tyler\n"
.align 2
endString: .asciiz "Loop completed!\n"
.align 2
scrambleString: .asciiz
.text
#counter
li $t0, 5
#pointer to string0
la $s0, string0
loop2:
#is counter = 0? go to loop3 if so
beq $t0, $0, loop3
#seed & prepare randomized number generator
li $v0, 30
syscall
li $v0, 40 #sets seed
syscall
#generates random number in $a0, with the coUnter $t0 being the upper bound
addi $a1, $t0, 1
li $v0, 42
syscall
#add STRING POINTER by random number in $a0, store this new address in $t1
#addi $a0, $a0, 1
add $t1, $s0, $a0
#srlv $t1, $s0, $a0
#isolates that bytesized char, puts it into $t2
lbu $t2, ($t1)
#beq $t2, 0x5c, loop2
#replaces char in original string with "*"
li $t3, 0x2a
sb $t3, ($t1)
beq $t1, $t3, loop2
#decrement counter
addi $t0, $t0, -1
#loop return
j loop2
loop3:
la $a0, string0
li $v0, 4
syscall
li $v0, 10
syscall
You are resetting the random number seed on every iteration of
your loop (loop2:).
Syscalls 40 and 42 each take 2 parameters which should be in $a0 and
$a1. See here.
The temporary registers $t0,...,$t9 get altered by each
syscall. You should be using the callee saved registers
$s0,...$s8 instead.