MIPS - How to perform a shift on a string? - string

I'm very new to MIPS programming, and I've been stuck on a problem I've been attempting to program. I realize what I'm trying to do may be silly, but bear with me please! Here's a description of what I'm attempting to do.
Let's say that I have this string: "~~Hello World!". I want to obtain the string "Hello World!" by shifting this string left by two characters. So far, my closest attempt at performing such an operation is this:
Let the register $t0 contain the string "~~Hello World!". I want to perform a left shift of 2 bits on this string and store in the register $t1.
.data
output1: .asciiz "The value in $t1 is: "
.text
sll $t1, $t0, 2 # attempt at shifting left by 2 bits
li $v0, 4
la $a0, output1
syscall # print "The value in $t1 is: "
li $v0, 4
move $a0, $t1
syscall # print the contents of the register $t1
However, when I assemble these instructions, I'm met with an address out of range error. Can anybody point out where I'm going wrong, and perhaps what I should do to achieve this?

I've figured it out! Here is an updated code snippet, which now contains the working instructions. I'll leave this post up in case it helps anybody else.
.data
output1: .asciiz "The value in $t1 is: "
.text
add $t0, $t0, 2 # shifts the string left by 2 bits (CORRECT)
li $v0, 4
la $a0, output1
syscall # print "The value in $t1 is: "
li $v0, 4
move $a0, $t1
syscall # print the contents of the register $t1

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).

MIPS not recognizing NULL

Forgive me for the easiness of this question but I am new to MIPS and am getting an odd error:
.data
myString: .asciiz "P5"
.text
li $v0 4
la $a0, myString
newLoop:
syscall
addi $a0, $a0, 1
beq $a0, $zero, done
j newLoop
done:
li $v0, 10
syscall
My program never terminates despite the fact that there is a null character (as I have gleaned from other posts, equivalent to $zero) at the end of myString. I would have thought that $a0 would point to "P", then "5", then "\0" and then jump to done and terminate.
Thanks for your eyes!
What you're comparing to zero is the address, not the value at that address. You need something like:
lbu $t0,($a0) # load the byte pointed to by $a0
beq $t0,$zero,done

MIPS (Bare Mode) String Won't Print

Recently while starting to learn MIPS in university, I've come across a problem while trying to print 1 string, accept a user input, and then print another string and accept a user input. Both user inputs should be stored to registers a0 and a1 respectively.
The names of each string are promptD for the Dividend input, and enterD for the Divisor input (you might guess this is an unsigned division calculator program).
In my debugging attempts, I have narrowed the problem to a small snippet of the code, posted below.
I think I am incorrectly offsetting my first .data register to reach my 2nd .data register. The problem I am noticing as I've tried QTspim, xspim, PCspim, and MARS is that all 4 of these give the first string in .data a different initial register address.
For example: The string "Enter Dividend" will be in reg address 0x10010000 in MARS but will start in 0x10000000 in PCspim. The following register address for "Enter Divisor" will be in either 0x10010011 in MARS or 0x10000010 in PCspim.
In its current state thru MARS, the program snippet below asks the user to input dividend, and it will store the value. Immediately after storing to a0, the code will fail due to a line 37 (which is just the 3rd syscall) runtime exception at 0x00400024: address out of range 0x00000004. It is not prompting "Enter Divisor" at all.
To really see the problem in action, I think running this in MARS would help make it more clear. Is it a offsetting issue? Am I clobbering a register without seeing it? I haven't found much MIPS help on here that deals with problems without pseudo-instructions. I realize with them, I could load an address directly (la)...but I can't use them here.
Thanks
.globl main
.data #for the data
promptD: .asciiz "Enter Dividend \n"
enterD: .asciiz "Enter Divisor \n"
# result: .asciiz "Result = "
.text #for the instructions
main:
#for Dividend
addi $v0, $0, 4 #store string instr to v0
lui $a0, 0x1001 #address of promptD
syscall #display promptD
addi $v0, $0, 5 #store input instr to v0
syscall # Get dividend
add $a0, $0, $v0 # Dividend to $a0
#for Divisor
addi $v0, $0, 4 #store string instr to v0
lui $a1, 0x1001 #Where I think the problem is...
#Address of first string followed by add offset?
addi $a1, $a1, 33 #Maybe incorrect offset?
syscall #display enterD
addi $v0, $0, 5 #store input instr to v0
syscall # Get divisor
add $a1, $0, $v0 # Divisor to $a1
#end snippet
Here's the problematic code:
lui $a1, 0x1001 #Where I think the problem is...
#Address of first string followed by add offset?
addi $a1, $a1, 33 #Maybe incorrect offset?
You're using the wrong register. The argument for syscall 4 should be placed in $a0, not $a1.
The offset 33 is incorrect. If you look at the Data Segment viewer in Mars you can see that the NUL-terminator byte for promptD is located at 0x10010010, and that the enterD string begins at 0x10010011 (if you have a hard time reading hexadecimal ASCII codes you can tick the "ASCII" checkbox in the Data Segment viewer to view the data as characters). So the offset you should be using is 0x11 (17 decimal).

