Can someone explain some parts of this MIPS code to me? - 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
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.

Related

String input in MIPS omits the first four characters that are inputted

.data
EntryReq:
.asciiz "Please enter an 8 digit hexadecimal MIPS instruction: \n"
InputLongError:
.asciiz "\nYour input was too long, make sure it is 8 digits. "
InputShortError:
.asciiz "\nYour input was too short, make sure it is 8 digits. "
CharInvalidError:
.asciiz "\nYour input contains an invalid character. "
ValidChars:
.asciiz "0123456789abcdef\n\b\0"
.align 4
input:
.space 20
.text
main:
#Print input request
la $a0, EntryReq #loads input into arg. reg.
li $v0, 4 #op code for print string
syscall
#take input for input (stored)
li $v0, 8 #op code for take user input
la $a0, input #provide address for syscall
li $a1, 20 # tell syscall the byte space required for the string
syscall
#move to input(stored)
sw $v0, input #move inputted into from $v0 to input(stored)
#check validity of input
la $a0, input #load address of input to arg. reg. for method call
la $a1, ValidChars #load address of string of valid chars
jal verifyInput #call the verifyInput method which does as expected
#test if string length count works
addi $a0, $v0, 0 #load from $v0 to arg. reg.
li $v0, 1 #op code for print int
syscall
terminate:
li $v0, 10
syscall
verifyInput:
li $v0, -1 #start length count at 0
verifyLoop:
lb $t0, ($a0) #load current
li $a2, 0 #loop for char check, loops up to length of validChar string
la $a1, ValidChars
j checkChar
charVerified: #ignore this, is entry point back into verifyLoop for checkChar
addi $a0, $a0, 1 #increment
addi $v0, $v0, 1
bgt $v0, 8, printTooLongError #if result bigger than 8, error
bne $t0, 10, verifyLoop #10 is string end, so check if string is end
blt $v0, 8, printTooShortError #if result less than 8, error
jr $ra #if here string input was confirmed okay
checkChar: # loops through valid chars for each char in $a0 | Valid Chars: 0123456789abcdef\n |
lb $t1, ($a1) #loads in byte from char string
addi $a1, $a1, 1 #increment address, for the next char
addi $a2, $a2, 1 #increment until length of valid char string is reached
beq $t0, $t1, charVerified
bne $a2, 19, checkChar #if length of valid chars changes, change second argument here
j charNotValidError
charNotValidError:
la $a0, CharInvalidError #loads input into arg. reg.
li $v0, 4 #op code for print string
syscall
j terminate
printTooLongError:
la $a0, InputLongError #loads input into arg. reg.
li $v0, 4 #op code for print string
syscall
j terminate
printTooShortError:
la $a0, InputShortError #loads input into arg. reg.
li $v0, 4 #op code for print string
syscall
j terminate
The general gist of this code is for the user to input an 8 digit hexadecimal string, and then the program checks whether it is a valid hexadecimal string (i.e. includes only 0-9 and a-f). However, whenever I run it, the string that I input is missing the first four characters. So if I place invalid characters in the first four digits, like wwww1abc, then the code runs fine, which it shouldn't. But if I do 1abcwwww, it outputs an invalid character error, which it should. I'm genuinely confused as to why this is the case, nor have I seen anyone else experience this issue. Any help is greatly appreciated.
The problem is this line:
#move to input(stored)
sw $v0, input #move inputted into from $v0 to input(stored)
Unlike read integer syscall, read string puts the result in the input buffer, in your case input. So you don't need to read out the value in $v0 and by storing it in input you're overwriting the first 4 bytes of the buffer with the value of $v0, which is still 0x00000008, which conveniently is the same as the string "\b\0\0\0" for little endian machines, all of which are in your validity list. Removing that line should fix your program (though I didn't look over all the rest of the code for errors).

Need help troubleshooting MIPS code to count lowercase letters

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.

Push Each Character of a String Into a Stack MIPS

So I'm working on a project in MIPS to check if a string input by the user is a palindrome or not. The part I'm stuck on is reading the string and pushing each character of the string into the stack one by one (the PushLoop part of the code). When I debug it, the program seems to think I haven't entered anything at all. Here's what I have so far:
.text
main:
li $v0, 4 # Prints str1
la $a0, str1
syscall
jal Init # Sets $s0 equal to $sp to compare if the stack is empty later
li $v0, 8 # Read String
la $a0, buffer # Loads memory buffer (100)
li $a1, 100 # Defines length of buffer
syscall
la $t0, buffer # Moves base register to $t0
PushLoop:
lb $a2, ($t0) # Loads current character into $a2
beqz $a2, fin # if $a2 is equal to zero, the loop is terminated
jal Push # Pushes what is stored in $a0 to the stack
add $t0, $t0, -8 # Subtracts from buffer
j PushLoop
fin:
la $t0, buffer # Resets the memory buffer (I think)
PopLoop:
jal IsEmpty # Checks if the stack is empty
lb $a2, ($t0) # Loads current character into $a2
beq $v0, 1, isPal # If stack is empty, jump to isPal
jal Pop # Pops what is stored in the stack to $t1
add $t0, $t0, -8 # Subtracts from buffer
bne $a2, $t1, notPal
j PopLoop
notPal:
li $v0, 4 # Prints str3
la $a0, str3
syscall
li $v0, 0 # loads 0 into $v0
j end
isPal:
li $v0, 4 # Prints str2
la $a0, str2
syscall
li $v0, 1 # loads 1 into $v0
j end
#EXIT
end:
li $v0, 10 # ends the program
syscall
Push:
addi $sp, $sp, -8 # Move stack pointer
sb $a2, ($sp) # Store contents of $a2 at ($sp)
jr $ra
Pop:
lw $t1, ($sp) # Pop char from stack and store in $t1
addi $sp, $sp, 8 # Move stack pointer
jr $ra
Init:
add $s0, $sp, $zero # Sets $s0 equal to $sp
jr $ra
IsEmpty:
beq $sp, $s0, Yes # If $s0 is equal to the initial value of $sp, then stack is empty
li $v0, 0 # Loads 0 into $v0
jr $ra
Yes:
li $v0, 1 # Loads 1 into $v0
jr $ra
.data # Data declaration section
str1: .asciiz "Please enter a String: "
str2: .asciiz "Is a palindrome!"
str3: .asciiz "Is NOT a palindrome"
buffer: .space 100
I'm sure there are more things wrong with the code, but I'm just trying to squash one bug at a time. Thanks so much for helping me out!
You're not using syscall 8 properly:
li $v0, 8 # Read String
la $t0, buffer # Loads memory buffer (100)
syscall
If you read the description of syscall 8, it says "Arguments $a0 = buffer, $a1 = length". So those three lines of code should be changed into something like:
li $v0, 8 # Read String
la $a0, buffer
li $a1, 100
syscall
Then you can do la $t0, buffer after the syscall if you still want to use $t0 as the base register for the memory reads in PushLoop.

MIPS A String to Integer Conversion

Basically, I will read a string from console, which is no problem. The first and third characters in this string will be a 0-9 number and I want these numbers to store as ıntegers in memory to reuse later. I get "Exception occured at PC=0x0040004c" and when clicking abort I get "Unaligned address in store:0x100100c9".
What is the problem? Please, help!
EDIT:When I run step by step, error occurs in line 24.
.data
exp: .space 201 #allocate 200 bytes for logic expression to be read from stdin. +1 is for null char.
dimension: .space 8 #allocate 8 bytes for dimensions of environment
.text
main:
li $v0, 8 # load appropriate system call code into register $v0;
# code for reading string is 8
la $a0, exp # load address of string to be read into $a0
li $a1, 201 # load length of string to be read into $a1
syscall # call operating system to perform read operation
la $t0, exp
la $t1, dimension
add $t2,$zero,$zero
lb $t2, 0($t0)
addi $t2, $t2, -48
sw $t2, 0($t1)
li $v0, 10
syscall
You have to align the data at word boundary when storing a word.
For that you would have to use .align directive with parameter 2.
In your example dimension is not aligned because exp is 201 bytes length (not a multiple of 4). So you would have to use:
.data
exp: .space 201 #allocate 200 bytes for logic expression to be read from stdin. +1 is for null char.
.align 2 # Align data
dimension: .space 8 #allocate 8 bytes for dimensions of environment
.text

MIPS randomized word scrambler

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.

Resources