Bubble Sort in MIPS - sorting

I am trying to sort an array of integers in MIPS using bubble sort but every time that I run bubble sort I get an address out of range error. I have been staring at the code for hours and have no idea why this is happening. Hopefully' it is something really obvious that someone with more experience can see and help me fix.
The point of the program is simply to read in integers and symbols (price of stock, and stock symbol) and then sort those based on the prices. Here is the code:
.data
welcome: .asciiz "Welcome!\n"
prompt1: .asciiz "Enter how many stocks you have.\n >"
prompt2: .asciiz "Enter the four character NASDAQ abbrevation and price for each stock.\n"
prompt3p1: .asciiz "You have entered "
prompt3p2: .asciiz " stock abbreviations and prices. How many stocks do you want to buy:\n"
prompt4: .asciiz "How many stocks do you want to sell:\n"
InfoPrompt: .asciiz "Here are the symbols and the corresponding numbers that were entered: \n"
numStocks: .word 0
stockPrice: .space 40 # this will be the list of the stock prices
stockSymbol: .word 0:20 # this will be for the lit of stock abbrevs
symbols: .space 12 #this should be used for a 40 character array
inputFormat: .asciiz "\n> "
length: .word 0
buffer: .space 4
.globl main
.text
main: # display all of the propts
li $v0, 4 # get ready to print welcome
la $a0, welcome
syscall # print welcome
li $v0, 4 # not sure this is necessary since it was already loaded into v0 before
la $a0, prompt1
syscall # print("enter how many stocks you have.")
li $v0, 5 # this will get ready to accept the number of stocks
syscall # this should store the number into the $v0 register
sw $v0, numStocks # store in memory so we dont lose it
move $t0, $v0 # this will hold the num of stocks
#before we go into the procedure we need to declare and move the stack for the $t registers.
la $t1, symbols
la $t2, stockPrice
sub $sp, $sp, 8
sw $t1, 0($sp)
sw $t2, 4($sp)
jal getInfo
# now that we have all the information lets run a test to see how successful we were
# jal printInfo
li $v0, 4 #get ready to ask how many items you want to buy
la $a0, prompt3p1
syscall
li $v0, 1
lw $a0, numStocks # prints the number of stocks in the portfolio
syscall
li $v0, 4
la $a0, prompt3p2
syscall
# we need to now get the number of stocks the person wants to buy
li $v0, 4
la $a0, inputFormat
syscall #format the next input
li $v0, 5
syscall
move $t3, $v0 # the number of stocks we want to buy is now stored as $t3
#we need to get how many they want to buy
li $v0, 4
la $a0, prompt4
syscall
li $v0, 4
la $a0, inputFormat
syscall #format the next input
li $v0, 5
syscall
move $t4, $v0 # the number of stocks that you want to sell
# now we have to sort the list to figure out what elements we are going to sell and buy
la $a2, stockPrice
la $a0, stockPrice
la $a1, numStocks
jal buble_sort
jal printInfo
# end program
li $v0,10 #load the syscall number for terminating
syscall #terminate
####################################################################
# This will iterate for the number of stocks
# Only accepts the number of stocks
####################################################################
getInfo:
sub $sp, $sp, 8
sw $ra, 0($sp) # store the return value
sw $t0, 4($sp) # Save the t registers that we will be using
li $v0, 4 # set up the first call to initialize the calls for the abbreviations and numbers
la $a0, prompt2
syscall
# we want to have a place to store the symbols
la $t1, symbols
la $t2, stockPrice
GI_loop:
beq $t0, $zero, GI_loop_done # if the counter == 0 then we are done
li $v0, 4
la $a0, inputFormat
syscall #format the next input
# ask for the string input
li $v0, 8
la $a0, 0($t1)
li $a1, 6
syscall
#store the value in the array
addi $t1, $t1, 6 #increment our "array"
# ask for the integer input
li $v0, 4
la $a0, inputFormat
syscall #format the next input
li $v0, 5
syscall # get the integer value that we require
sw $v0, 0($t2) #store the value
addi $t2, $t2,4 #increment our counter
addi $t0, $t0, -1 # decrement our counter
j GI_loop
GI_loop_done:
lw $ra, 0($sp)
lw $t0, 4($sp)
lw $t1, 8($sp)
lw $t2, 12($sp)
add $sp, $sp, 8
jr $ra
####################################################################
# This will go through the lists and print out what was stored
# will go through the symbols then the numbers
####################################################################
printInfo:
sub $sp, $sp, 12
sw $ra, 0($sp)
sw $t0, 4($sp) # this will store the number of stocks that were entered
sw $t1, 8($sp)
li $v0, 4
la $a0, InfoPrompt
syscall
# we know that $t0 stores the correct number that was originally enetered so we need to loop through and print all the integers
InfoLoop:
beq $t0, $zero, InfoLoopDone # a basic counter check
#li $v0, 4
#la $a0, 0($t1)
#syscall
#addi $t1, $t1, 6
#addi $t0, $t0, -1
#j InfoLoop
################################### INTEGER PRINT WORKING
li $v0, 1 # this will print out the integers
lw $a0, 0($t2) # we have to load the world that is found in the address of $t2
syscall
addi $t2,$t2, 4 # this will increment the array
addi $t0, $t0, -1 ## this will fix our counter
j InfoLoop
InfoLoopDone:
lw $ra, 0($sp)
lw $t0, 4($sp)
add $sp, $sp, 8
jr $ra
################################
# BUBBLE SORT
################################
buble_sort:
#a0=address of table
#a1=sizeof table
add $t0,$zero,$zero #counter1( i )=0
loop1:
addi $t0,$t0,1 #i++
bgt $t0,$a1,endloop1 #if t0 > a1 break;
add $t1,$a1,$zero #counter2=size=6
loop2:
bge $t0,$t1,loop1 #j < = i
#slt $t3,$t1,$t0
#bne $t3,$zero,loop1
addi $t1,$t1,-1 #j--
mul $t4,$t1,4 #t4+a0=table[j]
addi $t3,$t4,-4 #t3+a0=table[j-1]
add $t7,$t4,$a2 #t7=table[j]
add $t8,$t3,$a2 #t8=table[j-1]
lw $t5,0($t7)
lw $t6,0($t8)
bgt $t5,$t6,loop2
#switch t5,t6
sw $t5,0($t8)
sw $t6,0($t7)
j loop2
endloop1:
jr $ra

