MIPS Help. Load Byte error. Address out of range - mips

I am trying to add numbers that are in base 5.
Im supposed to prompt the user for 2 separate base 5 number in the form XXXXXX.XXXXX, and then add them.
My current problem is that I am getting an error when I am loading the last digit into a register, so I can start the calculation.
please help! Thanks
.data
str: .space 13 # XXXXXX.XXXXX hold 12 chars + 0x00
str2: .space 13
sum: .space 14
printstr: .space 13
printstr2: .space 13
printsum: .space 14
message1: .asciiz "Enter a base 5 number A: "
message2: .asciiz "Enter a base 5 number B: "
message3: .asciiz "Sum of A and B: "
newline: .asciiz "\n"
.text
main:
#get number A
li $v0, 4
la $a0, message1
syscall
li $v0, 8
li $a1, 13
la $a0, str
syscall
li $v0, 4
la $a0, newline
syscall
#get number B
li $v0, 4
la $a0, message2
syscall
li $v0, 8
li $a1, 13
la $a0, str2
syscall
li $v0, 4
la $a0, newline
syscall
#pointer to input string A
la $s1, str
addi $s1, $s1, 12
#pointer to input string A
la $s2, str2
addi $s2, $s2, 12
#pointer to sum
la $s3, sum
addi $s3, $s3, 13
#other variables
li $t0, 0 # inital carry is 0
li $t1, 1 # counter for looping through string
li $t2, 5 # base 5
loop:
lb $t3, ($s1) ############################# PROBLEM HERE######
lb $t4, ($s2)
beq $t3, '.', next
beq $t4, '.', next
subi $t3, $t3, 0x30
subi $t4, $t4, 0x30
add $t5, $t3, $t4
add $t5, $t5, $t0
div $t5, $t2
mflo $t0
mfhi $t5
addi $t5, $t5, 0x30
sb $t5, ($s3)
subi $s1, $s1, 1
subi $s2, $s2, 1
subi $s3, $s3, 1
addi $t1, $t1, 1
ble $t1, 13, loop
addi $t0, $t0, 0x30
sb $t0, ($s3)
next:
subi $s1, $s1, 1
subi $s2, $s2, 1
#subi $s3, $s3, 1
addi $t1, $t1, 1
j loop
PRINT: #print the sum
exit:
li $v0, 10
syscall

You set up $s1 to point past str and decrement it backwards. Your loop: termination is the ble $t1,13,loop. When that completes, $s1 is pointing to the start of the .data section (i.e. 0x10010000).
But, then, you "fall through" to next: [probably wrong] and decrement $s1 so it has the value 0x1000ffff. Then, you do j loop so the fetch is now coming from an address one byte below the start of the .data segment (i.e. memory that does not exist)
That's the source of the crash. You probably need a jump inst after the ble to continue on to some other code.
But, also, when you do beq $t3,'.',next you go to next: and decrement both pointers. Unless you restrict your input there is no guarantee that both $s1 and $s2 both point to '.' at the same time, so you only want to decrement one of them. (e.g. suppose you had str: 12.3 and str2: 123.41)
So, you may need some code to align the two numbers with respect to their decimal points beforehand.

Related

Getting Memory out of bounds exception while running code in QTSPIM

I am trying an array to save i * j values and print the values from array.
I have two loops loop1, loop2, where loop1 takes i and loop2 takes on j.
I am trying to save the i * j in a myarray which is space datatype.
I am getting exception Memory address out of bounds and unable to find whats the error.
.data
myarray: .space 10000
n: .word 1
space_line: .asciiz " "
new_line: .asciiz "\n"
.text
.globl main
main:
lw $a0, n
la $a1, myarray
li $a2, -1 #row
li $t0, 0
li $t2, 0
loop1:
addi $a2, $a2,1
bge $a2, $a0, print_loop
li $a3, 0 #column
j loop2
loop2:
bge $a3, $a0, loop1
#multiply a2 and a3
mul $t1, $a2, $a3
sw $t1, 0($a1)
addu $a1, $a1,4
addi $a3, $a3,1
j loop2
print_loop:
mul $t3, $a0, $a0
bge $t0, $t3, exit
li $v0, 4
lw $a0, myarray($t2)
syscall
li $v0, 4
lw $a0, space_line
syscall
rem $t4, $t3, $a0
beqz $t4, newline
addu $t2, $t2, 4
addi $t0, $t0, 1
j print_loop
newline:
li $v0, 4
lw $a0, myarray($t2)
syscall
exit:
# Done, terminate program.
li $v0, 10
syscall # all done!
.end main
For n =4,i am expecting the output in console as
0 0 0 0
0 1 2 3
0 2 4 6
0 4 8 12
You can find this problem by single stepping in the debugger.  Start with the smallest possible input, like n=1 as you're showing.  After each instruction, verify that it did what you want, and that it didn't do anything else except what you wanted.
Here's a hint: Pay attention to the difference between la and lw.  Also, If you want to put syscalls in the middle of your code or loops, then avoid the $a0 and $v0 registers for your own variables — just makes things easier/better.

