规则
- 直接使用加法器来加
- 减法通过加 减数的二进制补码 来实现
溢出的情况
- 加法
add
和立即数addi
可能在两个操作数同号时溢出 - 减法
sub
可能在两操作数异号时发生溢出 - 无符号加法
addu
立即数无符号加法addiu
和无符号减法subu
不会溢出 - 发生溢出时,MIPS会报异常
注意
与addi
和slti
一样,sltiu
和 addiu
虽然是无符号操作,但是16位的立即数也要符号扩展为32位,因此,操作是无符号的,但是立即数却是有符号的。
一般算法
一般用32位长去乘以32位长,然后舍去高于32位的部分。
- 乘积寄存器为64位 初始化为0
- 检查乘数最低位,如为1跳到3,为0跳到4
- 乘积 = 乘积 + 被乘数 跳到4
- 被乘数左移1位,乘数右移1位
- 判断是否已经重复了32次,否则跳到2
- 结束
有符号乘法
符号位不参与运算,同号得正,异号得负。
MIPS里的乘法
- MIPS准备了一对32位寄存器
Hi
和Lo
来存64位的积 - 乘法指令有两条,分别是
mult
和无符号的multu
- 为了得到32位的积,我们需要用
mflo
(move from lo) mfhi
(move from hi)一般用于检查溢出
被除数 = 商 × 除数 + 余数
一般算法
- 将被除数赋给余数寄存器,商寄存器为0
- 余数寄存器 = 余数寄存器 – 除数
- 若余数非负,则到4,否则到5
- 商寄存器左移,最低位设为1 到6
- 余数寄存器 = 余数寄存器 + 除数 商寄存器左移,最低位设为0 到6
- 除数寄存器右移1位
- 重复2-6共33次
有符号除法
- 同号为正,异号为负
- 保证余数的符号与被除数的符号相同
MIPS中的除法
- 乘法器可以用来做除法
Hi
中存余数,而Lo
中存商
浮点数的表示
见754标准。
加法
- 将较小指数的数向较大指数的数对齐(右移,指数增大)
- 有效数字(即尾数)相加
- 对结果规格化调整,检查溢出
- 对结果进行四舍五入,如果结果不再规格化,则回到3
- 结束
乘法
- 指数部分相加,减去偏阶值作为新的指数部分
- 尾数相乘
- 对结果规格化调整,检查溢出
- 对结果进行四舍五入,如果结果不再规格化,则回到3
- 设置符号位
- 结束
MIPS里的浮点运算指令
- 单精度以.s结尾,双精度以.d结尾,如
add.s
add.d
- 单精度比较为
c.x.s
双精度比较为c.x.d
其中x可能是eq
neq
lt
le
gt
ge
- 浮点比较为真跳转
bclt
浮点比较为假跳转bclf
例题:将华氏温度转为摄氏温度
“`c++
float f2c (float fahr) {
return ((5.0/9.0) * (fahr – 32.0));
}
```shell
# fahr在$f12中 结果放在$f0中
f2c:
lwcl $f16,const5($gp) # 把5.0存到$f16
lwcl $f18,const9($gp) # 把9.0存到$f18
div.s $f16,$f16,$f18 # 把5.0/9.0c存到$16
lwcl $f18,const32($gp) # 把32.0存到$f18
sub.s $f18,$f12,$f18 # $f18 = fahr - 32.0
mul.s $f0 ,$f16,$f18 # $f0 = (5/9)*(fahr - 32.0)
jr $ra # return