Your problem is in the statement before calling your bubble sort routine:
la $a1, numStocks
It will load the address where the number of stocks are saved, not the number of stocks itself.
You should change it with
lw $a1, numStocks

Related

Runtime exception at 0x0040002c: address out of range 0x00000001 in MIPS Assembler for ceasar encryption

The Programm compiles just fine but as soon as i give input this error is thrown:
"Error in line 28: Runtime exception at 0x0040002c: address out of range 0x00000001
Processing terminated due to errors."
Here ist the code for my programm:
.data
line: .space 80
.text
main:
# read line from stdin
li $v0, 8
la $a0, line
li $a1, 80
syscall
# call caesar_line
li $a0, 1
jal caesar_line
# return 0
li $v0, 0
jr $ra
caesar_line:
# save start of line
move $t0, $a0
# loop through line
loop:
# load the character from memory
move $t1, $a0
lb $a0, 0($t1)
beqz $a0, end_loop
jal caesar_char
sb $v0, 0($t1)
addi $t1, $t1, 1
move $a0, $t1
j loop
end_loop:
# print line
li $v0, 4
move $a0, $t0
syscall
jr $ra
caesar_char:
# check if c is lowercase
blt $a0, 'a', upper
bgt $a0, 'z', not_alpha
addi $a1, $a1, 'a'
jal caesar_helper
j done
upper:
# check if c is uppercase
blt $a0, 'A', not_alpha
bgt $a0, 'Z', not_alpha
addi $a1, $a1, 'A'
jal caesar_helper
j done
not_alpha:
# not an alphabetical character
move $v0, $a0
j done
caesar_helper:
# subtract base from c
sub $t0, $a0, $a2 # $t0 = c - base
# add distance + 26 to c
addi $t0, $t0, 26 # $t0 += 26
add $t0, $t0, $a1 # $t0 += distance
# calculate c % 26
li $t1, 26 # $t1 = 26
div $t0, $t1 , $t1 # $lo = c % 26
mflo $t0
# add base to c
add $v0, $t0, $a2 # $v0 = c + base
done:
jr $ra
Not even ChatGBT could find an error.
The code should shift all chars of an string by a certain amount, but as soon as it is run the error above is thrown.

I have to multiply the digits as well as adding them.,

