RV32I架构RARS模拟器下定点数平方根计算程序异常求助
RV32I定点数平方根计算问题修复
问题描述
需求是读取32位有符号整数,将其解释为14位小数位的32位无符号定点数,计算平方根后,再以相同格式输出。但输入409600(对应实际值25)时,输出始终为8388607或-8388607(格式最大值或其负数),与预期的81920(对应实际值5)不符。
核心问题分析
- 二进制搜索逻辑错误:当候选猜测的平方大于输入时,错误地将当前猜测减去步长,导致猜测值变为负数(无符号下为极大值),后续所有比较完全偏离正确方向。
- 乘法溢出问题:仅用
mul指令获取乘积低32位,当猜测值较大时,平方结果超过32位,导致右移后的比较值完全错误。
修复后的代码(RV32M版本)
.data input_raw: .word 0 .text .globl main main: # (A) 读取输入值 li a7, 5 ecall la t4, input_raw sw a0, 0(t4) # 加载输入值(无符号处理) lw t5, 0(t4) # 初始化二进制搜索寄存器 li t0, 0 # 当前猜测值,初始为0 li t1, 4194304 # 初始步长:2^22(最大可能猜测值2^23的一半) loop: # (B) 正确计算(t0 + t1)^2 >>14(64位乘法避免溢出) add t3, t0, t1 # 候选猜测值 mul t6, t3, t3 # 乘积低32位 mulh t7, t3, t3 # 乘积高32位 # 组合高低位得到右移14位的结果 srli t8, t7, 14 # 高32位右移14位 slli t9, t6, 18 # 低32位左移18位(填补高32位空缺) or t6, t8, t9 # t6即为(t3*t3) >>14 # (C) 无符号比较候选平方与输入值 bltu t6, t5, increase_guess # 若候选平方>=输入,保持猜测值不变,直接减半步长 j halve_step increase_guess: # (D) 候选平方小于输入,将步长加到猜测值中 add t0, t0, t1 halve_step: # (E) 步长减半 srli t1, t1, 1 # (F) 步长不为0则继续循环 bnez t1, loop # (G) 输出最终猜测值 done: mv a0, t0 li a7, 1 ecall # 退出程序 li a7, 10 ecall
关键修改说明
- 修正搜索逻辑:移除错误的减法操作,当候选猜测的平方大于输入时,仅减半步长、保持猜测值不变;只有当候选平方小于输入时,才将步长加到猜测值中,符合二进制搜索逼近平方根的正确逻辑。
- 解决乘法溢出:使用
mulh获取乘积高32位,结合mul的低32位,正确计算出平方右移14位的结果,避免大数值下的溢出错误。 - 消除负数输出:猜测值始终从0开始累加正数步长,最终结果必然是非负的,解决了负数输出问题。
严格RV32I版本(无乘法指令)
若需完全符合RV32I指令集(禁用mul/mulh),可将平方计算部分替换为移位加法实现的64位乘法:
# 替换原乘法部分,计算t3*t3 >>14存入t6 li t6, 0 li t7, 0 mv t8, t3 mv t9, t3 li t10, 0 mul_loop: andi t11, t9, 1 bnez t11, add_t8 j next_bit add_t8: add t6, t6, t8 sltu t11, t6, t8 add t7, t7, t11 next_bit: slli t8, t8, 1 sltu t11, t8, 1 add t7, t7, t11 srli t9, t9, 1 addi t10, t10, 1 bltu t10, 32, mul_loop # 计算右移14位 srli t8, t7, 14 slli t9, t6, 18 or t6, t8, t9
内容的提问来源于stack exchange,提问作者swaab
相关产品推荐
相关产品推荐

