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

RISC-V汇编恢复除法算法实现故障排查与初始化咨询

RISC-V 无div指令的恢复除法算法实现修正

需求说明

实现32位整数的恢复除法算法,不使用div/divu指令,约定:

  • a0:输入被除数,最终输出商
  • a1:输入除数

现有代码无法正常运行,核心疑惑点是如何将除数放入64位运算块的左半部分,同时需要排查代码逻辑错误并完成正确实现。

现有代码核心问题

  1. 初始化逻辑错误:未遵循恢复除法的64位寄存器对结构(余数+商组成64位块),除数也未做高位对齐处理
  2. 循环操作逻辑混乱:错误地对除数执行右移,恢复除法中除数位置固定,应是余数+商整体左移
  3. 符号处理不完整:仅记录了符号翻转次数,但未在最后恢复商和余数的正确符号
  4. 寄存器未初始化:t6未清零直接累加,导致循环次数不确定
  5. 商位设置逻辑错误:位操作逻辑混乱,未正确实现商最低位的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 23:36:02