由于明显缺乏对寄存器 a4 和 a5 的支持,无法让 MIP 代码在 QTSpim 中专门工作

Having trouble getting MIPs code to work specifically in QTSpim due to apparent lack of support for registers a4 and a5

提问人:Eric Mariasis 提问时间:11/17/2023 最后编辑:Peter CordesEric Mariasis 更新时间:11/17/2023 访问量:29

问:

我下面有一些MIP代码,这些代码是我根据下面进一步开发的一些C代码开发的。我所做工作的前提是计算输入矩阵的最长递增路径,但这似乎与我的问题没有太大关系。当我尝试在 QTSpim 中运行 MIPs 代码时,它在首次使用寄存器 a4 和 a5 时出错,这表明它可能不支持这些代码。我尝试使用一些建议的策略,例如使用堆栈和额外的临时寄存器,但我无法让它们工作。任何建议将不胜感激!如果可能的话,我想让它在 QTSpim 中工作。

MIPs 代码

.data
    prompt_rows: .asciiz "Enter the number of rows: "
    prompt_cols: .asciiz "Enter the number of columns: "
    prompt_value: .asciiz "Enter value for row "
    space: .asciiz " column "
    newline: .asciiz "\n"

    matrix_rows: .word 0
    matrix_cols: .word 0

.text
.globl main

main:
    # Read number of rows
    li $v0, 4
    la $a0, prompt_rows
    syscall

    li $v0, 5
    syscall
    sw $v0, matrix_rows

    # Read number of columns
    li $v0, 4
    la $a0, prompt_cols
    syscall

    li $v0, 5
    syscall
    sw $v0, matrix_cols

    # Load rows and cols into registers
    lw $t0, matrix_rows   # $t0 = number of rows
    lw $t1, matrix_cols   # $t1 = number of columns

    # Calculate total number of elements (rows * cols) for main matrix
    mul $t2, $t0, $t1    # $t2 = total elements

    # Allocate memory for the main matrix
    sll $t2, $t2, 2      # Multiply total elements by 4 (size of word)
    li $v0, 9            # Syscall for memory allocation
    move $a0, $t2
    syscall
    move $t3, $v0        # $t3 = base address of the main matrix

    # Initialize counters for rows and columns
    li $t4, 0            # Row counter
    li $t5, 0            # Column counter

read_loop:
    # Check if loop is done
    bge $t4, $t0, end_read_loop

    # Output prompt for value
    li $v0, 4
    la $a0, prompt_value
    syscall

    li $v0, 1
    move $a0, $t4
    syscall

    li $v0, 4
    la $a0, space
    syscall

    li $v0, 1
    move $a0, $t5
    syscall

    li $v0, 4
    la $a0, newline
    syscall

    # Read integer
    li $v0, 5
    syscall

    # Store the value in the matrix
    sw $v0, 0($t3)

    # Print a tab character
    li $v0, 11      # Print character syscall
    li $a0, 9       # ASCII code for tab character
    syscall

    # Increment address, row, and column counters
    addi $t3, $t3, 4
    addi $t5, $t5, 1

    # Check if it's the end of the row
    beq $t5, $t1, print_tab_newline

    j read_loop

print_tab_newline:
    # Print a tab+newline
    li $v0, 11      # Print character syscall
    li $a0, 9       # ASCII code for tab character
    syscall

    li $v0, 11      # Print character syscall
    li $a0, 10      # ASCII code for newline character
    syscall

    # Increment row counter and reset column counter
    addi $t4, $t4, 1
    li $t5, 0

    j read_loop

end_read_loop:
    # Reset $t3 to the start of the main matrix
    sub $t3, $t3, $t2

    # Auxiliary matrix creation and initialization starts here
    # Reuse $t2 for the total number of elements in the auxiliary matrix
    # Allocate memory for the auxiliary matrix
    li $v0, 9             # Syscall for memory allocation
    move $a0, $t2
    syscall
    move $t7, $v0         # $t7 = base address of the auxiliary matrix

    # Initialize the auxiliary matrix to -1
    li $t8, 0             # Counter for the number of initialized elements
    li $t9, -1            # Value to initialize each element (-1)

initialize_aux_matrix:
    bge $t8, $t2, end_initialize_aux # Check if all elements are initialized
    sw $t9, 0($t7)                  # Store -1 in the current element
    addi $t7, $t7, 4                # Move to the next element
    addi $t8, $t8, 4                # Increment counter
    j initialize_aux_matrix

