关于MIPS三操作数divu指令及取余逻辑的技术咨询
MIPS汇编代码解析:divu指令与取模逻辑
原始代码对照
C代码
i = low + (1664525*(unsigned)high + 22695477*(unsigned)low) % (high-low+1);
MIPS汇编代码
lw $3,40($fp) li $2,1638400 # 0x190000 ori $2,$2,0x660d mult $3,$2 mflo $2 lw $4,36($fp) li $3,22675456 # 0x15a0000 ori $3,$3,0x4e35 mult $4,$3 mflo $3 addu $2,$2,$3 lw $4,40($fp) lw $3,36($fp) nop subu $3,$4,$3 addiu $3,$3,1 divu $0,$2,$3 bne $3,$0,1f nop break 7 mfhi $2 move $3,$2 lw $2,36($fp) nop addu $2,$3,$2 sw $2,8($fp)
已知:low存储在36($fp),high存储在40($fp)
核心疑问解答
1. 为什么divu是三操作数形式?
MIPS原生的divu指令确实是双操作数格式,但这里的三操作数写法是汇编器提供的语法糖,等价于:
- 将
$2的值加载到LO寄存器 - 把
HI寄存器置0 - 执行双操作数
divu $0, $3(即把HI:LO组成的64位无符号数除以$3)
这种写法简化了操作,无需手动设置HI和LO寄存器,直接指定32位被除数和除数即可完成无符号除法。
2. 为什么用mfhi取结果而非mflo?
原C代码中需要计算的是无符号取模运算(%),而MIPS的divu指令执行后:
- 除法的商会被存入
LO寄存器,用mflo读取 - 除法的余数会被存入
HI寄存器,用mfhi读取
这里要获取的是取模结果,也就是余数,因此必须用mfhi而非mflo。
完整代码工作机制解析
计算1664525*high
- 从
40($fp)取出high到$3 - 通过
li+ori组合出系数1664525(0x19660d)存入$2 - 执行
mult $3,$2完成乘法,用mflo $2取出乘积的低32位(无符号场景下足够)
- 从
计算22695477*low
- 从
36($fp)取出low到$4 - 通过
li+ori组合出系数22695477(0x15a4e35)存入$3 - 执行
mult $4,$3完成乘法,用mflo $3取出乘积的低32位
- 从
求和得到被除数
addu $2,$2,$3:将两个乘积相加,结果1664525*high + 22695477*low存入$2
计算除数high-low+1
- 重新取出
high和low,执行subu $3,$4,$3得到high-low addiu $3,$3,1完成+1,除数存入$3
- 重新取出
无符号除法与除数检查
divu $0,$2,$3:执行无符号除法,被除数为$2,除数为$3bne $3,$0,1f:如果除数不为0,跳过中断指令;否则执行break 7触发除数为0的异常
计算最终结果i
mfhi $2:取出取模运算的余数addu $2,$3,$2:将余数与low相加,得到i的值sw $2,8($fp):将结果存入指定内存位置
内容的提问来源于stack exchange,提问作者user202004
相关产品推荐
相关产品推荐

