关于MIPS I型指令符号扩展的困惑
Confusion about MIPS I-type instruction sign extend
我正在学习MIPS指令,当我测试需要对立即数进行符号扩展的I型指令时,我对以下结果感到困惑(它们在MARS中都是运行):
- 假设我们有源代码行
ori $s1, $s2, 0xfd10
,MARS 给出了基本汇编指令 ori , , 0x0000fd10
。这是预期,因为 ori
应该 零扩展 16 位立即数。如果我们只把functori
改成andi
,也就是源代码行andi $s1, $s2, 0xfd10
,MARS给出了几乎相同的基本汇编程序指令 andi , , 0x0000fd10
。然而,与ori
不同的是,andi
应该使用符号扩展。所以基本汇编指令应该是andi , , 0xfffffd10
.
andi
也应该使用零扩展!请忽略第一个问题
- 当我尝试使用
slti rt, rs, imm
时,例如 slti $s1, $s2, 0x8000
,MARS 拒绝执行该行,错误消息为 "0x8000": operand is out of range
。我看不出立即数超出范围的原因。如果我把立即数改小一点,比如 slti $s1, $s2, 0x7fff
,它起作用了,立即数被扩展到 0x00007fff
。我的期望是 0x8000
应该扩展到 0xffff8000
。我的理解有问题吗?
asm 源代码中的值表示您要使用的实际数值,而不仅仅是要编码到指令中的位模式。
0x8000
与 0xffff8000
不是同一个数字,因此 assembler 会阻止您通过符号扩展修改您的值。如果您想要最终指令的机器代码来编码值0xffff8000
,您应该在 asm 源代码中编写 0xffff8000
用于符号扩展其立即数的指令。
在我们的数字位值书写系统中,显式数字左侧有无限数量的隐式高位 0
数字。 所以 0x8000
与 0x00008000
是相同的数字,而 那是 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 位零扩展立即数)
我正在学习MIPS指令,当我测试需要对立即数进行符号扩展的I型指令时,我对以下结果感到困惑(它们在MARS中都是运行):
- 假设我们有源代码行
ori $s1, $s2, 0xfd10
,MARS 给出了基本汇编指令ori , , 0x0000fd10
。这是预期,因为ori
应该 零扩展 16 位立即数。如果我们只把functori
改成andi
,也就是源代码行andi $s1, $s2, 0xfd10
,MARS给出了几乎相同的基本汇编程序指令andi , , 0x0000fd10
。然而,与ori
不同的是,andi
应该使用符号扩展。所以基本汇编指令应该是andi , , 0xfffffd10
.
andi
也应该使用零扩展!请忽略第一个问题
- 当我尝试使用
slti rt, rs, imm
时,例如slti $s1, $s2, 0x8000
,MARS 拒绝执行该行,错误消息为"0x8000": operand is out of range
。我看不出立即数超出范围的原因。如果我把立即数改小一点,比如slti $s1, $s2, 0x7fff
,它起作用了,立即数被扩展到0x00007fff
。我的期望是0x8000
应该扩展到0xffff8000
。我的理解有问题吗?
asm 源代码中的值表示您要使用的实际数值,而不仅仅是要编码到指令中的位模式。
0x8000
与 0xffff8000
不是同一个数字,因此 assembler 会阻止您通过符号扩展修改您的值。如果您想要最终指令的机器代码来编码值0xffff8000
,您应该在 asm 源代码中编写 0xffff8000
用于符号扩展其立即数的指令。
在我们的数字位值书写系统中,显式数字左侧有无限数量的隐式高位 0
数字。 所以 0x8000
与 0x00008000
是相同的数字,而 那是 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
或其他任何东西。
还有 andi
和一个不可编码的值,它将在另一个寄存器中构造一个完整的 32 位值16 位零扩展立即数)