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
- 递归计算最长递增路径并输出结果
内容的提问来源于stack exchange,提问作者Eric Mariasis
相关产品推荐
相关产品推荐

