You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

QTSpim中MIPS代码因a4/a5寄存器不兼容报错的解决咨询

MIPS最长递增路径代码适配QTSpim解决方案

问题背景

基于下方C代码开发的MIPS版最长递增路径(LIP)计算程序,在QTSpim中运行时因使用$a4/$a5寄存器报错——QTSpim仅支持MIPS32基础架构,仅提供$a0-$a3四个参数寄存器,$a4/$a5属于MIPS64扩展无法使用。尝试用栈/临时寄存器替换未成功,需调整代码以适配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
    # 原代码中使用$a4/$a5的部分将替换为保存寄存器
    move $s0, $t0   # $s0 = 行数
    move $s1, $t1   # $s1 = 列数

    # 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及相关代码将替换为下方修改后的版本

原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;
}

修改方案

1. 替换$a4/$a5为保存寄存器

QTSpim不支持扩展参数寄存器,改用**保存寄存器($s0-$s7)**传递行数/列数(保存寄存器在函数调用中会被保留,适合递归场景):

  • 在main调用compute_LIP前,将行数/列数存入$s0/$s1
  • 在compute_LIP开头,将用到的保存寄存器和返回地址压栈(递归会修改返回地址,需保护)
  • 在compute_LIP结尾恢复寄存器并出栈

2. 重构compute_LIP核心逻辑

对齐C代码逻辑,修复原MIPS代码中的条件判断错误、冗余代码块问题:

compute_LIP:
    # 保存返回地址和用到的保存寄存器到栈
    addi $sp, $sp, -16
    sw $ra, 0($sp)
    sw $s0, 4($sp)
    sw $s1, 8($sp)
    sw $s2, 12($sp)

    # 计算当前位置在辅助矩阵的字节偏移:(x*cols + y)*4
    mul $t0, $a0, $s1
    add $t0, $t0, $a1
    sll $t0, $t0, 2
    add $t0, $a3, $t0
    lw $t7, 0($t0)
    bgez $t7, return_from_compute_LIP  # 已计算过,直接返回

    li $t9, 1  # 最小路径长度为1(当前单元格)

    # 获取当前元素值
    mul $t0, $a0, $s1
    add $t0, $t0, $a1
    sll $t0, $t0, 2
    add $t0, $a2, $t0
    lw $s2, 0($t0)  # $s2 = 当前元素值

    # 检查右侧邻居(y+1 < cols)
    addi $t1, $a1, 1
    blt $t1, $s1, check_right_neighbor
    j check_down_neighbor

check_right_neighbor:
    # 计算右侧元素地址
    mul $t0, $a0, $s1
    add $t0, $t0, $t1
    sll $t0, $t0, 2
    add $t0, $a2, $t0
    lw $t2, 0($t0)
    ble $t2, $s2, check_down_neighbor  # 右侧元素不大于当前,跳过

    # 递归调用compute_LIP(x, y+1)
    move $a1, $t1
    jal compute_LIP
    addi $t3, $v0, 1
    bgt $t3, $t9, update_max_right
    j check_down_neighbor

update_max_right:
    move $t9, $t3
    j check_down_neighbor

check_down_neighbor:
    # 检查下方邻居(x+1 < rows)
    addi $t1, $a0, 1
    blt $t1, $s0, check_down_valid
    j update_aux_matrix

check_down_valid:
    # 计算下方元素地址
    mul $t0, $t1, $s1
    add $t0, $t0, $a1
    sll $t0, $t0, 2
    add $t0, $a2, $t0
    lw $t2, 0($t0)
    ble $t2, $s2, update_aux_matrix  # 下方元素不大于当前,跳过

    # 递归调用compute_LIP(x+1, y)
    move $a0, $t1
    jal compute_LIP
    addi $t3, $v0, 1
    bgt $t3, $t9, update_max_down
    j update_aux_matrix

update_max_down:
    move $t9, $t3

update_aux_matrix:
    # 将结果存入辅助矩阵
    mul $t0, $a0, $s1
    add $t0, $t0, $a1
    sll $t0, $t0, 2
    add $t0, $a3, $t0
    sw $t9, 0($t0)

return_from_compute_LIP:
    move $v0, $t9
    # 恢复寄存器并出栈
    lw $ra, 0($sp)
    lw $s0, 4($sp)
    lw $s1, 8($sp)
    lw $s2, 12($sp)
    addi $sp, $sp, 16
    jr $ra

验证说明

将修改后的compute_LIP及相关代码替换原MIPS代码中的对应部分,即可在QTSpim中正常运行:

  1. 程序会先读取矩阵的行数、列数
  2. 逐个读取矩阵元素并存储
  3. 初始化辅助矩阵为-1
  4. 递归计算最长递增路径并输出结果

内容的提问来源于stack exchange,提问作者Eric Mariasis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 02:00:53