我必须用汇编代码MIPS编写一个算法。我选择了合并排序算法,下面是我到目前为止所做的。每当我尝试通过MARS模拟器运行程序时,我得到"错误:无效程序计数器值:0x00000000。"我该如何解决这个错误?
## We begin by checking to see if the array has size 0 or 1, and also some error cases.
## The arrays are designed so that the length of the array is located at the first index of each array.
## Then, the values in the array follow the length.
#First, we will check the input for errors.
bgt $a0, $sp, ErrorCase #If maze address is higher than the stack pointer, error
blt $a0, $gp, ErrorCase #If maze pointer is in text or below zero, both < $gp, error
#Second, we will load the length of the parameter array.
lw $t0, 0($a0) # Check the array at spot 0 for the length of the array
li $t1, 1 # Checking for one element in array
#Check for negative length value
blt $t0, $zero, ErrorCase #If length < 0, error
#Check if length exceeds $gp
bge $t0, $gp, checkHeap #If length > $gp and goes into stack, error
#Checks for 0 or one element in array
ble $t0, $t1, ReturnOriginal #return original array if size is 0 or 1
#Otherwise, jump to the main function.
j recursion
checkHeap:
## This will check to see if the heap overlaps the stack.
bge $sp, $gp, ErrorCase
j recursion
ReturnOriginal:
## This will handle arrays of size 0 or 1. Return the array as is.
move $v0, $a0
jr $ra
ErrorCase:
## This will handle any errors. Sets output to null (0)
li $v0, 0
jr $ra
## Recursion function
## Parameters:
## $a0 = input array
## $v0 = output array
## Temp Registers:
## $t0 = increment variable
## $t1 = 2 constant
## $t2 = 4 constant
## $t3 = first subarray length (l1)
## $t4 = first subarray (sub1)
## $t5 = second subarray length (l2)
## $t6 = second subarray (sub2)
## $t7 = length of the original array, later used to move things from original array to sub array
## $t8 = a[index]
## $t9 = a[index+l1]
recursion:
## This is the recursive step where we will check to see if we should still be dividing the array
## into subarrays of size 1.
#save current return address and array we are manipulating on the stack
addi $sp, $sp, -8
sw $ra, 0($sp)
sw $a0, 4($sp)
#constants
li $t0, 1 #$t0 = 1 loop counter
li $t1, 2 #$t1 = 2 check to see if array is fully split up
li $t2, 4 #$t2 = 4 4 bytes per int value
lw $t7, 0($a0) #$t7 = length of array we are currently working on
bge $t7, $t1, divide #check the array if it is greater than 2 in size, if not, go to base case
#If it is the base case, just return the array
move $v0, $a0 #move array to result $v0
lw $ra, 0($sp) #obtain return address
addi $sp, $sp, 8 #deallocate memory
jr $ra
divide:
## This function will effectively divide the array we are working on in half.
li $t2, 4 #$t2 = 4, 4 bytes per int value
#divide the length of the array by 2 for first sub array length
div $t7, $t1 #divide orig_array length by 2
mflo $t3 #obtain length of sub array 1 (l1)
mul $a0, $t3, $t2 #get the size = index * data, load it into $a0
addi $a0, $a0, 4 #extra space added for length in array
#initialize the first sub array
li $v0, 9 #load 9 into $v0
syscall
move $t4, $v0 #obtain the first subarray (sub1)
sw $t3, 0($t4) #save length of the first sub array to the first part of sub1
#get the length of the second sub array
sub $t5, $t7, $t3 #obtain length of the second array (l2 = array_length-l1)
mul $a0, $t5, $t2 #get the size = index * data, load it into $a0
addi $a0, $a0, 4 #extra space added for length of array
#initialize the second sub array
li $v0, 9 #load 9 into $v0
syscall
move $t6, $v0 #obtain the second subarray (sub2)
sw $t5, 0($t6) #save length of the second subarray to first part of sub2
FillArray1:
## This will fill the first subarray with the top half of the array we are working with
bgt $t0, $t3, else #check if $t0 > $t3, loop if not
lw $a0, 4($sp) #load previous state of the original array
mul $t8, $t0, $t2 #obtain real index = index * size (4)
add $a0, $a0, $t8 #add this to original array to move to a new address
add $t4, $t4, $t8 #add this index also to sub1 array
lw $t7, 0($a0) #load element from original array[index]
sw $t7, 0($t4) #store element to sub1[index]
addi $t0, $t0, 1 #inc by 1
#Reset the subarray offset to 0
li $t7, -1
mul $t8, $t8, $t7
add $t4, $t4, $t8
j FillArray1
else:
li $t0, 1 #reset increment to 1
FillArray2:
## This will fill the second subarray with the bottom half of the array we are working with
bgt $t0, $t5, else2 #check if $t0 > $t5, loop if not
lw $a0, 4($sp) #load previous state of the original array
add $t9, $t0, $t3 #obtain new index = i+l1
mul $t9, $t9, $t2 #obtain real index = (i+l1)*4
mul $t8, $t0, $t2 #obtain real index = sub2[index * size] (4)
add $a0, $a0, $t9 #add this to original array to move to a new address a[i+l1]
add $t6, $t6, $t8 #add $t8 to obtain address or sub2[index]
lw $t7, 0($a0) #load element from original array[index+l1]
sw $t7, 0($t6) #store element to sub2[index]
addi $t0, $t0, 1 #inc by 1
#Reset the subarray offset to 0
li $t7, -1
mul $t8, $t8, $t7
add $t6, $t6, $t8
j FillArray2
else2:
li $t0, 1 #reset increment to 1
callOnMerge:
## This is where we will implement recursion through dividing the arrays and merging the arrays.
move $a0, $t4 #Put first subarray into $a0
move $a1, $t6 #Put second subarray into $a1
addi $sp, $sp, -4 #Put second subarray onto the stack!
sw $a1, 0($sp)
jal recursion #recursion on subarray 1
lw $a0, 0($sp) #Load the second subarray
sw $v0, 0($sp) #save sub array result from recurse into stack
jal recursion #recursion on subarray 2
move $a2, $v0 #sets up the second subarray
lw $a1, 0($sp) #sets up first subarray
addi $sp, $sp, 4
jal Merge #merge the two
lw $ra, 0($sp) #load return address
addi $sp, $sp, 8 #deallocate memory
jr $ra #return to main function that called it
# Params:
# $a1 = first subarray
# $a2 = second subarray
# $v0 = new array, merged
# Temp Registers:
# $t0 = counter for first array (static)
# St1 = counter for second array (static)
# $t2 = loop counter (static)
# $t3 = bytes per int (4), or the offset
# $t4 = subarray1 length (static)
# $t5 = subarray2 length (static)
# $t6 = subarray1 value
# $t7 = address we grab from based on offset
# $t8 = new array length (static)
# $t9 = subarray2 value
Merge:
## This function will merge two given subarrays from parameters $a1 and $a2
#Set counters to one.
li $t0, 1 #first
li $t1, 1 #second
#Set loop counter to start at one.
li $t2, 1
#Initialize return array, where length is in $a1
li $t3, 4 #Each int inside the array is 4 bytes
lw $t4, 0 ($a1) #Get first subarray length
lw $t5, 0 ($a2) #Get second subarray length
add $t8, $t4, $t5 #Length of new array we are creating
mul $a0, $t3, $t8 #How much space our solution will need allocated
addi $a0, $a0, 4 #Add extra spot for length value
#Allocates enough bytes specified in $a0, which $v0 will point to.
li $v0, 9
syscall
sw $t8, 0 ($v0) #Puts the length of the new array at first index.
Do_Loop:
## Check to see if loop is complete. Which means we performed enough iterations to fill up the new array
bgt $t2, $t8, Merge_Complete
First_Array_Empty:
## Check to see if the first array is empty.
## If so, take the element from array 2.
ble $t0, $t4, Second_Array_Empty #If the counter is less than the first array, continue on.
li $t3, 4 #Each int inside the array is 4 bytes
mul $t3, $t3, $t1 #Multiply 2nd array counter by 4 bytes per int to get offset
add $t7, $t3, $a2 #Puts the offset address into $t7
lw $t9, 0 ($t7) #Put the value at this address into $t9. In a moment, we will put this into our return array.
li $t3, 4 #Each int inside the array is 4 bytes
mul $t3, $t3, $t2 #Multiply loop counter by 4 bytes per int to get offset
add $t7, $t3, $v0 #Now apply the offset to our new array
sw $t9, 0 ($t7) #Store the value into our new array
addi $t2, $t2, 1 #loop counter
addi $t1, $t1, 1 #second array counter
j Do_Loop #loop again
Second_Array_Empty:
## Check to see if the second array is empty.
## If so, take the element from array 1.
ble $t1, $t5, Grab_First
li $t3, 4 #Each int inside the array is 4 bytes
mul $t3, $t3, $t0 #Multiply 1st array counter by 4 bytes per int to get offset
add $t7, $t3, $a1 #Puts the offset address into $t7
lw $t6, 0 ($t7) #Put the value at this address into $t6. In a moment, we will put this into our return array.
li $t3, 4 #Each int inside the array is 4 bytes
mul $t3, $t3, $t2 #Multiply loop counter by 4 bytes per int to get offset
add $t7, $t3, $v0 #Now apply the offset to our new array
sw $t6, 0 ($t7) #Store the value into our new arrays
addi $t2, $t2, 1 #loop counter
addi $t0, $t0, 1 #first array counter
j Do_Loop #loop again
Grab_First:
#Check to see if we should grab a value from the first array.
#We will do this if first_element < second_element
#First we want to get the value at the 1nd array counter index
li $t3, 4 #Each int inside the array is 4 bytes
mul $t3, $t3, $t0 #Multiply 1st array counter by 4 bytes per int to get offset
add $t7, $t3, $a1 #Puts the offset address into $t7
lw $t6, 0 ($t7) #Put the value at this address into $t6. In a moment, we will put this into our return array.
#Then we want to get the value at the 2nd array counter index
li $t3, 4 #Each int inside the array is 4 bytes
mul $t3, $t3, $t1 #Multiply 2nd array counter by 4 bytes per int to get offset
add $t7, $t3, $a2 #Puts the offset address into $t7
lw $t9, 0 ($t7) #Put the value at this address into $t9. In a moment, we will put this into our return array.
bge $t6, $t9, Grab_Second #If the second value is smaller, branch to that function.
li $t3, 4 #Each int inside the array is 4 bytes
mul $t3, $t3, $t2 #Multiply loop counter by 4 bytes per int to get offset
add $t7, $t3, $v0 #Puts the offset address into $t7
sw $t6, 0 ($t7) #Store the value in the new array
addi $t2, $t2, 1 #loop counter
addi $t0, $t0, 1 #first array counter
j Do_Loop #loop again
Grab_Second:
## We will take the element from the second array.
## We will reach here if first_element > second_element
#We want to get the value at the 2nd array counter index
li $t3, 4 #Each int inside the array is 4 bytes
mul $t3, $t3, $t1 #Multiply 2nd array counter by 4 bytes per int to get offset
add $t7, $t3, $a2 #Puts the offset address into $t7
lw $t9, 0 ($t7) #Put the value at this address into $t9. In a moment, we will put this into our return array.
li $t3, 4 #Each int inside the array is 4 bytes
mul $t3, $t3, $t2 #Multiply loop counter by 4 bytes per int to get offset
add $t7, $t3, $v0 #Get new array address offset
sw $t9, 0 ($t7) #Store it at that location
addi $t2, $t2, 1 #loop counter
addi $t1, $t1, 1 #second array counter
j Do_Loop #loop again
Merge_Complete:
## Reaches here when the merge is complete.
## Now all we have to do is return the array.
jr $ra #return array to the Merge_Sort function