【问题标题】:andi vs. addi instruction in MIPS with negative immediate constant带有负立即常数的 MIPS 中的 andi 与 addi 指令
【发布时间】:2016-10-17 15:22:09
【问题描述】:

假设 $t2=0x55555550,然后执行以下指令:

andi $t2, $t2, -1

$t2 变为 0x0005550

MIPS 模拟器确认了这一点1

然而,这不是我所期望的。我认为答案应该是 0x55555550 & 0xFFFFFFFF = 0x55555550。 我认为常数 -1 在 and 逻辑之前被符号扩展为 0xFFFFFFFF 。但似乎答案是 0x55555550 & 0x0000FFFF

为什么 -1 符号扩展为 0x0000FFFF 而不是 0xFFFFFFFF


脚注 1:编者注:启用“扩展伪指令”的 MARS 确实将其扩展为多条指令,以在 tmp 寄存器中生成 0xffffffff,从而使 $t2 保持不变。否则 MARS 和 SPIM 都拒绝它,因为它是不可编码的。其他汇编程序可能不同。

【问题讨论】:

  • 您对价值的期望是正确的。 哪个 mips 模拟器?我已经在marsspim [单步] 中对此进行了测试,它们 产生0x5555554F。您是否确定正确地预加载了原始值(例如li $t2,0x55555550)?如果您单步检查帖子addi 的值,您如何获得5550 的值?在最坏的情况下,使用 16 位截断,你会得到 554F。这是一个基本的操作,你可以在十六进制计算器上验证它。
  • @CraigEstey 我深表歉意。昨晚很晚我头晕,我的想法完全错了。它应该是 andi 而不是 addi。请您花点时间再次阅读我的问题。对不起.......
  • 嗯,MIPS 立即数 16 位宽,无论如何。
  • @LinYuCheng 希望你感觉好多了。同样,您对价值的期望是正确的。但是,您误读了模拟器结果。请参阅我对实际情况的回答。

标签: assembly mips sign-extension zero-extension immediate-operand


【解决方案1】:

您的预期是正确的,但您对实验结果的解释是

$t2 变为 0x0005550 这由 MIPS 仿真器确认。

不,这是不正确的。所以,以下之一:

  1. 不知何故,您误读了模拟器在做什么。来自模拟器的实际值预期的值。
  2. 或者,您在$t2 中没有0x55555550 之前 andi,但0x5550 代替(即)您的测试程序没有' t 正确设置$t2

然而,这不是我所期望的。我认为答案应该是 0x55555550 & 0xFFFFFFFF = 0x55555550。我认为常量 -1 在 and 逻辑之前被符号扩展为 0xFFFFFFFF。

是的,这正确的。而且,我将在下面解释发生了什么以及为什么。

但似乎答案是 0x55555550 & 0x0000FFFF。为什么-1符号扩展为0x0000FFFF而不是0xFFFFFFFF

不是。它扩展为0xFFFFFFFF。同样,您正在错误地读取实验结果[或者您的测试程序有错误]。


mips 模拟器和汇编器具有伪操作

这些指令可能作为真实的物理指令存在,也可能不存在。但是,它们被汇编器解释为生成一系列物理/实际指令。

“纯”伪操作的一个示例是li(“立即加载”)。它没有对应的指令,但通常会生成两个指令序列:luiori(它们物理指令)。

伪操作不应与汇编程序指令混淆,例如.text.data.word.eqv等。 p>

一些伪操作可以与实际的物理指令重叠。这就是您的示例所发生的情况。

事实上,汇编器将任何给定指令作为潜在伪操作进行检查。它可以确定 in 可以通过单个物理指令实现 intent。如果不是,它将生成一个 1-3 指令序列,并可能使用 [保留] $at 寄存器 [即 $1] 作为该序列的一部分。

mars 中,要查看实际的真实指令,请查看源窗口的Basic 列。

为了我的回答的完整性,以下所有内容都以顶级 cmets 开头。

我创建了三个示例程序:

  1. addi 与您原来的帖子中的一样
  2. andi 在您更正后的帖子中
  3. andi 使用 unsigned 参数

(1) 这是使用addi 的原始问题的汇编源代码:

    .text
    .globl  main
main:
    li      $t2,0x55555550
    addi    $t3,$t2,-1
    nop

mars 是这样解释的:

 Address    Code        Basic                     Source

0x00400000  0x3c015555  lui $1,0x00005555         4     li      $t2,0x55555550
0x00400004  0x342a5550  ori $10,$1,0x00005550
0x00400008  0x214bffff  addi $11,$10,0xffffffff   5     addi    $t3,$t2,-1
0x0040000c  0x00000000  nop                       6     nop

addi符号扩展它的 16 位立即数,所以我们有 0xFFFFFFFF。然后,做一个二的补码加操作,我们得到0x5555554F的最终结果@

因此,汇编器不需要为addi 生成额外的指令,因此addi pseudo-op 生成了单个real addi


(2) 这里是andi 来源:

    .text
    .globl  main
main:
    li      $t2,0x55555550
    andi    $t3,$t2,-1
    nop