.data
enterMsg1: .asciiz "Please enter the last four digits of your student id \n"
enterMsg2: .asciiz "Press enter between each digit \n"
enterMsg3: .asciiz "Enter next digit \n"
TotalDig4: .asciiz "The total of the digits is: "
.text
# output the initial instruction text to the console
addi $v0, $zero, 4
la $a0, enterMsg1
syscall
# output the second instruction text to the console
addi $v0, $zero, 4
la $a0, enterMsg2
syscall
# read an integer from keyboard input and store the input in $s0 for the total
addi $v0, $zero, 5
syscall
# store the input in $s0
add $s0, $zero, $v0
# output the text asking for the next digit to the console
# then receive the input,
jal receiveInputs
#add to total ($s0)
add $s0, $s0, $v0
# then receive the input,
jal receiveInputs
#add to total ($s0)
add $s0, $s0, $v0
# then receive the input,
jal receiveInputs
#add to total ($s0)
add $s0, $s0, $v0
# output the total text to the console
addi $v0, $zero, 4
la $a0, TotalDig4
syscall
add $a0, $s0, $zero
addi $v0, $zero, 1
syscall
addi $v0, $zero, 10
syscall
receiveInputs:
# receive the input, add to total ($s0)
addi $v0, $zero, 4
la $a0, enterMsg3
syscall
addi $v0, $zero, 5
syscall
jr $ra
Loop:
add $s0, $zero, $s0
addi $a0, $zero, 1
syscall
# output a space
addi $v0, $zero, 10
addi $a0, $zero, 0x20
syscall
addi $s0, $s0, -1
# end the program
addi $v0, $zero, 10
After adding the first digit to $s0, on the next line add that same first digit from $v0 to $s1 which will hold your product.
Then after getting each digit from the function receiveInputs use (mul $s1, $s1, $v0) to multiply the digits.
Finally print the result from $s1 just as you would for the sum.

Changing ascending sort to descending in MIPS assembly

I know that in c or java the quick fix to changing an ascending sort to descending would be to find the < or > somewhere and reverse it. But try as I might, I can't find the equivalent (or equivalent swap) to change this code that I've written to be descending instead of ascending. (Right now, it works perfectly in printing the linkedlist in ascending order). There's a fair 100 or so lines above what I've included that I cut out as they don't do the sort, but they assign values--so that isn't the problem. I feel like I'm just missing something obvious? Would the change be in the way I print or the way I insert or both? Any help would be appreciated.
loop_to_find_correct_spot:
beqz $t0, if_current_node_next_equals_null
l.s $f0, 0($t0)
c.lt.s $f12, $f0
bc1t if_current_node_does_not_equal_null
or $t1, $t0, $zero
lw $t0, 4($t0)
j loop_to_find_correct_spot
if_current_node_next_equals_null:
# link this node to the previous, $v0 = &(previous node)
# copy address of the new node into the previous node
sw $v0, 4($t1)
# initalize the current node value to the passed in argument on the $f12 register
swc1 $f12, 0($v0)
# initalize the current node next value to null
sw $zero, 4($v0)
j end_insert_if_else
if_current_node_does_not_equal_null:
# initalize the current node value to the passed in argument on the $f12 register
swc1 $f12, 0($v0)
sw $v0, 4($t1)
sw $t0, 4($v0)
j end_insert_if_else
end_insert_if_else:
lw $ra, 0($sp)
addi $sp, $sp, 4
jr $ra
allocate_memory_for_node:
addi $sp, $sp, -4
sw $ra, 0($sp)
# allocate 12 bytes in memory for the new node
li $v0, 9
li $a0, 8
syscall
lw $ra, 0($sp)
addi $sp, $sp, 4
jr $ra
print_linked_list:
addi $sp, $sp, -4
sw $ra, 0($sp)
lw $s0, head # get a pointer to the head node
lw $s0, 4($s0)
begin_loop_print_linked_list:
# while (next != null)
beqz $s0, end_loop_print_linked_list
# get the value for the current node
l.s $f12, 0($s0)
# print out current item
li $v0, 2
syscall
la $a0, end_line_prompt #puts newlines in printed list
li $v0, 4
syscall
#get the pointer to the next node
lw $s0, 4($s0)
b begin_loop_print_linked_list
end_loop_print_linked_list:
lw $ra, 0($sp)
addi $sp, $sp, 4
jr $ra

comparing a string in MIPS

