RISC-V汇编恢复除法算法实现故障排查与初始化咨询
RISC-V 无div指令的恢复除法算法实现修正
需求说明
实现32位整数的恢复除法算法,不使用div/divu指令,约定:
a0:输入被除数,最终输出商a1:输入除数
现有代码无法正常运行,核心疑惑点是如何将除数放入64位运算块的左半部分,同时需要排查代码逻辑错误并完成正确实现。
现有代码核心问题
- 初始化逻辑错误:未遵循恢复除法的64位寄存器对结构(余数+商组成64位块),除数也未做高位对齐处理
- 循环操作逻辑混乱:错误地对除数执行右移,恢复除法中除数位置固定,应是余数+商整体左移
- 符号处理不完整:仅记录了符号翻转次数,但未在最后恢复商和余数的正确符号
- 寄存器未初始化:
t6未清零直接累加,导致循环次数不确定 - 商位设置逻辑错误:位操作逻辑混乱,未正确实现商最低位的0/1设置
修正后的完整实现代码
.data a: .word 3 # 除数 b: .word 7 # 被除数 str_div0: .string "Divisione per 0\n" str_overflow: .string "Overflow nella divisione\n" .text main: lw a1, a # 加载除数到a1 lw a0, b # 加载被除数到a0 jal ra, restore_div # 输出商(a0)和余数(a2)示例 li a7, 1 ecall li a0, ' ' li a7, 11 ecall mv a0, a2 li a7, 1 ecall end: li a7, 10 ecall # 恢复除法核心函数 # 输入:a0=被除数, a1=除数 # 输出:a0=商, a2=余数 restore_div: addi sp, sp, -16 sw ra, 0(sp) sw t0, 4(sp) # 保存t0(被除数符号标记) sw t1, 8(sp) # 保存t1(除数符号标记) sw t2, 12(sp) # 保存t2(循环计数器) # 1. 除零检查 beqz a1, div_by_zero # 2. 符号处理:转为无符号运算,记录符号 li t0, 0 # t0=1表示被除数为负 li t1, 0 # t1=1表示除数为负 bgez a0, check_divisor_sign neg a0, a0 li t0, 1 check_divisor_sign: bgez a1, init_div neg a1, a1 li t1, 1 # 3. 初始化64位运算块:a2(高32位,余数)=0,a3(低32位,商)=被除数 # 除数左移31位,和余数的最高位对齐 init_div: mv a2, zero # 余数初始为0 mv a3, a0 # 商初始为被除数 slli a1, a1, 31 # 除数移到64位块的左半部分(最高位) li t2, 32 # 循环32次 div_loop: # 左移余数+商组成的64位块 slli a2, a2, 1 srli t3, a3, 31 # 取商的最高位 or a2, a2, t3 # 放到余数的最低位 slli a3, a3, 1 # 余数减除数 sub a2, a2, a1 # 判断余数是否非负 bgez a2, set_quotient_bit1 # 余数为负,恢复余数 add a2, a2, a1 # 商最低位置0(已经左移过,最低位是0,无需额外操作) j loop_end set_quotient_bit1: # 商最低位置1 addi a3, a3, 1 loop_end: addi t2, t2, -1 bnez t2, div_loop # 4. 恢复符号 # 商的符号:被除数和除数符号不同则为负 xor t0, t0, t1 beqz t0, restore_remainder_sign neg a3, a3 restore_remainder_sign: # 余数符号和被除数一致 beqz t0, end_div neg a2, a2 end_div: mv a0, a3 # 商存入a0 # 余数保留在a2 lw ra, 0(sp) lw t0, 4(sp) lw t1, 8(sp) lw t2, 12(sp) addi sp, sp, 16 jr ra div_by_zero: la a0, str_div0 li a7, 4 ecall j end
关键实现说明
- 64位块初始化:用
a2(高32位,余数)和a3(低32位,商)组成64位运算单元,初始时余数为0,商为被除数;除数通过slli a1, a1, 31左移31位,对齐到64位块的最高位,确保减法操作的位对齐。 - 循环核心步骤:每次将余数+商整体左移1位,余数减除数,若余数≥0则商的最低位置1,否则恢复余数并将商的最低位置0,循环32次完成所有位的运算。
- 符号处理:先将被除数和除数转为正数运算,记录原始符号,最后根据符号规则翻转商和余数的符号(商的符号由被除数和除数异或决定,余数符号与被除数一致)。
内容的提问来源于stack exchange,提问作者gabibbo quinto
相关产品推荐
相关产品推荐