How to count the number of spaces in MIPS?

I need to write a program in which the output will be the number of sentences and average number of words. The code is working perfectly for counting the sentences, but for the second task, it doesn't work. I'm using branch if equal with the current char and the register in which I've declared the ascii value for space which is 32. With this code, the output for the average words is the total number of characters from the whole input. I can't understand how it can count every character when the beq is clearly incorrect. (I've also tried with emptySpace: .asciiz " ", but it's not working)
This is what I got so far:
.data
str_input: .space 256
dot: .asciiz "."
msg1: .asciiz "Number of sentences: "
msg2: .asciiz "\nAverage number of words: "
.text
li $v0, 8 #read string
la $a0, str_input #address of str_input vo $a0
li $a1, 256 #256 max
la $a2, dot
lb $a2, 0($a2)
li $a3, 32
syscall
addi $t4, $zero, 0 #counter for words
addi $t5, $zero, 0 #counter for sentences
or $t0, $a0, $zero #$t0 pointer to array
start:
lb $t1, 0($t0) #$t1 current char
beqz $t1, end
jal check
addiu $t0, $t0, 1
j start
chech:
beq $t1, $a2, IsDot
beq $t1, $a3, IsEmptySpace
IsDot:
addi $t5, $t5, 1
jr $ra
IsEmptySpace:
addi $t4, $t4, 1
jr $ra
end:
la $a0, msg1 #address of msg1 in $a0
li $v0, 4 #load string in $v0
syscall
add $a0, $t5, $zero
li $v0, 1
syscall #print number of sentences
addi $t4, $t4, 1 #add the last word
div $t4, $t5 #divide number of words with number of sentences
mflo $t6
la $a0, msg2 #address of msg2
li $v0, 4 #load string in $v0
syscall
add $a0, $t6, $zero
li $v0, 1
syscall

How to remove a character from string using native mips

This is a follow up of my previous question which I edited:
How to remove a comma from string input
I managed to fix the infinite loop, and found a way to increment through the string. My code now can, iterate through a string(eg. 123,456) find the address of the "," and stores in $t4.
But what I can't figure out is how to shift all the numbers towards the left to remove the "," from the string(should look like this in the memory 123,456 -> 123456)
I'm using native MIPS instructions. If you could help me out like that, I would really appreciate it.
.globl main
.globl main2
.globl main3
.globl firstNumCountChr
.globl firstNumIncrem
.globl secondNumCountChr
.globl secondNumIncrem
.globl thirdNumCountChr
.globl thirdNumInCrem
.data
prompt1: .asciiz "Enter first number:"
prompt2: .asciiz "Enter second number:"
prompt3: .asciiz "Enter third number:"
.text
# 0x10000000 will store first number
# 0x10000008 will store second number
# 0x10000010 will store third number
main:
#display prompt1
addi $v0, $0, 4
lui $a0, 0x1000
syscall
#Input first number
lui $a0, 0x1000
ori $a0, 0x0000 #reads number into memory(0x10000000)
addi $a1, $0, 8 #7 characters
addi $v0, $0, 8
syscall
#removing comma of first number
add $t1, $0, $0 #$t1 is the counter set to 0
add $t3, $0, 0x2c # 0x2c is acsii of "," in hex
firstNumCountChr:
lb $t2, 0($a0) #load first byte from address in $a0
beq $t2, $0, firstNumRemoveComma #if $t2 == 0 go to firstNumRemoveComma
or $0, $0, $0 #NOP
bne $t2, $t3, firstNumIncrem #branch if symbol doesn't equal ","
or $0, $0, $0
add $t4, $a0, $0 #$t4 will save position of ","
firstNumIncrem:
addi $a0, $a0, 1 #increment address
addi $t1, $t1, 1 #increment counter
j firstNumCountChr #loop
firstNumRemoveComma:
beq $t4, $0, main2 #branch if $t4 == 0 (no comma) to main2
or $0, $0, $0 #NOP
main2:
#display prompt2
addi $v0, $0, 4
lui $a0, 0x1000
addi $a0, $a0, 20
syscall
#inputing second number
lui $a0, 0x1000
ori $a0, 0x0008 #reads number into memory(0x10000008)
addi $a1,$0, 8 #7 characters
addi $v0, $0, 8
syscall
#removing comma of second number
addi $t1, 0 # $t1 is the counter set to 0
add $t3, 0x2c # 0x2c is acsii of "," in hex
secondNumCountChr:
lb $t2, 0($a0) # load first byte from address in $a0
beq $t2, $0, end # if $t2 == 0 go to end
or $0, $0, $0 # NOP
bne $t2, $t3, secondNumIncrem # branch if symbol doesn't equal ","
or $0, $0, $0 # NOP
add $t4, $a0, $0 # $t4 will save position of ","
secondNumIncrem:
addi $a0, $a0, 1 #increment address
addi $t1, $t1, 1 #increment counter
j secondNumCountChr #loop
main3:
#display prompt3
addi $v0, $0, 4
lui $a0, 0x1000
addi $a0, $a0, 41
syscall
#inputting third number
lui $a0, 0x1000
ori $a0, 0x0010 #reads number into memory(0x10000010)
addi $a1, $0, 8 #7 characters
addi $v0,$0, 8
syscall
#removing comma of third number
addi $t1, 0 #$t1 is the counter set to 0
add $t3, 0x2c # 0x2c is acsii of "," in hex
thirdNumCountChr:
lb $t2, 0($a0) #load first byte from address in $a0
beq $t2, $0, end # if $t2 == 0 go to end
or $0, $0, $0
bne $t2, $t3, thirdNumInCrem # branch if symbol doesn't equal ","
or $0, $0, $0
add $t4, $a0, $0 # $t4 will save position of ","
thirdNumInCrem:
addi $a0, $a0, 1 #increment address
addi $t1, $t1, 1 #increment counter
j thirdNumCountChr #loop
end:
add $0, $0, $0