end_initialize_aux:

    # Setup for calling compute_LIP
    li $a0, 0       # Initial row index
    li $a1, 0       # Initial column index
    move $a2, $t3   # Pass the base address of the main matrix
    move $a3, $t7   # Pass the base address of the auxiliary matrix
    move $a4, $t0   # Pass the number of rows
    move $a5, $t1   # Pass the number of columns

    # Call compute_LIP
    jal compute_LIP

    # Handle the returned value here
    move $s1, $v0  # Store the length of the longest increasing path

    # Print the length as a single integer value
    li $v0, 1
    move $a0, $s1
    syscall

    # Exit
    li $v0, 10
    syscall

compute_LIP:
    # Load value from auxiliary matrix at current index
    lw $t7, 0($a3)
    bgez $t7, return_from_compute_LIP  # If value is non-negative, use it

    # Initialize result
    li $t9, 0

    # Check for bottom-right corner
    addi $t0, $a0, 1   # x + 1
    addi $t1, $a1, 1   # y + 1
    beq $a0, $a4, is_bottom_right  # if x == m - 1
    beq $a1, $a5, is_bottom_right  # if y == n - 1

    # Recursive call for right neighbor
    recursive_right:
    blt $t0, $a4, check_right  # if x + 1 < m
    j recursive_down

    check_right:
    # Load current and right element, compare
    # Call compute_LIP if right element is greater
    # Update $t9 with max($t9, 1 + returned value)

    # Recursive call for down neighbor
    recursive_down:
    blt $t1, $a5, check_down  # if y + 1 < n
    j update_aux_matrix

    check_down:
    # Load current and down element, compare
    # Call compute_LIP if down element is greater
    # Update $t9 with max($t9, 1 + returned value)

    # Store the result in the auxiliary matrix
    update_aux_matrix:
    sw $t9, 0($a3)
    j return_from_compute_LIP

    is_bottom_right:
    li $t9, 1
    sw $t9, 0($a3)

    return_from_compute_LIP:
    move $v0, $t9
    jr $ra


check_neighbor:
    # Assuming $t0 is row index for neighbor, $t1 is column index for neighbor
    # and $t10 is the value of the current element

    # Calculate address of neighbor element in the main matrix
    sll $t2, $t0, 2     # Row index * 4 (word size)
    mul $t2, $t2, $a5   # Multiply by number of columns
    add $t2, $t2, $t1   # Add column index
    sll $t2, $t2, 2     # Multiply by word size
    add $t2, $a2, $t2   # Add base address of main matrix
    lw $t3, 0($t2)      # Load neighbor element

    # Check if neighbor is greater than current element
    ble $t3, $t10, return_from_neighbor  # If not greater, return

    # If neighbor is greater, make a recursive call
    move $a0, $t0       # Set new row index for recursive call
    move $a1, $t1       # Set new column index for recursive call
    jal compute_LIP     # Recursive call to compute_LIP

    # Compare and update the result
    addi $t4, $v0, 1    # Add 1 to the returned path length
    bgt $t4, $t9, update_max_path  # If new path is longer, update max length

    return_from_neighbor:
    jr $ra              # Return from subroutine

update_max_path:
    move $t9, $t4       # Update maximum path length
    j return_from_neighbor  # Return to the caller

aux_not_computed:
    # Otherwise, compute the value using the LIP algorithm

    # Initialize result to 0
    li $t9, 0
    # Get the current element from the main matrix
    mul $t8, $a0, $a5
    add $t8, $t8, $a1
    sll $t8, $t8, 2
    add $t8, $a2, $t8
    lw $t10, 0($t8)

    # Check if we are at the bottom-right corner
    beq $a0, $a4, check_right
    beq $a1, $a5, check_right

    # Check the right cell
    addi $t1, $a1, 1
    mul $t2, $a0, $a5
    add $t2, $t2, $t1
    sll $t2, $t2, 2
    add $t2, $a2, $t2
    lw $t11, 0($t2)
    bge $t11, $t10, check_right

    # Recursive call for right cell
    addi $a1, $a1, 1
    jal compute_LIP
    addi $t12, $v0, 1
    b check_down

check_right:
    move $t12, $t9

check_down:
    # Check the down cell
    addi $t1, $a0, 1
    mul $t2, $t1, $a5
    add $t2, $t2, $a1
    sll $t2, $t2, 2
    add $t2, $a2, $t2
    lw $t11, 0($t2)
    bge $t11, $t10, store_result

    # Recursive call for down cell
    addi $a0, $a0, 1
    jal compute_LIP
    add $t3, $v0, 1
    b store_result

store_result:
    # Store the maximum of right and down paths
    max $t9, $t12, $t3

    # Store the result in the auxiliary matrix
    sw $t9, 0($a3)

    # Return the result
    move $v0, $t9
    jr $ra

