MIPS 中 ori 操作和 lui 之后的 add 操作有什么区别?
What is the difference between an ori operation and an add operation after lui in MIPS?
我想将 3*2^16 + 9
存储在 $t0
中。我做了 lui $t0,3
和 addi $t0,$t0,3
。顺便说一句,在教科书中,值是通过lui
之后的ori
操作创建的。我这样做的方式有问题吗?两者有什么区别?
What is the difference between the two?
ori
和 addi
都允许 16 位立即数。
但是,ori
会将立即数扩展为零,也就是说,立即数总是被视为正数,因此在32位中,扩展立即数的高16位将为零。
而 addi
将对立即数进行符号扩展,因此它被视为 16 位有符号值,可以是正数也可以是负数。
两者都可以,但是在使用addi
时我们必须注意以下几点:如果低16位设置了符号位,那么根据符号扩展和加法的性质,它会产生效果要减少上部,所以需要在上部立即数上加一。例如,假设我们要加载一个常量 0x23458765。 lui
应该被赋予 0x2346 而不是 0x2345,然后 addi
得到 0x8765,这是负的 16 位有符号立即数,因此将从 [=15= 提供的 0x23460000 中减去 1 ], 使其成为 0x23458765.
另一个区别是 addi
会在溢出时陷入困境,这在这里是非常不受欢迎的副作用。 ori
不会陷入溢出。但是,我们可以改用 addiu
,因为它也不会陷入溢出并使用与 addi
.
相同的 16 位有符号立即数
注意:汇编程序通常会按照您的意图进行操作,而不是完全按照您指定的方式进行操作。在某些汇编程序中将 0x8765 与 addi
或 addiu
一起使用将生成多条指令以将该数字容纳为正数。例如,如果你想用 MARS 测试上述序列,我们必须使用 -30875(10) 而不是 0x8765 来让汇编器生成立即数 0x8765,否则它将使用多条指令构建+34661(10)。 (将 -30875 与 ori
一起使用也会生成多条指令,因此我们必须使用 0x8765 或 34661 在一条指令中获得立即数。)
Is there something wrong with the way I did it?
总而言之,您可以使用任何您喜欢的代码序列来构建您的常量。虽然有些文本只会显示一种方式,但其他方式当然是可能的,而且没有“正确”的方式。
话虽这么说,但是,如果您使用的是汇编程序伪函数 %hi
和 %lo
,它们是为与 addiu
一起使用而设计的——这意味着 %hi
将如果低 16 位显示为负立即数,则执行 +1。这些函数的用法如下: lui $t0, %hi(label); addiu $t0, $t0, %lo(label)
— 其中 label
是(代码或数据)标签,但也可以是 32 位常量。 (MARS 不支持这些功能,所以对于 MARS,我们使用 li
或 la
伪指令代替,它会根据需要生成一两个指令。)
%hi
和 %lo
以这种方式工作的原因是有时序列使用加载(例如 lw
)或存储(例如 sw
) addiu
,并且所有加载和存储也使用相同的 16 位带符号立即数(因此当低 16 位变为负数时,也会产生递减上部的潜在影响)。 (那些序列 (lui
;lw
/sw
) 可以在这里和那里保存指令,例如,如果意图是访问全局变量。)
我想将 3*2^16 + 9
存储在 $t0
中。我做了 lui $t0,3
和 addi $t0,$t0,3
。顺便说一句,在教科书中,值是通过lui
之后的ori
操作创建的。我这样做的方式有问题吗?两者有什么区别?
What is the difference between the two?
ori
和 addi
都允许 16 位立即数。
但是,ori
会将立即数扩展为零,也就是说,立即数总是被视为正数,因此在32位中,扩展立即数的高16位将为零。
而 addi
将对立即数进行符号扩展,因此它被视为 16 位有符号值,可以是正数也可以是负数。
两者都可以,但是在使用addi
时我们必须注意以下几点:如果低16位设置了符号位,那么根据符号扩展和加法的性质,它会产生效果要减少上部,所以需要在上部立即数上加一。例如,假设我们要加载一个常量 0x23458765。 lui
应该被赋予 0x2346 而不是 0x2345,然后 addi
得到 0x8765,这是负的 16 位有符号立即数,因此将从 [=15= 提供的 0x23460000 中减去 1 ], 使其成为 0x23458765.
另一个区别是 addi
会在溢出时陷入困境,这在这里是非常不受欢迎的副作用。 ori
不会陷入溢出。但是,我们可以改用 addiu
,因为它也不会陷入溢出并使用与 addi
.
注意:汇编程序通常会按照您的意图进行操作,而不是完全按照您指定的方式进行操作。在某些汇编程序中将 0x8765 与 addi
或 addiu
一起使用将生成多条指令以将该数字容纳为正数。例如,如果你想用 MARS 测试上述序列,我们必须使用 -30875(10) 而不是 0x8765 来让汇编器生成立即数 0x8765,否则它将使用多条指令构建+34661(10)。 (将 -30875 与 ori
一起使用也会生成多条指令,因此我们必须使用 0x8765 或 34661 在一条指令中获得立即数。)
Is there something wrong with the way I did it?
总而言之,您可以使用任何您喜欢的代码序列来构建您的常量。虽然有些文本只会显示一种方式,但其他方式当然是可能的,而且没有“正确”的方式。
话虽这么说,但是,如果您使用的是汇编程序伪函数 %hi
和 %lo
,它们是为与 addiu
一起使用而设计的——这意味着 %hi
将如果低 16 位显示为负立即数,则执行 +1。这些函数的用法如下: lui $t0, %hi(label); addiu $t0, $t0, %lo(label)
— 其中 label
是(代码或数据)标签,但也可以是 32 位常量。 (MARS 不支持这些功能,所以对于 MARS,我们使用 li
或 la
伪指令代替,它会根据需要生成一两个指令。)
%hi
和 %lo
以这种方式工作的原因是有时序列使用加载(例如 lw
)或存储(例如 sw
) addiu
,并且所有加载和存储也使用相同的 16 位带符号立即数(因此当低 16 位变为负数时,也会产生递减上部的潜在影响)。 (那些序列 (lui
;lw
/sw
) 可以在这里和那里保存指令,例如,如果意图是访问全局变量。)