Converting C code to mips gives error

This is the C code that i have been converted so far. it gives me some error that i have been included in the following code. i don't understand which part is wrong in this c to mips conversion?
char ch[10];
int i;
for (i = 0; i != 10; i++)
ch[i] = ch[i] – 32
.data
.text
li $v0 4
syscall
#$s1 = i, $s0 base address of ch
addi $s1, $0, 0 #i =0
addi $t0, $0, 10 #t0 = 10
loop: beq $t0, $s1, end
add $t1, $s1, $s0
lw $t2, 0($t1)
addi $t2, $t2, -32
sw $t2, 0($t1)
addi $s1, $s1, 1
j loop
end:
My output:
Runtime exception at 0x00400018: address out of range 0x00000000
From the C code you are converting a char type array and in MIPS you should use lb instead of lw.
In order to print out you need a main: label and also you should declare an array like .byte or .space
You should usesyscall 11 to print a character or syscall 4 to print
string.
I have added some of these mentioned above to your code hope it helps.
.data
#ch: .byte 'a','b','c','d','e'
ch: .space 10
.text
main:
li $v0, 8 #read character
li $a1, 10 #load the space
la $a0, ch
syscall
li $v0,11 #print character
syscall
li $v0,10 # exit program
syscall
addi $s1, $0, 0 #i = 0
addi $t0, $0, 10 # $t0 = 10
loop: beq $t0, $s1, end
add $t1, $s1, $s0
lb $t2, ch($t1)
addi $t2, $t2, -32
sb $t2, ch($t1)
addi $s1, $s1, 1
j loop
end:

Trouble with MIPS array

