MIPS中的Andi与Addi指令的立即数为负 [英] andi vs. addi instruction in MIPS with negative immediate constant

查看:1179
本文介绍了MIPS中的Andi与Addi指令的立即数为负的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

andi $t2, $t2, -1

$ t2变为0x0005550

这已由MIPS模拟器 1

确认.

但是,这不是我所期望的.我认为答案应该是0x55555550& 0xFFFFFFFF = 0x55555550. 我认为常数-1在和逻辑之前被符号扩展为0xFFFFFFFF.但看来答案是0x55555550& 0x0000FFFF

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


脚注1:编者注:启用了扩展伪指令"的MARS确实会将其扩展为多条指令,以在tmp寄存器中生成0xffffffff,从而使$t2保持不变.否则,MARS和SPIM都将其拒绝,并出现错误,表明该错误不可编码.其他汇编程序可能有所不同.

解决方案

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

$ t2变为0x0005550,这已由MIPS仿真器确认.

否,这是不正确的.因此,请执行以下操作之一:

  1. 不知何故,您误解了模拟器的功能.模拟器的实际值是您期望的 .
  2. ,假设您没有在andi之前的$t2 中插入0x55555550,而是使用0x5550代替(即)测试程序无法正确设置$t2.

但是,这不是我所期望的.我认为答案应该是0x55555550& 0xFFFFFFFF = 0x55555550.我认为常数-1在和逻辑之前被符号扩展为0xFFFFFFFF.

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

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

不是. 符号扩展到了0xFFFFFFFF.同样,您错误地读取了实验结果[或您的测试程序有错误].


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

这些指令可能以真实的物理指令形式存在或不存在.但是,它们由汇编程序解释以生成一系列物理/真实指令.

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

不应将伪操作与汇编指令 (例如.text.data.word.eqv等)混淆.

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

实际上,汇编程序将给定指令的任何检查为潜在伪操作.它可以确定in可以通过一条物理指令满足意图.如果没有,它将生成1-3条指令序列,并且可以使用[reserved] $at寄存器[$1]作为该序列的一部分.

mars中,要查看实际的实际指令,请查看源代码窗口的Basic列.

为使我的回答更加完整,以下所有内容均以开头的评论开头.

我创建了三个示例程序:

  1. 您的原始帖子中的addi
  2. 已更正帖子中的andi
  3. 使用 unsigned 自变量的andi


(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,我们告诉汇编程序我们 did 需要符号扩展名(即0xFFFFFFFF)

因此,汇编器可能只用一条指令 not 就无法实现意图,我们得到了上面的序列.并且生成的序列可以使用andi,但是必须使用寄存器形式:and.这是andi生成的代码,这些代码被转换回更友好的asm源:

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

结果是,我们对0x555555500xFFFFFFFF进行和运算,这是[c0>的[仍然不变]]


(3)这是>的 unsigned 版本的来源:

    .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

Assume $t2=0x55555550, then executing the following instruction:

andi $t2, $t2, -1

$t2 becomes 0x0005550

This is confirmed by the MIPS emulator1

However, it is not what I expected. I think the answer should be 0x55555550 & 0xFFFFFFFF = 0x55555550. I think the constant -1 was sign extended to 0xFFFFFFFF before the and logic. But it appears that the answer was 0x55555550 & 0x0000FFFF

Why -1 is sign extended to 0x0000FFFF instead of 0xFFFFFFFF


Footnote 1: Editor's note: MARS with "extended pseudo-instructions" enabled does expand this to multiple instructions to generate 0xffffffff in a tmp register, thus leaving $t2 unchanged. Otherwise MARS and SPIM both reject it with an error as not encodeable. Other assemblers may differ.

解决方案

Your expectation is correct, but your interpretation of your experimental results is not

$t2 becomes 0x0005550 This is confirmed by the MIPS emulator.

No, this is incorrect. So, one of the following:

  1. Somehow, you're misreading what the emulator is doing. The actual value from the emulator is what you expected it to be.
  2. Or, you don't have 0x55555550 in $t2 before the andi as you assume, but 0x5550 instead (i.e.) your test program doesn't set up $t2 correctly.

However, it is not what I expected. I think the answer should be 0x55555550 & 0xFFFFFFFF = 0x55555550. I think the constant -1 was sign extended to 0xFFFFFFFF before the and logic.

Yes, this is correct. And, I'll explain what is happening and why below.

But it appears that the answer was 0x55555550 & 0x0000FFFF. Why -1 is sign extended to 0x0000FFFF instead of 0xFFFFFFFF

It wasn't. It was sign extended to 0xFFFFFFFF. Again, you're reading the experimental results incorrectly [or your test program has a bug].


mips simulators and assemblers have pseudo ops.

These are instructions that may or may not exist as real, physical instructions. However, they are interpreted by the assembler to generate a sequence of physical/real instructions.

An example of a "pure" pseudo-op is li ("load immediate"). It has no corresponding instruction, but usually generates a two instruction sequence: lui, ori (which are physical instructions).

Pseudo-ops should not be confused with assembler directives, such as .text, .data, .word, .eqv, etc.

Some pseudo-ops can overlap with actual physical instructions. That is what is happening with your example.

In fact, the assembler examines any given instruction as a potential pseudo-op. It may determine that in can fulfill the intent with a single physical instruction. If not, it will generate a 1-3 instruction sequence and may use the [reserved] $at register [which is $1] as part of that sequence.

In mars, to see the actual real instructions, look in the Basic column of the source window.

For the sake of the completeness of my answer, all that follows is prefaced by the top comments.

I've created three example programs:

  1. The addi as in your original post
  2. The andi as in your corrected post
  3. An andi that uses an unsigned argument


(1) Here is the assembler source for your original question using addi:

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

Here is how mars interpreted it:

 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 will sign extend its 16 bit immediate, so we have 0xFFFFFFFF. Then, doing a two's complement add operation, we have a final result of 0x5555554F

Thus, the assembler didn't need to generate extra instructions for the addi, so the addi pseudo-op generated a single real addi


(2) Here is the andi source:

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

Here is the assembly:

 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

Whoa! What happened? The andi generated three instructions.

A real andi instruction does not sign extend its immediate argument. So, the largest unsigned value we can use in a real andi is 0xFFFF

But, by specifying -1, we told the assembler that we did want sign extension (i.e. 0xFFFFFFFF)

So, the assembler could not fulfull the intent with a single instruction and we get the sequence above. And the generated sequence could not use andi but had to use the register form: and. Here is the andi generated code converted back into more friendly asm source:

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

As to result, we're anding 0x55555550 and 0xFFFFFFFF which is a [still unchanged] value of 0x55555550


(3) Here is the source for an unsigned version of andi:

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

Here is the assembler output:

 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

When the assembler sees that we're using a hex constant (i.e. the 0x prefix), it tries to fulfill the value as an unsigned operation. So, it doesn't need to sign extend. And, the real andi can fulfill the request.

The result of this is 0x5550

Note that if we had used a mask value of 0x1FFFF, that would be unsigned. But, it's larger than 16 bits, so the assembler would generate a multi-instruction sequence to fulfill the request.

And, the result here would be 0x15550

这篇关于MIPS中的Andi与Addi指令的立即数为负的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