Simple Integer to string/char in MIPS assembly? Print integer to text file?

Ok so I have an assignment where I have to find and print prime numbers.
I got that already complete, but now I need to print my results to a file.
Long story short, how do i print an integer to a file?
Long story
I can print integers and strings to the console, so I have my output like this:
1.) 2
2.) 3
3.) 5
...
I can print chars/strings just fine to a file, but all i can print is:
.)
.)
.)
....
Is there a way to convert or store an intger to a string in MIPS assembly? My assignment is not to do a MIPS version iota, so if there is a simple to just output an integer to file, I'd appreciate any insight.
I've read this page : MIPS File I/O Example
So that is how I learned to print strings to file, but i cannot find anything on how to print intgers that are calulated in the program. I've been looking since last night for an easy solution, but it escapes me.
This is the first MIPS assigment, we had to write a c program and then translate it to MIPS assembly, so I don't have too much experience so any help is appreciated.
Thanks in advance.
Here is the part of the code which I would like to work on, as you can see I'm trying to mirror what is desiplayed on the console in a text file. I'm using the MARS MIPS simulator.
FOR:
beq $t0, $t1, EndFOR
IF:
jal test_prime
bne $s1, 1, EndIF
addi $s0, $s0, 1 #Increment 'c'.
#Print 'c', the nth counted place of the found Prime Integer.
li $v0, 1
move $a0, $s0
syscall
sw $s0, buffer($0)
li $v0, 15
move $a0, $s7
la $a1, buffer
li $a2, 1
syscall
#Print '.) '
li $v0, 4
la $a0, dotP
syscall
li $v0, 15
move $a0, $s7
la $a1, dotP
li $a2, 3
syscall
#Print the Prime integer, 'i'.
li $v0, 1
move $a0, $t0
syscall
#Print a New Line.
li $v0, 4
la $a0, newL
syscall
li $v0, 15
move $a0, $s7
la $a1, newL
li $a2, 1
syscall
EndIF:
IF2:
beq $s0, 100, EndFOR #Once 100 Prime Integers have been found, escape out of the 'For' loop.
EndIF2: #Not Necessary, but just there to have a complete coding style.
addi $t0, $t0, 1 #Increment 'i'.
j FOR
EndFOR:
Assembly is all about appreciating high-level programming. You should try convert integer one by one to character and print them. You can turn this pseudo-code to assembly for this purpose (k is the integer number):
while(k){
char c = 0x03|((k%10)&0x0f);
push(c);
k=k/10;
}
while(c=pop()){
printf("%c",c);
}

Pig Latin in MIPS Assembly

In my MIPs Assembly Programming class I've been tasked with writing a program that converts a string into simplified pig latin.
Simplified pig latin assumes all words in the string are at least 2 characters long, and every word has its first letter shifted to the end followed by "ay". Also, assume there are no punctuation marks of any kind.
So, "stackoverflow is great" becomes "tackoverfloway siay reatgay".
I've taken a stab at this program and I'm nearly completed. It works fine, except that for some reason I have a line break in the middle of the last word every time.
For example:
tackoverflowsay siay reat
gay
Instead of:
tackoverflowsay siay reatgay
I've tried decuding what would be causing this line break in the last exit portion of my program but I don't see it. Do I have a pre-mature null terminated string? If I do, I don't see it.
Here is my code:
####################################################
# Text Segment
####################################################
.text
.globl main
main:
la $t0, char
la $t1, buffer
lb $t3, space
la $a0, prompt
li $v0, 4
syscall
la $a0, buffer
li $a1, 200
li $v0, 8
syscall
lb $t2, ($t1) # Load first char
addi $t1, $t1, 1
loop:
lb $t4, ($t1) # Load next character into $t4
addi $t1, $t1, 1
beqz $t4, exit # Reached end of string, exit?
beq $t3, $t4, loop2 # If $t4 = " " char, second loop
move $a0, $t4 # else, lets keep printing chars
li $v0, 11
syscall
j loop
loop2:
move $a0, $t2
li $v0, 11
syscall
la $a0, aystr
li $v0, 4
syscall
lb $t2, ($t1)
addi $t1, $t1, 1
j loop
exit:
move $a0, $t2
li $v0, 11
syscall
la $a0, aystr
li $v0, 4
syscall
li $v0, 10
syscall # Cya...
####################################################
# Data Segment
####################################################
.data
prompt: .asciiz "Enter Phrase: "
result: .asciiz "Pig Latin: "
space: .ascii " "
aystr: .asciiz "ay "
char: .byte 1
buffer: .byte 200
You almost certainly have a string of the form:
stackoverflow is great\n
where \n is a newline character. This would translate into:
tackoverflowsay siahy reat\ngay
if you simplistically detected the end of the word as either space or null-terminator.
I'm not going to give you the code (since this is homework) but the easiest solution, in my opinion, would be to have another loop processing the entire string, replacing all "\n" characters with spaces.
This would be done before your latinization loops.

Resources