Could someone tell me what is wrong with my code so far. I am trying to make a program that takes input from the user (roman numerals) and then converts it to integers. So far this is what I have:
.data
buffer: .space 20
onlyCaps: .asciiz "Please enter only Capital Numbers\n"
enter1: .asciiz "Number out of range. Please enter another number\n"
enter2: .asciiz "Please enter your roman numeral: "
debug: .asciiz "reach"
M: .asciiz "1000"
D: .asciiz "500"
C: .asciiz "100"
L: .asciiz "50"
X: .asciiz "10"
V: .asciiz "5"
I: .asciiz "1"
.text
main:
la $a0, onlyCaps # "Enter Only Capital numbers"
li $v0, 4
syscall
la $a0, enter2 #prompt user with "Please enter a roman numeral:"
li $v0, 4
syscall
la $a0, buffer #load byte space into address
li $a1, 3 # allot the byte space for string
li $v0, 8 #read user input, j
syscall
li $t4, 1
loop:
lb $t0, 0($a0) # Save $v0 value to $t0
beqz $t4, done # if it is equal to zero end the loop
add $a0, $a0, $t4 #increment the address
j mCheck
#while loop ends here
mCheck:
beq $t0, 'M', mChar # if $t0 equal M go to mChar
bne $t0, $t1, dCheck # move to see if equals D
dCheck:
beq $t0, 'D', dChar # if $t0 equal D go to dChar
bne $t0, $t1, cCheck
cCheck:
beq $t0, 'C', cChar # if $t0 equal C go to cChar
bne $t0, $t1, lCheck
lCheck:
beq $t0, 'L', lChar # if $t0 equal L go to lChar
bne $t0, $t1, xCheck
xCheck:
beq $t0, 'X', xChar # if $t0 equal X go to xChar
bne $t0, $t1, vCheck
vCheck:
beq $t0, 'V', vChar # if $t0 equal V go to vChar
bne $t0, $t1, iCheck
iCheck:
beq $t0, 'I', iChar # if $t0 equal I go to iChar
bne $t0, $t1, error
mChar:
la $a0, M #puts one hundred in $t3
li $v0, 4
syscall
j loop
dChar:
la $a0, D # prints out 500
li $v0, 4
syscall
j loop
cChar:
la $a0, C # prints out 500
li $v0, 4
syscall
j loop
lChar:
la $a0, L # prints out 500
li $v0, 4
syscall
j loop
xChar:
la $a0, X # prints out 500
li $v0, 4
syscall
j loop
vChar:
la $a0, V # prints out 500
li $v0, 4
syscall
j loop
iChar:
la $a0, I # prints out 500
li $v0, 4
syscall
j loop
error:
la $a0, enter1 # Print error meg. then back to main
li $v0, 4
syscall
j done
done:
li $v0, 10 # Exit
syscall
My question is how can you take input from the user and put it in $a0, and then use a while loop after that? I can't get the bytes to go to the next spot (i.e. MXX to go from M to X.) currently the program reads M, but not X. Eventually I will switch the program to sum these numbers and to also check to see if the number before is less (i.e. IV) to account for those roman numerals but I need help with the while loop first.

Asm program... something goes wrong

I load two arrays. I have to return a third array that contain the sum of the two and has the dimension of the smaller. Print the last one.
Example:
INPUT: Array1: [1 2 3 4 5] Array2: [2 6 1]
OUTPUT: Array3: [3 8 4]
Program runs... it give me the exact number of elements but every element is 0.
.data
vett1: .word 0:100
vett2: .word 0:100
vett3: .word 0:100
x: .word 0
space: .asciiz " "
.text
.globl main
main:
la $a0, vett1
la $a1, vett2
la $a2, vett3
la $a3, x
li $t0, 0
li $t1, 0
li $t2, 0
jal loadA1 #mi salvo 26 salto a caricavettore1
jal loadA2 #mi salvo 27 salto a caricavettore2
jal lenght #mi salvo 28 salto a controllalunghezza
lw $t2, ($a3)
lw $t3, ($a3)
la $a0, vett1
la $a1, vett2
la $a2, vett3
jal summ
jal print
li $v0, 10
syscall
loadA1:
li $v0, 5
syscall
beq $v0, -1, exit
sw $v0, ($a0)
addi $t0, $t0, 1
addi $a0, $a0, 4
j loadA1
exit: jr $ra
loadA2:
li $v0, 5
syscall
beq $v0, -1, exit2
addi $t1, $t1, 1
sw $v0, ($a1)
addi $a1, $a1, 4
j loadA2
exit2: jr $ra
lenght:
blt $t0, $t1, cond1
sw $t1, ($a3)
jr $ra
cond1: sw $t0, ($a3)
jr $ra
summ:
subi $sp, $sp, 4
sw $ra, 0($sp)
bnez $t2, rec
j exit3
rec: lw $s0, ($a0)
lw $s1, ($a1)
add $v0, $s0, $s1
sw $v0, ($a2)
addi $a0, $a0, 4
addi $a1, $a1, 4
addi $a2, $a2, 4
subi $t2, $t2, 1
jal summ
exit3:
lw $ra, 0($sp)
addi $sp, $sp, 4
jr $ra
print:
beqz $t3, exit4
lw $a0, ($a2)
li $v0, 1
syscall
la $a0, space
li $v0, 4
syscall
addi $a2, $a2, 4
subi $t3, $t3, 1
j print
exit4: jr $ra
When you sum the two arrays you add 4 to $a2 at the end of each iteration to point it to the next element of vett3. So after the summing is complete $a2 will point to the first memory location after the end of vett3.
Then you call print but don't reset $a2 to point at the start of vett3, so you end up printing garbage data (which could happen to be all zeroes - or mostly zeroes at least, since x and space will be there).

Resources