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
Related
I'm having trouble reading a string that previously was introduced by the user and saved in memory.
The function to read the string:
.data
table: .space 1200
buffer: .space 30
empty: .asciiz "The string is empty\n"
.text
la $t7,table
li $s4,0
li $v0, 8
la $a0,buffer
li $a1, 30
syscall
move $t0,$a0
move $a0,$t0 # parameter
jal insert
Then using the readed string, I pass through $a0 as a parameter to another function that stores the string to a certain memory position (with 60 bytes space within each string).
insert: mul $s6,$s4,60 # padding (index*padding)
add $t7,$t7,$s6 # address of the next free position
sw $a0,0($t7)
addi $s4,$s4,1
Also I've got a function that given an index (introduced by the user as an integer), recovers the string stored in that position (if is not empty):
read_table: move $t5,$a0 # a0 contains the index as a parameter
la $t4, table
mul $t5,$t5,60
add $t4,$t4,$t5
lw $s1,0($t4)
beqz $s1,empty_str
li $v0,4
move $a0,$s1
syscall
empty_str: li $v0,4
la $a0,empty
syscall
My problem comes when regardless of the index I enter, the program always return the last string introduced by the user although it seems to be stored properly. I understand that it might be some misuse of the buffer, but any of the solutions I've thought worked.
[EDIT] Here goes the whole code block to clarify the question, as suggested (supposing that all the data that the user introduces is OK):
):
.data
table: .space 1200
buffer: .space 30
empty: .asciiz "The string is empty\n"
.text
la $t7,table
li $s4,0
main: li $v0,4
la $a0,tira1
syscall
li $v0,5
syscall
beqz $v0,index # If 0, read from table, 1 insert to the table
beq $v0,1,string
string: li $v0, 8
la $a0,buffer
li $a1, 30
syscall
move $t0,$a0
move $a0,$t0 # parameter
jal insert
index: li $v0,5 # function to get index
syscall
move $a0,$v0
jal read_table
insert: mul $s6,$s4,60 # padding (index*padding)
add $t7,$t7,$s6 # address of the next free position
sw $a0,0($t7)
addi $s4,$s4,1
b main
read_table: move $t5,$a0 # a0 contains the index as a parameter
la $t4, table
mul $t5,$t5,60
add $t4,$t4,$t5
lw $s1,0($t4)
beqz $s1,empty_str
li $v0,4
move $a0,$s1
syscall
b main
empty_str: li $v0,4
la $a0,empty
syscall
.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).
I have written a MIPS assembly language code using sw instruction so that I can only replace the 1st character of a string with a character of my choice.
But, what happens is, the instead of only changing one character, the code changes the 1st character plus destroys characters in next three bytes.
How can I get it right?
I have written the following code:
# replace 1st character of a string
.data
string: .asciiz "ABCDEFGH"
.text
main:
# load string's 1st address into the memory
la $a0, string
li $t0, 'X'
#addi $t0,$t0, 48
sw $t0, ($a0)
# print string
la $a0, string # load 1st address of the string
li $v0, 4 # syscall for string print
syscall
# exit program
li $v0, 10
syscall
Input: ABCDEFGH
Expected result: XBCDEFGH
Actual result: X
You incorrectly use sw that stores a word, ie a 4-bte data.
In your algorithm, after the instruction
li $t0, 'X'
you write 'X' as a 32 bits word in your t0 register. Probably your machine is configured as little endian and $t0, that is a 32 bits register holds the value 0x00000058 (0x58 is the ascii code of X).
When you write it to memory with sw $t0, ($a0), all the 32 bits are written and the content of your memory, that was originally "ABCDEFGH" becomes "X\0\0\0EFGH".
When you ask to print it, the '\0' at position string+1 is considered as an end-of-string terminator and you have just 'X' displayed.
The fix is just to replace the line with
sw $t0, ($a0)
with
sb $t0, ($a0)
and only the least significant byte of your register (ie 'X') is written to memory.
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).
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.