mul 和 mulu 之间的确切区别
Exact difference between mul and mulu
我从源代码中发现 Rs 和 Rt 的内容被认为是 mul 的有符号整数。
而对于 mulu,Rs 和 Rt 的内容被视为无符号整数。
但是每次我执行mul和mulu,他们似乎都给出相同的结果。
li $t0 -2
li $t1 2
mul $s0, $t0, $t1
mulu $s1, $t0, $t1
两者都将 -4 存储在 $s0 和 $s1 中。
我的问题是说 Rs 和 Rt 被认为是 signed/unsigned 整数是什么意思,mul 和 mulu 如何以不同方式对待 Rt 和 Rs?
我可以看到 mul 和 mulu 给出不同结果的具体情况是什么?
我正在使用 MARS 模拟器。
谢谢你。如果您对问题有任何困惑,请问我。
MIPS 有一个可以给出精确答案的乘法单元:它需要 32 位 × 32 位 → 64 位,从数学上讲,这就是乘法的工作原理。
在 MARS 上,mul
是一个真正的指令。它产生一个在 hi
和 lo
中捕获的 64 位结果,并将其低 32 位存储到 rd
中。 (此指令不是第一个 MIPS 的一部分;它是后来添加的。)如果您执行此指令,您将看到 hi
和 lo
以及 rd
受到 MARS 的影响。
而在 MARS 上 mulu
是一个伪指令。它还会生成在 hi
& lo
中捕获的 64 位结果,并将其低 32 位存储到“rd
”(我在这里用引号括起来 b/c 这个 mulu
不是真正的指令,所以没有实际的寄存器字段),但是由 MARS 汇编器实现为 2 个真正的指令,如下所示:首先是 multu rs,rt
,然后是 mflo rd
.如果您在 MARS 中查看此指令的机器代码,您会看到此扩展为 2 条指令,如果您执行,您将首先看到 hi
和 lo
,然后是 rd
受到影响。
较旧的 MIPS 通过两个操作数 mult
& multu
仅提供 32 × 32 → 64 结果,64 位结果在特殊的 hi
& [=12 中捕获=] 寄存器(这样乘法可能需要多个周期,并且不会干扰可以并行服务其他指令 运行 的整数寄存器文件)所以您可以考虑尝试这些,例如mult $t0, $t1
,以及 multu $t0, $t1
。
2 × -2 的有符号答案(例如使用 mult
)是 0xffffffff 0xfffffffc,这个值可以安全地截断为 32 位(或更少),因为这个值只是 -4 , 适合较小的位数1.
无符号中没有 -2,因此这些位被解释为一个大的正数,fffffffe16 又名 4,294,967,29410。
2 × 0xfffffffe 的无符号答案(使用 multu
)是 0x00000001 0xfffffffc,而这个值——正如你对 unsigned × unsigned 所期望的那样是正数——不适合 32 位2,所以当你在没有检查的情况下强行截断时,我们就会溢出,也就是说:一个错误的答案。
碰巧低 32 位的位模式与有符号和无符号的位模式相同,但由于溢出,这相对没有意义 — 当然,这对硬件很有用,因为这个事实意味着两种乘法类型共享很多电路。
1 我们如何判断这个 64 位值适合 32 位?较高的结果是全 0 或全 1,并且这些位也与较低结果的符号位(最高位,MSB)匹配。
我们如何在 MIPS 上对此进行运行时测试?取低 32 位结果并将其算术右移 31 个位置(只保留 LSB 位置的符号位)。使用算术移位在符号位右移时复制符号位,因此我们将根据原始符号获得全 0 或全 1 的值。然后将移位后的值与高32位进行比较,如果相等,则64位值可以用32位表示,如果不相等,则不能用32位表示。
2 我们怎么知道这个 64 位数字不适合 32 位?由于无符号数据类型的所有位都是量级位(即没有符号位),那么如果结果的高32位是non-zero,那么这个数就需要多于32位来表示,只保留低 32 位将截断结果,就像对 232.
取模一样
我从源代码中发现 Rs 和 Rt 的内容被认为是 mul 的有符号整数。
而对于 mulu,Rs 和 Rt 的内容被视为无符号整数。
但是每次我执行mul和mulu,他们似乎都给出相同的结果。
li $t0 -2
li $t1 2
mul $s0, $t0, $t1
mulu $s1, $t0, $t1
两者都将 -4 存储在 $s0 和 $s1 中。 我的问题是说 Rs 和 Rt 被认为是 signed/unsigned 整数是什么意思,mul 和 mulu 如何以不同方式对待 Rt 和 Rs? 我可以看到 mul 和 mulu 给出不同结果的具体情况是什么? 我正在使用 MARS 模拟器。 谢谢你。如果您对问题有任何困惑,请问我。
MIPS 有一个可以给出精确答案的乘法单元:它需要 32 位 × 32 位 → 64 位,从数学上讲,这就是乘法的工作原理。
在 MARS 上,mul
是一个真正的指令。它产生一个在 hi
和 lo
中捕获的 64 位结果,并将其低 32 位存储到 rd
中。 (此指令不是第一个 MIPS 的一部分;它是后来添加的。)如果您执行此指令,您将看到 hi
和 lo
以及 rd
受到 MARS 的影响。
而在 MARS 上 mulu
是一个伪指令。它还会生成在 hi
& lo
中捕获的 64 位结果,并将其低 32 位存储到“rd
”(我在这里用引号括起来 b/c 这个 mulu
不是真正的指令,所以没有实际的寄存器字段),但是由 MARS 汇编器实现为 2 个真正的指令,如下所示:首先是 multu rs,rt
,然后是 mflo rd
.如果您在 MARS 中查看此指令的机器代码,您会看到此扩展为 2 条指令,如果您执行,您将首先看到 hi
和 lo
,然后是 rd
受到影响。
较旧的 MIPS 通过两个操作数 mult
& multu
仅提供 32 × 32 → 64 结果,64 位结果在特殊的 hi
& [=12 中捕获=] 寄存器(这样乘法可能需要多个周期,并且不会干扰可以并行服务其他指令 运行 的整数寄存器文件)所以您可以考虑尝试这些,例如mult $t0, $t1
,以及 multu $t0, $t1
。
2 × -2 的有符号答案(例如使用 mult
)是 0xffffffff 0xfffffffc,这个值可以安全地截断为 32 位(或更少),因为这个值只是 -4 , 适合较小的位数1.
无符号中没有 -2,因此这些位被解释为一个大的正数,fffffffe16 又名 4,294,967,29410。
2 × 0xfffffffe 的无符号答案(使用 multu
)是 0x00000001 0xfffffffc,而这个值——正如你对 unsigned × unsigned 所期望的那样是正数——不适合 32 位2,所以当你在没有检查的情况下强行截断时,我们就会溢出,也就是说:一个错误的答案。
碰巧低 32 位的位模式与有符号和无符号的位模式相同,但由于溢出,这相对没有意义 — 当然,这对硬件很有用,因为这个事实意味着两种乘法类型共享很多电路。
1 我们如何判断这个 64 位值适合 32 位?较高的结果是全 0 或全 1,并且这些位也与较低结果的符号位(最高位,MSB)匹配。
我们如何在 MIPS 上对此进行运行时测试?取低 32 位结果并将其算术右移 31 个位置(只保留 LSB 位置的符号位)。使用算术移位在符号位右移时复制符号位,因此我们将根据原始符号获得全 0 或全 1 的值。然后将移位后的值与高32位进行比较,如果相等,则64位值可以用32位表示,如果不相等,则不能用32位表示。
2 我们怎么知道这个 64 位数字不适合 32 位?由于无符号数据类型的所有位都是量级位(即没有符号位),那么如果结果的高32位是non-zero,那么这个数就需要多于32位来表示,只保留低 32 位将截断结果,就像对 232.
取模一样