为什么在 MIPS 中有两种方法可以将任意有符号数相乘?
Why are there two ways to multiply arbitrary signed numbers in MIPS?
如果您需要在 MIPS 中将两个任意有符号数相乘,有没有理由更喜欢:
mul $t0 $s0 $s1
或者这样:
mult $s0 $s1
mflo $t0
?
我在网上发现每个答案的含义都不一致。乍一看,我认为前者是后者的伪指令。 (甚至有一个网页声称。)但查看机器代码,似乎 mult
是有效的 R 型指令(操作码 0),而 mul
具有非零操作码(0x1c)所以不应该是 R 型,即使它包含 3 个寄存器?!
RISC 哲学说要经常使用伪指令,因为我们只有有限的真实指令。但我只是没有想到为什么你需要两种不同的繁殖方式。两者都会影响 lo
和 hi
(使用 MARS),因此您可以使用其中任何一个检查溢出。那么为什么要裁员呢?为什么不告诉大家一直使用 mul
?
mul
是 不是 伪指令。它 而不是 修改 hi
或 lo
寄存器,mult
会修改。它们是指令集中不同的 real 指令。
一般来说,我们有a = b * c
因为两个32位的数相乘得到64位的结果,一般情况下我们用mult
然后用mflo
得到结果的低32位和高32位mfhi
。这允许更高的准确性,但需要额外的指令 [或两个] 来获得结果。
如果我们只关心乘法结果的低 32 位(例如数组索引计算),我们可以使用 mul
,它允许结果与参数位于不同的寄存器中(在单条指令)
考虑一个简单的程序:
.text
.globl main
main:
mul $v0,$a0,$a1
mult $v1,$a2
mflo $v0
现在,如果我们 assemble 使用 mars
,我们得到:
00400000: 70851002 mul $v0,$a0,$a1
00400004: 00660018 mult $v1,$a2
00400008: 00001012 mflo $v0
注意我们在第 3 行有一个真正的 mflo
指令。如果 mul
是一个伪操作,mars
会 [必须]在mul
和mult
行之间插入一个mflo $v0
更新:
That's interesting. And you're right about it not being a pseudo-instruction. (You'd see that when it was assembled, if it were.) But when I use MARS, both mul and mult modify hi and lo. Maybe this is a MARS bug?
可能吧。 spim
也修改hi和lo。
经过进一步思考,考虑到原始 mips CPU 内核的时代(大约 1985 年)和它们拥有的 [极其] 有限数量的门,这似乎是合乎逻辑的。
但是,真正的 mips 内核今天仍然存在。公司是 "MIPS Technologies, Inc",截至 2017 年它仍然存在。
[AFAICT] 公司的 ISA 参考手册在这里有一个副本:https://s3-eu-west-1.amazonaws.com/downloads-mips/documents/MD00086-2B-MIPS32BIS-AFP-6.06.pdf
在该文档中,mul
指令不 列出改变 hi 或 lo 作为副作用。
在我看过的一些文档中[我不记得是哪个],它指出[对于old/real硬件]你必须有一个中间指令在 mult
和 mflo
之间(例如 nop
)。模拟器不需要这个。
作为一种好的做法,我可能不会依赖 lo/hi 在 mult
之后有效太久并且 根本不会 依赖它们mul
,因此,对于 class 的工作,这有点没有实际意义。
看看 qemu
做了什么会很有趣。它比 spim
或 mars
[我更喜欢] 更难使用,但可能更接近实际硬件的功能。
如果您需要在 MIPS 中将两个任意有符号数相乘,有没有理由更喜欢:
mul $t0 $s0 $s1
或者这样:
mult $s0 $s1
mflo $t0
?
我在网上发现每个答案的含义都不一致。乍一看,我认为前者是后者的伪指令。 (甚至有一个网页声称。)但查看机器代码,似乎 mult
是有效的 R 型指令(操作码 0),而 mul
具有非零操作码(0x1c)所以不应该是 R 型,即使它包含 3 个寄存器?!
RISC 哲学说要经常使用伪指令,因为我们只有有限的真实指令。但我只是没有想到为什么你需要两种不同的繁殖方式。两者都会影响 lo
和 hi
(使用 MARS),因此您可以使用其中任何一个检查溢出。那么为什么要裁员呢?为什么不告诉大家一直使用 mul
?
mul
是 不是 伪指令。它 而不是 修改 hi
或 lo
寄存器,mult
会修改。它们是指令集中不同的 real 指令。
一般来说,我们有a = b * c
因为两个32位的数相乘得到64位的结果,一般情况下我们用mult
然后用mflo
得到结果的低32位和高32位mfhi
。这允许更高的准确性,但需要额外的指令 [或两个] 来获得结果。
如果我们只关心乘法结果的低 32 位(例如数组索引计算),我们可以使用 mul
,它允许结果与参数位于不同的寄存器中(在单条指令)
考虑一个简单的程序:
.text
.globl main
main:
mul $v0,$a0,$a1
mult $v1,$a2
mflo $v0
现在,如果我们 assemble 使用 mars
,我们得到:
00400000: 70851002 mul $v0,$a0,$a1
00400004: 00660018 mult $v1,$a2
00400008: 00001012 mflo $v0
注意我们在第 3 行有一个真正的 mflo
指令。如果 mul
是一个伪操作,mars
会 [必须]在mul
和mult
行之间插入一个mflo $v0
更新:
That's interesting. And you're right about it not being a pseudo-instruction. (You'd see that when it was assembled, if it were.) But when I use MARS, both mul and mult modify hi and lo. Maybe this is a MARS bug?
可能吧。 spim
也修改hi和lo。
经过进一步思考,考虑到原始 mips CPU 内核的时代(大约 1985 年)和它们拥有的 [极其] 有限数量的门,这似乎是合乎逻辑的。
但是,真正的 mips 内核今天仍然存在。公司是 "MIPS Technologies, Inc",截至 2017 年它仍然存在。
[AFAICT] 公司的 ISA 参考手册在这里有一个副本:https://s3-eu-west-1.amazonaws.com/downloads-mips/documents/MD00086-2B-MIPS32BIS-AFP-6.06.pdf
在该文档中,mul
指令不 列出改变 hi 或 lo 作为副作用。
在我看过的一些文档中[我不记得是哪个],它指出[对于old/real硬件]你必须有一个中间指令在 mult
和 mflo
之间(例如 nop
)。模拟器不需要这个。
作为一种好的做法,我可能不会依赖 lo/hi 在 mult
之后有效太久并且 根本不会 依赖它们mul
,因此,对于 class 的工作,这有点没有实际意义。
看看 qemu
做了什么会很有趣。它比 spim
或 mars
[我更喜欢] 更难使用,但可能更接近实际硬件的功能。