Related
i write the following MIPS program that take 10 integers from user, then output (min value, max value, and average), then i added instructions to get the median(starting from line 72, from the comment # Calculate median), every time i run the program after entering the 10 numbers i get the following exception (Runtime exception at 0x004000e0: fetch address not aligned on word boundary 0x10010005).
.data
array: .space 40 #10 X 4(byte)
prompt: .asciiz "Please enter 10 random numbers :\n"
sort: .asciiz "\nThe descending order of the numbers are :\n"
sum: .asciiz "\n\nThe Sum of all numbers are : "
average: .asciiz "\n\nThe average of all the number is : "
max: .asciiz "\n\nThe maximum number is : "
min: .asciiz "\n\nThe minimum number is : "
space: .asciiz " "
dot: .asciiz "."
median: .asciiz "\n\nThe median of the numbers is: "
.text
.globl main
main:
li $v0, 4
la $a0, prompt #print out prompt
syscall
la $s0, array #load array into register s0
LoopInput:
li $v0, 5 #input numbers
syscall
sw $v0, 0($s0) # $v0 = i
addi $s0, $s0,4 #move array position
addi $t0, $t0,1 #loop array where i++
bne $t0, 10,LoopInput #for(t1=0;t1!=10;t1++) g
la $s0, array
sub $t0, $t0,$t0
Sorting: #sorting number from big to small
beq $t1,9, ConSort #if t1=9, go to conSort
lw $s1, 0($s0) #load the number in the first location into $s1
lw $s2, 4($s0) #load the number in the second location into $s2
addi $s0, $s0, 4 #update array position
addi $t1, $t1, 1 #move array position #for(s1=0;s1!=9;s1++)
bge $s1, $s2, Sorting #if s1>s2, back to sorting
sw $s1, 0($s0) #exchange position
sw $s2, -4($s0)
bne $t1, 9, Sorting #if t1!=9, go back to sorting
ConSort:
la $s0, array #continue sort with the same way
addi $t0, $t0, 1 #keep sorting the other numbers
addi $t1, $t0, 0
bne $t0, 9, Sorting #if t0!=9, go back to sorting
li $v0, 4 #print out prompt
la $a0, sort
syscall
la $s0, array
sub $t0, $t0, $t0
PrintSort:
li $v0, 1 #print sorting
lw $a0, 0($s0)
syscall
li $v0, 4
la $a0, space #print out prompt
syscall
addi $s0, $s0, 4
addi $t0, $t0, 1
bne $t0, 10, PrintSort #if t0!=10, go to printsort
# Calculate median
li $t4, 5 # t4 = 5
la $s0, array # s0 points to the beginning of the array
add $s0, $s0, $t4 # s0 points to the middle element of the array
lw $t5, 0($s0) # t5 = array[5]
li $v0, 4 # print message
la $a0, median # message to print: "The median of the numbers is: "
syscall
move $a0, $t5 # print median value
li $v0, 1 # print integer
syscall
sub $t0, $t0, $t0
sub $t1, $t1, $t1
sub $t2, $t2, $t2
sub $t3, $t3, $t3
la $s0, array #load array number to $s0
li $v0, 4 #print out prompt
la $a0, sum
syscall
SumA:
lw $t2, 0($s0) #load first $t2 to $s0
addi $s0, $s0,4 #update the array[s0] position
add $t3, $t2, $t3 #t3=t2+t3
addi $t0, $t0, 1 #t0= i++
bne $t0, 10, SumA #if t0!=10, go back to SumAll
move $a0, $t3 #move $t3 to $a0
li $v0, 1 #print out the sum of all numbers
syscall
li $v0, 4
la $a0, average #print out prompt
syscall
addi $t6, $t6, 10 #t6=10
div $t3, $t6 #t3=t3/10
mflo $s5 #move quotient to s5
mfhi $s3 #move remainder to s3
move $a0, $s5 #move s5 to a0
li $v0, 1 #print out quotient
syscall
li $v0, 4
la $a0, dot #print out dot
syscall
move $a0, $s3 #move s3to a0
li $v0, 1 #print out remainder
syscall
la $s0, array #load array into s0
li $v0, 4 #print out prompt
la $a0, max
syscall
lw $t5, 0($s0) #load number in array into t5
move $a0, $t5 #move t5 to a0
li $v0, 1 #print out number
syscall
li $v0, 4 #print out prompt
la $a0, min
syscall
lw $t4 , 36($s0) #load number in array into t4
move $a0, $t4 #move t4 to a0
li $v0, 1 #print out number
syscall
li $v0, 10
syscall #end of program
from my understating the problem caused by an attempt to access memory at an address that is not aligned on a word boundary.
Unlike C, assembly doesn't auto-scale your pointer arithmetic/array indexing. It seems you understand this, since you always use addi $s0,$s0,4 to advance to the next entry in your array, as an int on the 32-bit MIPS hardware takes up 4 bytes. The only place you made an error was here:
li $t4, 5 # t4 = 5
la $s0, array # s0 points to the beginning of the array
add $s0, $s0, $t4 # s0 points to the middle element of the array
Presumably, you want the middle value which is actually going to require you to use li $t4, 20. I'll use a chart below to explain this. I'll assume that your array is located at memory address 0x00000000 (it isn't, but it's just to make the demonstration a bit easier.) If, for example, the user inputs the numbers 2,3,4,5,6,7,8,9,10, and 11, this is what your array would look like in memory after being sorted (assuming a little-endian CPU)
0x00000000: 02 00 00 00
0x00000004: 03 00 00 00
0x00000008: 04 00 00 00
0x0000000C: 05 00 00 00
0x00000010: 06 00 00 00
0x00000014: 07 00 00 00 (this is what you will get when you load from offset 20)
0x00000018: 08 00 00 00
0x0000001C: 09 00 00 00
0x00000020: 0A 00 00 00 (ten)
0x00000024: 0B 00 00 00 (eleven)
Now since there are an odd number of values, you're going to have to average the two in the center. So you'll load from 0($s0) and -4($s0), add them, and bit shift right once.
I am very new to MIPs programming and have been struggling alone to solve to problem. I am in need of help from people of expertise, to help me through the way.
I am trying to build a program that takes in multiple integer inputs from the console and sort it through mergesort.
The problem is, though I believe logic is right, I keep on facing "Bad address in data/stack read: Ox...." error in the merge phase of the logic.
It would be of great help if you could help.
Thank you in advance.
.data
array: .space 40 # store max up to 10 elements integer array
eol: .asciiz "\n"
mess: .asciiz " Enter 10 numbers to be stored in the array. "
# Some test data
eight: .word 8
five: .word 5
four: .word 4
nine: .word 9
one: .word 1
seven: .word 7
six: .word 6
ten: .word 10
three: .word 3
two: .word 2
# An array of pointers (indirect array)
length: .word 10 # Array length
info: .word seven
.word three
.word ten
.word one
.word five
.word two
.word nine
.word eight
.word four
.word six
.text
main :
la $t0, 0
jal readInput
la $a0, array # Load the start address of the array
lw $t0, length # Load the array length
sll $t0, $t0, 2 # Multiple the array length by 4 (the size of the elements)
add $a1, $a0, $t0 # Calculate the array end address
jal mergesort # Call the merge sort function
# b sortend # We are finished sorting
b prdone
readInput :
slt $t1, $t0, 40
beq $t1, 1, readInputLoop
jr $ra
readInputLoop :
beq $t0, 40, readInput
# Printout the message for input
li $v0, 4
la $a0, mess
syscall
# Receive inputs from the user
li $v0, 5
syscall
sw $v0, array($t0)
li $v0, 1
lw $a0, array($t0)
syscall
# Increment the loop index by 4, and loop again
addi $t0, $t0, 4
b readInputLoop
##
# Recrusive mergesort function
#
# #param $a0 first address of the array
# #param $a1 last address of the array
##
mergesort:
addi $sp, $sp, -16 # Adjust stack pointer
sw $ra, 0($sp) # Store the return address on the stack
sw $a0, 4($sp) # Store the array start address on the stack
sw $a1, 8($sp) # Store the array end address on the stack
sub $t0, $a1, $a0 # Calculate the difference between the start and end address (i.e. number of elements * 4)
ble $t0, 4, mergesortend # If the array only contains a single element, just return
srl $t0, $t0, 3 # Divide the array size by 8 to half the number of elements (shift right 3 bits)
sll $t0, $t0, 2 # Multiple that number by 4 to get half of the array size (shift left 2 bits)
add $a1, $a0, $t0 # Calculate the midpoint address of the array
sw $a1, 12($sp) # Store the array midpoint address on the stack
jal mergesort # Call recursively on the first half of the array
lw $a0, 12($sp) # Load the midpoint address of the array from the stack
lw $a1, 8($sp) # Load the end address of the array from the stack
jal mergesort # Call recursively on the second half of the array
lw $a0, 4($sp) # Load the array start address from the stack
lw $a1, 12($sp) # Load the array midpoint address from the stack
lw $a2, 8($sp) # Load the array end address from the stack
jal merge # Merge the two array halves
mergesortend:
lw $ra, 0($sp) # Load the return address from the stack
addi $sp, $sp, 16 # Adjust the stack pointer
jr $ra # Return
##
# Merge two sorted, adjacent arrays into one, in-place
#
# #param $a0 First address of first array
# #param $a1 First address of second array
# #param $a2 Last address of second array
##
merge:
addi $sp, $sp, -16 # Adjust the stack pointer
sw $ra, 0($sp) # Store the return address on the stack
sw $a0, 4($sp) # Store the start address on the stack
sw $a1, 8($sp) # Store the midpoint address on the stack
sw $a2, 12($sp) # Store the end address on the stack
move $s0, $a0 # Create a working copy of the first half address
move $s1, $a1 # Create a working copy of the second half address
mergeloop:
lw $t0, 0($s0) # Load the first half position pointer
lw $t1, 0($s1) # Load the second half position pointer
###### SOURCE LOCATION OF THE PROBLEM #####
lw $t0, 0($t0) # Load the first half position value
lw $t1, 0($t1) # Load the second half position value
bgt $t1, $t0, noshift # If the lower value is already first, don't shift
move $a0, $s1 # Load the argument for the element to move
move $a1, $s0 # Load the argument for the address to move it to
jal shift # Shift the element to the new position
addi $s1, $s1, 4 # Increment the second half index
noshift:
addi $s0, $s0, 4 # Increment the first half index
lw $a2, 12($sp) # Reload the end address
bge $s0, $a2, mergeloopend # End the loop when both halves are empty
bge $s1, $a2, mergeloopend # End the loop when both halves are empty
b mergeloop
mergeloopend:
lw $ra, 0($sp) # Load the return address
addi $sp, $sp, 16 # Adjust the stack pointer
jr $ra # Return
##
# Shift an array element to another position, at a lower address
#
# #param $a0 address of element to shift
# #param $a1 destination address of element
##
shift:
li $t0, 10
ble $a0, $a1, shiftend # If we are at the location, stop shifting
addi $t6, $a0, -4 # Find the previous address in the array
lw $t7, 0($a0) # Get the current pointer
lw $t8, 0($t6) # Get the previous pointer
sw $t7, 0($t6) # Save the current pointer to the previous address
sw $t8, 0($a0) # Save the previous pointer to the current address
move $a0, $t6 # Shift the current position back
b shift # Loop again
shiftend:
jr $ra # Return
sortend: # Point to jump to when sorting is complete
# Print out the indirect array
li $t0, 0 # Initialize the current index
prloop:
lw $t1,length # Load the array length
bge $t0,$t1,prdone # If we hit the end of the array, we are done
sll $t2,$t0,2 # Multiply the index by 4 (2^2)
lw $t3,array($t2) # Get the pointer
lw $a0,0($t3) # Get the value pointed to and store it for printing
li $v0,1
syscall # Print the value
la $a0,eol # Set the value to print to the newline
li $v0,4
syscall # Print the value
addi $t0,$t0,1 # Increment the current index
b prloop # Run through the print block again
prdone: # We are finished
li $v0,10
syscall
Expected result would be printed integers of a sorted array, but i keep on receiving the error message of
"Exception occurred at PC=0x0040015c Bad address in data/stack read:
0x00000000".
I have some problem when I'm writing a sorting program in MIPS.
The function of this program is like this: Input 10 integers from keyboard and print them out, then sort them and print the sorted array again.
But the output is different from what I expect, some numbers are not sorted, would someone help me?
.data
str1: .asciiz "Please input integer numbers, maximum 10: \n"
str2: .asciiz "The 10 integer numbers you input are: \n"
str3: .asciiz "The numbers you entered are sorted as: \n"
array: .space 40
space: .asciiz " "
.text
.globl main
main:
la $t6, array #load the address of array into $t6
move $t7, $t6
addi $t7, $t7, 40 #point $t7 to the end of the array
jal readin
la $t6, array
la $a0, str2
li $v0, 4
syscall
jal print1 #print out the array before sort
la $t0, array #put the address of array into $t0
add $t0, $t0, 40 #put $t0 to the end of the array
move $t1, $zero #set $t1 as counter of the outerloop
li $t2, 10 #set $t2 as number of the outerloop
la $t3, array #put the address to $t3
jal innerloop
la $a0, str3
li $v0, 4
syscall
la $t3, array
#move $t7, $t3
#add $t7, $t7, 40
jal print2
li $v0, 10
syscall
innerloop:
lb $t4, 0($t3)
lb $t5, 4($t3)
bgt $t4, $t5, swap
addi $t3, $t3, 4
blt $t3, $t0, innerloop #if $t3 < $t0, keep in the innerloop to check two #neighbor numbers
jal outerloop #jump to outerloop if one round is finished
swap:
sb $t4, 4($t3)
sb $t5, 0($t3)
addi $t3, $t3, 4
#sll $t3, $t3, 2
blt $t3, $t0, innerloop #
jr $ra
outerloop:
la $t3, array
addi $t1, $t1, 1 #add the outerloop counter $t1 by one,
addi $t0, $t0, -1
blt $t1, $t2, innerloop #if $t1 < $t2, keep searching
jr $ra
readin:
la $a0, str1 #print str1
li $v0, 4
syscall
li $v0, 5 #read in the number
syscall
sb $v0, ($t6) #store the number in the array
add $t6, $t6, 4
blt $t6, $t7, readin
jr $ra
print1:
lb $a0, ($t6)
li $v0, 1
syscall
li $a0, 32
li $v0, 11 # syscall number for printing character
syscall
add $t6, $t6, 4
blt $t6, $t7, print1
jr $ra
print2:
lb $a0, ($t3)
li $v0, 1
syscall
li $a0, 32
li $v0, 11 # syscall number for printing character
syscall
add $t3, $t3, 4
blt $t3, $t0, print2
jr $ra
And the result in SPIM is like this:
Please input integer numbers, maximum 10:
44
Please input integer numbers, maximum 10:
11
Please input integer numbers, maximum 10:
33
Please input integer numbers, maximum 10:
22
Please input integer numbers, maximum 10:
66
Please input integer numbers, maximum 10:
55
Please input integer numbers, maximum 10:
99
Please input integer numbers, maximum 10:
77
Please input integer numbers, maximum 10:
88
Please input integer numbers, maximum 10:
24
The 10 integer numbers you input are:
44 11 33 22 66 55 99 77 88 24 The numbers you entered are sorted as:
11 33 22 44 55 66 77 88 24 32
Would someone please explain to me why there is a 32 in the end and why they are not sorted properly?
Hi I have to write a program in MIPS that does a bubble sort and then prints the sorted array and plays a note(s). I am having trouble getting it to execute in Mars and I am wondering what I need to add to my program:
.include "ec2_data.asm" # load values into array
add $s0, $zero, 0x10010000
add $t0, $zero, 0x10010000 #how many times to loop
addi $t1, $zero, 0 #initilize the counter
addi $t2, $zero ,0 #initilize position x
addi $t3, $zero, 4 #initilize position y
lw $s2, $t3($s0) #get second position of $s0=y
LOOP:
addi $t0, $t0, -1 #subtract one from the counter
slt $t4, $s1, $s2 #t4 set to 1 if x > y
beqz $t4, BREAK #if t0 is zero (x<y) we dont' have to sort, so go to break
# sort:
add $t5, $zero, $s1 #temp. stores the value of x in t5
add $s1, $zero, $s2 #moves the value of y into x
add $s2, $zero, $t5 #moves the value of x into y
sw $s1, $t2($s0) #save the new x to register
sw $s2, $t3($s0) #save the new y to register
j BREAK
BREAK:
#in here: check to see if we have reached the end
#if not, increment t2 and t3 by 4 to get the next values and jump back to loop to go again
beq $t0, $zero, END #if we are done with the array, go to end
addi $t2, $t2, 4
addi $t3, $t3, 4
j LOOP #jump back to loop again
END:
li $v0, 1 # print integer
syscall
addi $a0, $0, 0xA # load line code into register
addi $v0, $0, 0xB # print new line
syscall
addi $v0, $zero, 33 # midi out synchronous
addi $a0, $zero, 60 # Middle-C
addi $a1, $zero, 250 # ms
addi $a2, $zero, 120 # some instrument
addi $a3, $zero, 64 # some volume
add $a0, $t7, $zero # load value into $a0
syscall # play note!
addi $t6, $t6, 4 # shift memory location by 32 bits
addi $s1, $s1, 1 # increment counter ++
j loop # loop
Exit:
li $v0, 10 # load exit code
syscall # exit
If by "having trouble getting it to execute", you mean it acts strange with the .include file, then you might not have a required option checked in MARS. Go to the Settings menu and check the box for "Initialize Program Counter to global Main if defined". That seems to be something that has to be in effect for included files to work - and for some reason, it isn't turned on by default.
I'm stuck on an exercise, and am unsure how to proceed. This is the exercise:
Write a MIPS assembly language procedure, Test, that accepts 2 integers as arguments and
returns 0 if the integers are equal, 1 if the first is less than the second, and 2 if the first is greater
than the second.
Write a MIPS assembly language program that reads in 2 integers, calls the procedure Test, then
outputs one of the following messages:
The integers are equal
The first integer is less than the second
The first integer is greater than the second
What would be an example to carry this out? Mips is very confusing to me, as I'm used to Java. Thank you.
EDIT: Here is the program I am using as a foundation, since I am unsure where to start:
.data
str1: .asciiz "Please Enter Integer 1: " # a
str2: .asciiz "Please Enter Integer 2: " # a
str3: .asciiz "The sum is " # a
newline: .asciiz "\n" # g
.text
main: addi $v0, $zero, 4
la $a0, str1
syscall
addi $v0, $zero, 5
syscall
add $s0, $zero, $v0
addi $v0, $zero, 4
la $a0, str2
syscall
addi $v0, $zero, 5
syscall
add $s1, $zero, $v0
L1: beq $s1, $zero, cont
addi $v0, $zero, 1
add $a0, $s0, $zero
addi $s1, $s1, -1
syscall
j L1
cont: addi $v0, $zero, 4
la $a0, newline
syscall
addi $v0, $zero, 10
syscall
jr $ra
To check whether one register's value is smaller than another register's value, we can use the
set-on-less-than instruction, which also has a set-on-less-than-immediate counterpart.
slt $r0, $r3, $r4
()if r3 < r4, r0 is set to 1
else r0 is set to 0
slti $r0, $r3, 10
()if r3 < 10, r0 is set to 1
else r0 is set to 0
slt and slti are similar to beq or bne, however, there are two differences. First, they test
whether one value is smaller than another value and, second, they don't branch to some
address, but, instead, set a flag, stored in the first operand.