MIPS 中的 andi 与 addi 指令的负立即数
andi vs. addi instruction in MIPS with negative immediate constant
假设$t2=0x55555550
,则执行如下指令:
andi $t2, $t2, -1
$t2 变为 0x0005550
MIPS 仿真器证实了这一点1
然而,这不是我所期望的。我认为答案应该是 0x55555550 & 0xFFFFFFFF = 0x55555550。
我认为常量 -1 在 and 逻辑之前被符号扩展为 0xFFFFFFFF。但看起来答案是 0x55555550 & 0x0000FFFF
为什么-1符号扩展为0x0000FFFF而不是0xFFFFFFFF
脚注 1:编者注:启用 "extended pseudo-instructions" 的 MARS 确实将其扩展为多条指令以在 tmp 寄存器中生成 0xffffffff
,从而使 $t2
保持不变。否则 MARS 和 SPIM 都会以不可编码的错误拒绝它。其他汇编程序可能不同。
根据specification,立即数是16位宽。
因此,andi $t2, $t2, -1
可以读作andi $t2, $t2, 0xFFFF
。
所有逻辑运算都将立即数视为位串,并将其零扩展为 32 位。
你的预期是正确的,但你对实验结果的解释不是
$t2 becomes 0x0005550 This is confirmed by the MIPS emulator.
不,这是不正确的。所以,以下之一:
- 不知何故,您误读了模拟器的功能。来自模拟器的实际值是您预期的值。
- 或,你在
$t2
之前没有0x55555550
andi
正如您假设的那样,但是 0x5550
相反(即)您的测试程序没有正确设置 $t2
。
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
它不是。它是符号扩展为0xFFFFFFFF
。同样,您对实验结果的解读不正确[或者您的测试程序有错误]。
mips
模拟器和汇编程序有 伪操作 .
这些指令可能作为真实的物理指令存在,也可能不存在。但是,它们被汇编程序解释为生成一系列 physical/real 指令。
"pure" 伪操作的一个例子是 li
("load immediate")。它没有没有对应的指令,但通常会生成两条指令序列:lui
、ori
(其中是物理指令).
伪操作应该不与汇编程序指令混淆,例如.text
、.data
、 .word
、.eqv
等
一些伪操作可以与实际的物理指令重叠。这就是您的示例所发生的情况。
事实上,汇编程序检查任何给定指令作为潜在伪操作。它可以确定 in 可以用单个物理指令实现 intent。如果不是,它将生成一个 1-3 指令序列,并且可以使用 [reserved] $at
寄存器 [这是 </code>] 作为该序列的一部分。</p>
<p>在 <code>mars
中,要查看实际的真实说明,请查看来源 window 的 Basic
列。
为了我回答的完整性,以下所有内容均以热门评论开头。
我创建了三个示例程序:
- 原来的
addi
post
andi
如您更正后的 post
- 使用无符号参数的
andi
(1) 这是您使用 addi
:
原始问题的汇编程序源
.text
.globl main
main:
li $t2,0x55555550
addi $t3,$t2,-1
nop
mars
对其的解释如下:
Address Code Basic Source
0x00400000 0x3c015555 lui ,0x00005555 4 li $t2,0x55555550
0x00400004 0x342a5550 ori ,,0x00005550
0x00400008 0x214bffff addi ,,0xffffffff 5 addi $t3,$t2,-1
0x0040000c 0x00000000 nop 6 nop
addi
将 符号扩展 它的 16 位立即数,所以我们有 0xFFFFFFFF
。然后,进行 补码 加法运算,最终结果为 0x5555554F
因此,汇编程序不需要为 addi
生成额外的指令,因此 addi
伪操作 生成了一个 真实addi
(2) 这是 andi
来源:
.text
.globl main
main:
li $t2,0x55555550
andi $t3,$t2,-1
nop
这是程序集:
Address Code Basic Source
0x00400000 0x3c015555 lui ,0x00005555 4 li $t2,0x55555550
0x00400004 0x342a5550 ori ,,0x00005550
0x00400008 0x3c01ffff lui ,0xffffffff 5 andi $t3,$t2,-1
0x0040000c 0x3421ffff ori ,,0x0000ffff
0x00400010 0x01415824 and ,,
0x00400014 0x00000000 nop 6 nop
哇! 发生什么事了? andi
生成了三个指令。
A real andi
指令 not 符号扩展其直接参数。因此,我们可以在真实 andi
中使用的最大 unsigned 值是 0xFFFF
但是,通过指定 -1
,我们告诉汇编程序我们 确实 想要符号扩展(即 0xFFFFFFFF
)
所以,汇编器可以而不是用一条指令完成意图,我们得到上面的序列。并且生成的序列可以不使用andi
但必须使用寄存器形式:and
。这是 andi
生成的代码转换回更友好的 asm 源代码:
lui $at,0xFFFF
ori $at,$at,0xFFFF
and $t3,$t2,$at
至于结果,我们将 0x55555550
和 0xFFFFFFFF
相加,这是 0x55555550
的 [仍然不变] 值
(3) 这是 unsigned 版本的 andi
:
的来源
.text
.globl main
main:
li $t2,0x55555550
andi $t3,$t2,0xFFFF
nop
这里是汇编输出:
Address Code Basic Source
0x00400000 0x3c015555 lui ,0x00005555 4 li $t2,0x55555550
0x00400004 0x342a5550 ori ,,0x00005550
0x00400008 0x314bffff andi ,,0x0000ffff 5 andi $t3,$t2,0xFFFF
0x0040000c 0x00000000 nop 6 nop
当汇编程序发现我们正在使用十六进制常量(即 0x
前缀)时,它会尝试将值作为 unsigned 操作来实现。所以,它不需要签署扩展。而且,真正的andi
可以满足要求。
结果是0x5550
请注意,如果我们使用 0x1FFFF
的掩码值,那将是无符号的。但是,它大于 16 位,因此汇编程序将生成一个多指令序列来满足请求。
而且,这里的结果将是 0x15550
从这个参考文献sheet,对于andi指令,它清楚地表明在立即数上完成的符号扩展是零扩展。 ori 指令也类似。对于您正在使用的操作序列,这正是 MIPS 应该做的。
为了做你打算做的事情,你应该将 0xFFFFFFFF 存储在其他寄存器中,并使用“and”操作。
假设$t2=0x55555550
,则执行如下指令:
andi $t2, $t2, -1
$t2 变为 0x0005550
MIPS 仿真器证实了这一点1
然而,这不是我所期望的。我认为答案应该是 0x55555550 & 0xFFFFFFFF = 0x55555550。 我认为常量 -1 在 and 逻辑之前被符号扩展为 0xFFFFFFFF。但看起来答案是 0x55555550 & 0x0000FFFF
为什么-1符号扩展为0x0000FFFF而不是0xFFFFFFFF
脚注 1:编者注:启用 "extended pseudo-instructions" 的 MARS 确实将其扩展为多条指令以在 tmp 寄存器中生成 0xffffffff
,从而使 $t2
保持不变。否则 MARS 和 SPIM 都会以不可编码的错误拒绝它。其他汇编程序可能不同。
根据specification,立即数是16位宽。
因此,andi $t2, $t2, -1
可以读作andi $t2, $t2, 0xFFFF
。
所有逻辑运算都将立即数视为位串,并将其零扩展为 32 位。
你的预期是正确的,但你对实验结果的解释不是
$t2 becomes 0x0005550 This is confirmed by the MIPS emulator.
不,这是不正确的。所以,以下之一:
- 不知何故,您误读了模拟器的功能。来自模拟器的实际值是您预期的值。
- 或,你在
$t2
之前没有0x55555550
andi
正如您假设的那样,但是0x5550
相反(即)您的测试程序没有正确设置$t2
。
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
它不是。它是符号扩展为0xFFFFFFFF
。同样,您对实验结果的解读不正确[或者您的测试程序有错误]。
mips
模拟器和汇编程序有 伪操作 .
这些指令可能作为真实的物理指令存在,也可能不存在。但是,它们被汇编程序解释为生成一系列 physical/real 指令。
"pure" 伪操作的一个例子是 li
("load immediate")。它没有没有对应的指令,但通常会生成两条指令序列:lui
、ori
(其中是物理指令).
伪操作应该不与汇编程序指令混淆,例如.text
、.data
、 .word
、.eqv
等
一些伪操作可以与实际的物理指令重叠。这就是您的示例所发生的情况。
事实上,汇编程序检查任何给定指令作为潜在伪操作。它可以确定 in 可以用单个物理指令实现 intent。如果不是,它将生成一个 1-3 指令序列,并且可以使用 [reserved] $at
寄存器 [这是 </code>] 作为该序列的一部分。</p>
<p>在 <code>mars
中,要查看实际的真实说明,请查看来源 window 的 Basic
列。
为了我回答的完整性,以下所有内容均以热门评论开头。
我创建了三个示例程序:
- 原来的
addi
post andi
如您更正后的 post- 使用无符号参数的
andi
(1) 这是您使用 addi
:
.text
.globl main
main:
li $t2,0x55555550
addi $t3,$t2,-1
nop
mars
对其的解释如下:
Address Code Basic Source
0x00400000 0x3c015555 lui ,0x00005555 4 li $t2,0x55555550
0x00400004 0x342a5550 ori ,,0x00005550
0x00400008 0x214bffff addi ,,0xffffffff 5 addi $t3,$t2,-1
0x0040000c 0x00000000 nop 6 nop
addi
将 符号扩展 它的 16 位立即数,所以我们有 0xFFFFFFFF
。然后,进行 补码 加法运算,最终结果为 0x5555554F
因此,汇编程序不需要为 addi
生成额外的指令,因此 addi
伪操作 生成了一个 真实addi
(2) 这是 andi
来源:
.text
.globl main
main:
li $t2,0x55555550
andi $t3,$t2,-1
nop
这是程序集:
Address Code Basic Source
0x00400000 0x3c015555 lui ,0x00005555 4 li $t2,0x55555550
0x00400004 0x342a5550 ori ,,0x00005550
0x00400008 0x3c01ffff lui ,0xffffffff 5 andi $t3,$t2,-1
0x0040000c 0x3421ffff ori ,,0x0000ffff
0x00400010 0x01415824 and ,,
0x00400014 0x00000000 nop 6 nop
哇! 发生什么事了? andi
生成了三个指令。
A real andi
指令 not 符号扩展其直接参数。因此,我们可以在真实 andi
中使用的最大 unsigned 值是 0xFFFF
但是,通过指定 -1
,我们告诉汇编程序我们 确实 想要符号扩展(即 0xFFFFFFFF
)
所以,汇编器可以而不是用一条指令完成意图,我们得到上面的序列。并且生成的序列可以不使用andi
但必须使用寄存器形式:and
。这是 andi
生成的代码转换回更友好的 asm 源代码:
lui $at,0xFFFF
ori $at,$at,0xFFFF
and $t3,$t2,$at
至于结果,我们将 0x55555550
和 0xFFFFFFFF
相加,这是 0x55555550
(3) 这是 unsigned 版本的 andi
:
.text
.globl main
main:
li $t2,0x55555550
andi $t3,$t2,0xFFFF
nop
这里是汇编输出:
Address Code Basic Source
0x00400000 0x3c015555 lui ,0x00005555 4 li $t2,0x55555550
0x00400004 0x342a5550 ori ,,0x00005550
0x00400008 0x314bffff andi ,,0x0000ffff 5 andi $t3,$t2,0xFFFF
0x0040000c 0x00000000 nop 6 nop
当汇编程序发现我们正在使用十六进制常量(即 0x
前缀)时,它会尝试将值作为 unsigned 操作来实现。所以,它不需要签署扩展。而且,真正的andi
可以满足要求。
结果是0x5550
请注意,如果我们使用 0x1FFFF
的掩码值,那将是无符号的。但是,它大于 16 位,因此汇编程序将生成一个多指令序列来满足请求。
而且,这里的结果将是 0x15550
从这个参考文献sheet,对于andi指令,它清楚地表明在立即数上完成的符号扩展是零扩展。 ori 指令也类似。对于您正在使用的操作序列,这正是 MIPS 应该做的。 为了做你打算做的事情,你应该将 0xFFFFFFFF 存储在其他寄存器中,并使用“and”操作。