i'm trying to write some code that take as input integers and strings, stores them into an array and then prints them in order (int-string, int-string etc.). I will eventually add some sorting code for the integer, when i get this to work. The problem is i can't get the code to work right, i can't manage to have the output come out correctly. I'm assuming the problem lies in the array, since i'm not sure how it is supposed to work (MIPS is definitely not my forte). The code is the following:
.data
array: .space 400 #array
in_name:
.asciiz "\nInsert name: "
in_date:
.asciiz "\nInsert date (mmdd): "
appt:
.asciiz "\nList: "
spaz: .asciiz " "
.text
main:
la $s0, array #load array in s0
addi $t0, $zero, 0 #t0=0 counter
addi $s1, $zero, 0 #s1=0 array size counter
j Input
Input:
li $v0, 4
la $a0, in_date
syscall #ask date
li $v0, 5
syscall #read date
add $t1, $zero, $t0 #offset in t1
add $t1, $t1, $t1 #t1*2
add $t1, $t1, $t1 #t1*4
add $s2, $t1, $s0 #array with offset in s2
sw $v0, 0($s2) #save date
addi $t0, $t0, 1 #t0++
addi $s1, $s1, 1 #array size counter +1
li $v0, 4
la $a0, in_name
syscall #ask name
li $a0, 4
li $v0, 9
syscall #space for new word (4bytes)
la $a0, array
li $a1, 4
li $v0, 8
syscall #read name
add $t1, $zero, $t0 #offset in t1
add $t1, $t1, $t1 #t1*2
add $t1, $t1, $t1 #t1*4
add $s2, $t1, $s0 #array with offset in s2
sw $v0, 0($s2) #save name
addi $s1, $s1, 1 #array size counter +1
addi $t0, $t0, 1 #t0++
beq $s1, 10, print #if array size=10 go to print
j Input #start over until s1=10
print:
la $a0, appt
li $v0, 4
syscall #print list
addi $t0, $zero, 0 #t0=0 counter
res:
add $t1, $zero, $t0 #offset in t1
add $t1, $t1, $t1 #t1*2
add $t1, $t1, $t1 #t1*4
add $s2, $t1, $s0 #array with offset in s2
lw $a0, 0($s2) #load date
li $v0, 1
syscall #print data
addi $t0, $t0, 1 #t0++
la $a0, spaz #load space
li $v0, 4
syscall #print space
add $t1, $zero, $t0 #offset in t1
add $t1, $t1, $t1 #t1*2
add $t1, $t1, $t1 #t1*4
add $s2, $t1, $s0 #array with offset in s2
lw $a0, 0($s2) #load name
li $v0, 4
syscall #print name
addi $t0, $t0, 1 #t0++
la $a0, spaz
syscall #print space
addi $t0, $t0, 1 #t0++ counter
bne $t0, $s1, res #start over until t0=s1
j end
end:
li $v0, 10
syscall #the end
Depending on which program i use to test it i get an error or the program ends correctly but with a wrong output (just some numbers).
Can someone point out to me how should i correct it to make it work properly?
Thanks
I changed the program a little. I created 2 arrays for numbers and strings. As I read date and name I save them to num_array and str_array respectively. This makes it easier to deal with addressing, and might be easier for processing later. Comments in the code should be helpful.
.data
num_array: .space 400 #array
str_array: .space 400
in_name: .asciiz "\nInsert name: "
in_date: .asciiz "\nInsert date (mmdd): "
appt: .asciiz "\nList: "
spaz: .asciiz " "
.text
main:
la $s0, num_array #load array in s0
la $s1, str_array
addi $t0, $zero, 0 #t0=0 counter
addi $s2, $zero, 0 #s1=0 array size counter
j Input
Input:
# prompt for date
li $v0, 4
la $a0, in_date
syscall
# read date
li $v0, 5
syscall
# store date in the num_array
sw $v0, 0($s0)
# increment counter and move to next position in the array
addi $t0, $t0, 1
addi $s2, $s2, 1
addi $s0, $s0, 4
# prompt for name
li $v0, 4
la $a0, in_name
syscall #ask name
# store name (max 4 bytes) to str_array ($s1)
move $a0, $s1
li $a1, 4
li $v0, 8
syscall #read name
# move to the beginnig of next string in $s1
# increment by 4 because length of each input word is 4
addi $s1, $s1, 4
beq $s2, 10, print #if array size=10 go to print
j Input #start over until s1=10
print:
# print "List:"
la $a0, appt
li $v0, 4
syscall #print list
addi $t0, $zero, 0 #t0=0 counter
la $s0, num_array # address of num_array
la $s1, str_array # address of str_array
res:
# get number from num_array and print it
lw $a0, 0($s0)
li $v0, 1
syscall
# move to the next element, increment by 4 because numbers take 1 word = 4 bytes
addi $s0, $s0, 4
# get string from str_array and print it
la $a0, 0($s1)
li $v0, 4
syscall
# print space
la $a0, 32
li $v0, 11
syscall
# move to the next element, increment by 4 because strs have 4 bytes length (in your case)
addi $s1, $s1, 4
# increment loop counter
addi $t0, $t0, 1
blt $t0, $s2, res # $s2 is size of the array
end:
li $v0, 10
syscall #the end
Here is the output:
Insert date (mmdd): 1201
Insert name: aaa
Insert date (mmdd): 1202
Insert name: bbb
Insert date (mmdd): 1203
Insert name: ccc
Insert date (mmdd): 1204
Insert name: ddd
Insert date (mmdd): 1205
Insert name: eee
Insert date (mmdd): 1206
Insert name: fff
Insert date (mmdd): 1207
Insert name: ggg
Insert date (mmdd): 1208
Insert name: hhh
Insert date (mmdd): 1209
Insert name: iii
Insert date (mmdd): 1210
Insert name: jjj
List: 1201aaa 1202bbb 1203ccc 1204ddd 1205eee 1206fff 1207ggg 1208hhh 1209iii 1210jjj
-- program is finished running --