C 代码

#include <stdio.h>
#include <stdlib.h>

int compute_LIP(int x, int y, int *main_matrix, int *aux_matrix, int rows, int cols);

int main() {
    int rows, cols;
    printf("Enter the number of rows: ");
    scanf("%d", &rows);
    printf("Enter the number of columns: ");
    scanf("%d", &cols);

    // Allocate memory for the main matrix
    int *matrix = (int *)malloc(rows * cols * sizeof(int));
    if (!matrix) {
        fprintf(stderr, "Memory allocation failed.\n");
        return 1;
    }

    // Read matrix elements
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("Enter value for row %d column %d: ", i, j);
            scanf("%d", &matrix[i * cols + j]);
        }
    }

    // Allocate memory for the auxiliary matrix
    int *aux_matrix = (int *)malloc(rows * cols * sizeof(int));
    if (!aux_matrix) {
        fprintf(stderr, "Memory allocation failed.\n");
        free(matrix);
        return 1;
    }

    // Initialize auxiliary matrix to -1
    for (int i = 0; i < rows * cols; i++) {
        aux_matrix[i] = -1;
    }

    // Call compute_LIP and get the result
    int lip_length = compute_LIP(0, 0, matrix, aux_matrix, rows, cols);

    // Print the result
    printf("Length of the longest increasing path: %d\n", lip_length);

    // Cleanup
    free(matrix);
    free(aux_matrix);
    return 0;
}

int compute_LIP(int x, int y, int *main_matrix, int *aux_matrix, int rows, int cols) {
    // Check if the auxiliary matrix already has a computed value
    if (aux_matrix[x * cols + y] != -1) {
        return aux_matrix[x * cols + y];
    }

    int max_path = 1; // Minimum path length is 1 (the current cell)
    int current_value = main_matrix[x * cols + y];

    // Check right neighbor
    if (y + 1 < cols && main_matrix[x * cols + (y + 1)] > current_value) {
        int right_path = 1 + compute_LIP(x, y + 1, main_matrix, aux_matrix, rows, cols);
        if (right_path > max_path) {
            max_path = right_path;
        }
    }

    // Check down neighbor
    if (x + 1 < rows && main_matrix[(x + 1) * cols + y] > current_value) {
        int down_path = 1 + compute_LIP(x + 1, y, main_matrix, aux_matrix, rows, cols);
        if (down_path > max_path) {
            max_path = down_path;
        }
    }

    // Store the computed value in the auxiliary matrix and return it
    aux_matrix[x * cols + y] = max_path;
    return max_path;
}

如上所述,我尝试了一些策略来保留功能,同时消除寄存器 a4 和 a5 的使用,但我无法让它们工作。

程序集 MIPS CPU 寄存器 qtspim

评论

1赞 Peter Cordes 11/17/2023
没错,MIPS 寄存器的“ABI 名称”不包括 a4 或 a5,因为标准调用约定在寄存器中最多只能传递 4 个参数。en.wikibooks.org/wiki/MIPS_Assembly/Register_File .也可以用作临时参数,或用于自定义调用约定中的参数。$t0-$t9
1赞 Erik Eidt 11/17/2023
出于好奇,什么环境使用a4和a5?这是编译器输出吗?仅供参考,RISC V 有这些,但我不知道没有 MIPS。
0赞 Eric Mariasis 11/17/2023
@PeterCordes我尝试过的方法之一(也许我不确定,但我确实尝试过)是使用临时寄存器,但其余的 t 寄存器都在我的代码中用于其他目的,所以我不确定如何将它们重新用于当前的 a4 和 a5。
0赞 Eric Mariasis 11/17/2023
@ErikEidt,我首先从我的 C 代码编写一些 MIP 开始,并通过 AI 对其进行了一些调整,从而产生了带有 a4 和 a5 的版本。我确实指定了MIPs作为语言。值得注意的是,在 QTSpim 中,我还尝试了编译器生成的 C 代码版本,其中我指定了 MIP,但也没有工作。QTSpim 似乎对它接受的内容非常挑剔。
0赞 Peter Cordes 11/17/2023
您的代码不使用 .哦,但它确实尝试使用不存在的.通常,您实际上并不需要同时“实时”那么多临时寄存器,例如,您可以重复使用相同的暂存寄存器来计算仅在单独块中使用的内容。否则,将东西洒到堆叠空间中。要么是一些很少使用的变量,比如来自外部循环,要么保存/恢复一些 和 ,即使你不将其用作帧指针。您也可以在不保存/恢复的情况下作为临时人员。$t6$t10$s0-$s7$ra$fp$v0$v1

答: 暂无答案