这是程序集:

 Address    Code        Basic                     Source

0x00400000  0x3c015555  lui $1,0x00005555         4     li      $t2,0x55555550
0x00400004  0x342a5550  ori $10,$1,0x00005550
0x00400008  0x3c01ffff  lui $1,0xffffffff         5     andi    $t3,$t2,-1
0x0040000c  0x3421ffff  ori $1,$1,0x0000ffff
0x00400010  0x01415824  and $11,$10,$1
0x00400014  0x00000000  nop                       6     nop

哇!发生了什么? andi 生成了三个指令。

real andi 指令确实 not 符号扩展其直接参数。因此,我们可以在真正的andi 中使用的最大 unsigned 值是 0xFFFF

但是,通过指定-1,我们告诉汇编器我们确实想要符号扩展(即0xFFFFFFFF

因此,汇编器可能用一条指令完成意图,我们得到了上面的序列。并且生成的序列不能使用andi,但必须使用寄存器形式:and。这是andi生成的代码转换回更友好的asm源代码:

    lui     $at,0xFFFF
    ori     $at,$at,0xFFFF
    and     $t3,$t2,$at

至于结果,我们将0x555555500xFFFFFFFF0x55555550 [仍然未更改] 值相匹配


(3) 这是andi未签名 版本的来源:

    .text
    .globl  main
main:
    li      $t2,0x55555550
    andi    $t3,$t2,0xFFFF
    nop

这是汇编程序的输出:

 Address    Code        Basic                     Source

0x00400000  0x3c015555  lui $1,0x00005555         4     li      $t2,0x55555550
0x00400004  0x342a5550  ori $10,$1,0x00005550
0x00400008  0x314bffff  andi $11,$10,0x0000ffff   5     andi    $t3,$t2,0xFFFF
0x0040000c  0x00000000  nop                       6     nop

当汇编器发现我们正在使用一个十六进制常量(即0x 前缀)时,它会尝试将该值作为 unsigned 操作来实现。所以,它不需要签名扩展。而且,真正的andi可以满足要求。

这个结果是0x5550

请注意,如果我们使用了0x1FFFF 的掩码值,那将是无符号的。但是,它大于 16 位,因此汇编器会生成一个多指令序列来满足请求。

而且,这里的结果是0x15550

【讨论】:

  • 感谢您的出色解释。我现在明白了。看来我必须阅读更多关于“物理”机器代码的信息。
  • 不客气。这是一个很好的指令列表:mrc.uidaho.edu/mrc/people/jff/digital/MIPSir.html 作为示例,请注意分支有六个真正的单寄存器形式:bltz/blez/beqz/bnez/bgez/bgtz。但是,只有两个真正的两个寄存器版本:bne/beq。其余 [未显示] blt/ble/bge/bgt 是伪操作。他们以某种方式使用slt 来设置$at。顺便说一句,习惯上赞成一个好的答案并接受最好的答案。
【解决方案2】:

根据specification,立即数是16位宽。

因此,andi $t2, $t2, -1 可以读作andi $t2, $t2, 0xFFFF

所有逻辑运算都将立即数视为位串,并将其零扩展为 32 位。

【讨论】:

  • 就实际/物理指令而言,这是正确的。但是,mips 模拟器/汇编器将指令解释为伪操作,并可能生成完全不同的东西。在 OP 的代码中,汇编器不会生成真正的andi。它生成一个 3 指令序列。详情见我的回答。
  • @CraigEstey:如果某些汇编程序只是截断 -1 以适应零扩展立即数,我不会感到惊讶。但是,当前版本的 SPIM 和 MARS 没有。带有扩展伪指令的 MARS 将其作为伪指令接受,否则 MARS 和 SPIM 都拒绝-1。 clang 的内置汇编器也是如此。 (另外,如果它提到其他 MIPS 指令符号扩展它们的立即数,这将是一个更好的答案,包括addiuWhat does "extend immediate to 32 bits" mean in MIPS?
  • @PeterCordes 我的回答[至少对于andi] 对此进行了介绍。如果你这样做了,andi $t2,0xFFFF,你会得到一个真正的andi,它截断为 16 位(即0x0000FFFF)。如果这样做,andi $t2,-1mars 会将其视为伪操作,并生成三个指令来生成完整的、符号扩展的 32 位 and(相当于 0xFFFFFFFF)。
【解决方案3】:

MIPS Reference Sheet

从这个参考表中,对于 andi 指令,它清楚地表明在立即数上进行的符号扩展是零扩展。 ori 指令也类似。对于您正在使用的操作序列,这正是 MIPS 应该做的。 为了做你想做的事情,你应该把 0xFFFFFFFF 存储在其他寄存器中,并使用“and”操作。

【讨论】:

    猜你喜欢
    • 2011-10-03
    • 2017-10-30
    • 1970-01-01
    • 1970-01-01
    • 2013-02-23
    • 1970-01-01
    • 2016-04-29
    • 1970-01-01
    • 2020-07-26
    相关资源
    最近更新 更多