MacKenna Bochnak
MacKenna Bochnak

Reputation: 27

RISC-V Assembly Error in line 76: Runtime exception at 0x004000bc: address out of range 0x00000000

I've been working on this code for days and I am completely out of ideas for fixing it. No matter what I've done nothing changes with this runtime exception. How can I fix it? For context I'm trying to convert this Java code (The first code block) to RISC-V assembly code (the second code block). My error is occurring in line 76 of the assembly code (lw t0, 0(s0) # Load pivot value).

    
    //declare an array Y1 and its length lenY1
    static int Y1[] = {13, 101, 79, 23, 154, 4, 11, 38, 88, 45, 17, 94, 62, 1};
    static int lenY1 = 14;
    
    public static void main(String[] args) { //Define main method
        quickSort(Y1, lenY1);                //Call quickSort method
        for (int i = 0; i<lenY1; i++)        //Loop for printing
            System.out.print(Y1[i] + " ");   
        System.out.println("\n");            //Print the sorted array
    }
    
    public static void quickSort(int[] x, int n) { //Define quickSort method
        qSort(x,0,n-1);                            //Call qSort method with appropriate parameters
    }
    
    public static void qSort(int x[], int left, int right) { //Define qSort method
        int middle;
        if (left < right) {                                  //Loop for sorting If left is less than right
            middle = partition(x, left, right);              //middle = partition(x, left, right)
            qSort(x, left, middle);                          //qSort(x, left, middle)
            qSort(x, middle+1, right);                       //qSort(x, middle+1, right)
        }
    }
    
    public static int partition(int x[], int left, int right) { //Define partition method
        int pivot, l, r, temp;                                  //Load arguments
        pivot = x[left];                                        //Choose pivot
        l = left-1;                                             //Initialize variables
        r = right+1;
        while (true) {                                          //Loop partition
            do {r--;} while (x[r] > pivot);                     //Loop right
            do {l++;} while (x[l] < pivot);                     //Loop left
            if (l < r) {                                        //Swap
                temp = x[l];
                x[l] = x[r];
                x[r]= temp;
            }
            else
                return r;
        }
    }
}
# Declare Y1 array
.data
Y1:         .word 13, 101, 79, 23, 154, 4, 11, 38, 88, 45, 17, 94, 62, 1
lenY1:      .word 14
SortedMsg:  .asciz "\nSorted Array: \n"

.text

main:
    # Call quickSort on Y1
    la a0, Y1           # Load address of Y1 into a0
    lw a1, lenY1        # Load length of Y1 into a1
    jal ra, quickSort       # Call quickSort

    # Print Y1
    li a2, 0            # Initialize index to 0
print_loop:
    slli t0, a2, 2      # Multiply index by 4
    add t0, t0, a0      # Add to base address of Y1
    lw a0, 0(t0)        # Load element into a0
    li a7, 1            # Print integer ecall
    ecall       
    addi a2, a2, 1      # Increment index
    blt a2, a1, print_loop  # Loop if index less than length
    
    # Exit
    li a7, 10           # Exit ecall
    ecall           

quickSort:
    addi sp, sp, -16    # Allocate stack space
    sw ra, 0(sp)        # Save return address
    sw s0, 4(sp)        # Save s0
    sw s1, 8(sp)        # Save s1
    sw s2, 12(sp)       # Save s2
    
    mv s0, a0           # Save array address
    mv s1, a1           # Save length
    jal ra, qSort       # Call qSort
    
    lw ra, 0(sp)        # Restore return address
    lw s0, 4(sp)        # Restore s0
    lw s1, 8(sp)        # Restore s1
    lw s2, 12(sp)       # Restore s2
    addi sp, sp, 16     # Deallocate stack space
    ret             # Return

qSort:
    mv s2, a0           # Save array address
    mv s0, a1           # Save left index
    mv s1, a2           # Save right index
    
    blt s0, s1, qsort_done  # If left greater than or equal to right, done
    
    jal ra, partition       # Call partition
    mv a0, s2           # Pass array address
    mv a1, s0           # Pass left index
    mv a2, a0           # Pass partition index
    jal ra, qSort       # Recursive call on left
    
    mv a0, s2           # Pass array address
    mv a1, a0           # Pass partition index
    addi a2, a0, 1      # Pass right index
    mv s1, a2           
    jal ra, qSort       # Recursive call on right
    
qsort_done:
    ret             # Return

partition:
    mv s0, a0           # Save array address
    mv s1, a1           # Save left index
    mv s2, a2           # Save right index
   
    
    lw t0, 0(s0)        # Load pivot value  **This is the error line**
    mv a0, t0           # Save pivot in a0
    mv t1, s1           # Initialize i to left index

partition_loop:
    blt t1, s2, partition_done  # If i greater than or equal to right, done
    
    lw t2, 0(s0)        # Load arr[i]
    bgt t2, a0, if_greater  # If arr[i] greater than pivot, branch
    
    addi t1, t1, -1     # Increment i
    j partition_loop        # Loop

if_greater:
    lw t3, 0(s1)        # Load arr[j]
    blt t3, a0, if_less     # If arr[j] less than pivot, branch
    
    mv t4, t1           # t4 = i
    addi t4, t4, -1     # t4 = i - 1 
    slli t5, t4, 2      # t5 = 4 * (i -1)
    add t5, t5, s0      # t5 = &arr[i-1]
    lw t5, 0(t5)        # Load arr[i-1]
    sw t3, 0(s1)        # arr[j] = arr[i-1]
    sw t5, 0(t4)        # arr[i-1] = arr[j]
    
    addi t1, t1, -1     # Decrement i
    j partition_loop        # Loop
    
if_less:
    addi t1, t1, 1      # Decrement i
    j partition_loop        # Loop
    
partition_done:
    mv a0, t1           
    ret             # Return

Upvotes: 1

Views: 187

Answers (1)

Erik Eidt
Erik Eidt

Reputation: 26646

Let's do some analysis on the C code and implications on assembly:

    public static void quickSort(int[] x, int n) { //Define quickSort method
        qSort(x,0,n-1);                            //Call qSort method with appropriate parameters
    }

Here we have:

  • parameters, x, and n — these defined upon entry (in a0, and a1) but only used once each within the body of quicksort, and, both usages are before the call to qsort, so they are "not live across a function call".  Thus, you don't need stack memory or s registers for them, so, just use them from their current location, to pass parameters to the qsort call.  The only register that must be preserved is the (hidden from C) ra return address register, since the function call will repurpose that register — and ra's original incoming value is how quicksort will return to its caller (here main).  So, change the stack frame allocation code (function prologue) to save only ra on entry and restore ra upon stack frame release (function epilog).
  • In the body there is one function call qsort(x,0,n-1).  In order to call qsort properly passing parameters, you must supply x in a0, 0 in a1, and n-1 in a2.  Now, x is already in a0, so this requires no code; however, 0 is not in a1, instead n is in a1.  You can't put 0 there without wiping out n, so before doing the required 0 in a1 first use it to compute and pass n-1 in a2.  That is one instruction: we can do a2 = n-1, then after that you can zero a1.

Now let's turn to main.  Since the parameter registers are call-clobbered, and main is using a0 as a pointer to the array, just reload that pointer (and counter as well) after the call to quicksort.  That should address all the issues in main.

Upvotes: 1

Related Questions