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 是一个真正的指令。它产生一个在 hilo 中捕获的 64 位结果,并将其低 32 位存储到 rd 中。 (此指令不是第一个 MIPS 的一部分;它是后来添加的。)如果您执行此指令,您将看到 hilo 以及 rd 受到 MARS 的影响。

而在 MARS 上 mulu 是一个伪指令。它还会生成在 hi & lo 中捕获的 64 位结果,并将其低 32 位存储到“rd”(我在这里用引号括起来 b/c 这个 mulu 不是真正的指令,所以没有实际的寄存器字段),但是由 MARS 汇编器实现为 2 个真正的指令,如下所示:首先是 multu rs,rt,然后是 mflo rd .如果您在 MARS 中查看此指令的机器代码,您会看到此扩展为 2 条指令,如果您执行,您将首先看到 hilo,然后是 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.

取模一样