关于MIPS I型指令符号扩展的困惑

Confusion about MIPS I-type instruction sign extend

我正在学习MIPS指令,当我测试需要对立即数进行符号扩展的I型指令时,我对以下结果感到困惑(它们在MARS中都是运行):

  1. 假设我们有源代码行 ori $s1, $s2, 0xfd10,MARS 给出了基本汇编指令 ori , , 0x0000fd10。这是预期,因为 ori 应该 零扩展 16 位立即数。如果我们只把functori改成andi,也就是源代码行andi $s1, $s2, 0xfd10,MARS给出了几乎相同的基本汇编程序指令 andi , , 0x0000fd10。然而,与ori不同的是,andi应该使用符号扩展。所以基本汇编指令应该是andi , , 0xfffffd10.

andi 也应该使用零扩展!请忽略第一个问题

  1. 当我尝试使用 slti rt, rs, imm 时,例如 slti $s1, $s2, 0x8000,MARS 拒绝执行该行,错误消息为 "0x8000": operand is out of range。我看不出立即数超出范围的原因。如果我把立即数改小一点,比如 slti $s1, $s2, 0x7fff,它起作用了,立即数被扩展到 0x00007fff。我的期望是 0x8000 应该扩展到 0xffff8000。我的理解有问题吗?

asm 源代码中的值表示您要使用的实际数值,而不仅仅是要编码到指令中的位模式。

0x80000xffff8000 不是同一个数字,因此 assembler 会阻止您通过符号扩展修改您的值。如果您想要最终指令的机器代码来编码值0xffff8000,您应该在 asm 源代码中编写 0xffff8000 用于符号扩展其立即数的指令。

在我们的数字位值书写系统中,显式数字左侧有无限数量的隐式高位 0 数字。 所以 0x80000x00008000 是相同的数字,而 那是 assembler 试图表示为16 位符号扩展立即数.


您正在从 I 型指令的编码方式的 PoV 来解决这个问题。但是 assemblers 旨在为您处理编码细节。这是使用 one 的部分意义所在。假设您编写 addiu $t0, $t1, -123 并且 assembler 将 -123 编码为 16 位符号扩展立即数。

假设您编写 ori $t0, $t0, -256 来设置低字节以上的所有位。但是 assembler 拒绝了这一点,因为它不能编码为 ori 的零扩展立即数,而不是像 0x0000ff00 那样默默地保留高 16 位未设置。 所以你不必记住每条指令是如何处理它的立即数的; assembler 会为您检查。这是一个有意的 功能 和一个很好的设计。

特别是如果您有一个定义了一些 assemble 时间常数然后以各种方式使用它们的大型程序:如果调整其中一个值导致指令不可编码,您会想知道关于它而不是默默地得到错误的结果。

(因为我使用了十进制示例,所以将数字写为十六进制数字文字不会改变 assembler 应该如何处理它们。)


However, unlike ori, andi should use sign extending.

不,在 MIPS 中,所有 3 个按位布尔逻辑指令 (ori/andi/xori) 对它们的立即数进行零扩展。 (符号扩展在更多情况下对于 AND 会更有用,允许掩码在低位中只有几个零,但这不是 MIPS 的设计方式。尽管这会使截断到恰好 16 位的成本更高。)

https://ablconnect.harvard.edu/files/ablconnect/files/mips_instruction_set.pdf 这样的文档确认 andi 零扩展。我没有查看官方的 MIPS 文档,但是这个信息在 Internet 上很普遍;您还可以测试编译器是否以这种方式使用它来实现 uint16_t 或其他任何东西。

还有 (涵盖启用了扩展伪指令的 MARS,因此如果您使用 andi 和一个不可编码的值,它将在另一个寄存器中构造一个完整的 32 位值16 位零扩展立即数)