MIPS 程序集,lui 0x1001

MIPS Assembly, lui 0x1001

我有一个作业,我必须在其中解释有关以下 MIPS 汇编代码的一些事情:

.data
x: .word 4711
y: .word 10
z: .word 0x0A91
e: .word 0

.text
.globl main
main:
lw , x
lw , y
lw , z
add , , 
sub , , 
sw , e
li , 10
syscall

第一条指令lw , x在assembled时被分成两条指令。指令是 lui , 0x00001001 后跟 lw , 0x00000000()。我明白lui将十六进制值1001移到寄存器的上半部分,此时$1中存储的值为0x10010000,但我完全不明白1001是从哪里来的,第二条指令是什么意思。我真的很感激任何关于 subject.I 的帮助,我正在使用 MARS 来 assemble 和 运行 这个程序。

MIPS 指令是 32 位长,程序使用的地址也是如此。
这意味着 lw 指令无法将完整的 32 位地址指定为立即数。 简单地说,指令 lw $t, var 无效(预计极少数情况)。

其实它的编码是

lw $t, offset($s)
1000 11ss ssst tttt iiii iiii iiii iiii

其中 i 位表示只有 16 位用于指定地址(并且必须始终指定基址寄存器,最终 $zero 寄存器可以被使用)。

所以汇编器做了这个把戏:每当你使用 lw $t, var 时,它都会将该指令汇编成 两条 指令,一条指令将地址的高 16 位加载到$atlw 使用 $at 作为基址寄存器,地址的低 16 位作为偏移量。

lui $at, ADDR_H            #ADDR_H is ADDR >> 16
lw $t, ADDR_L($at)         #ADDR_L is ADDR & 0xffff

请注意,由于 lw$at + ADDR_L 读取,因此使用的最终地址是 ADDR_H << 16 + ADDR_L = ADDR。不出所料。

这里有微妙之处,指出(非常感谢他),见下文

这种不直接映射到ISA的指令被称为伪指令$at 寄存器是为汇编程序保留的,正是为了实现它们。


在 MARS 中,您可以通过取消选中 设置 > 允许扩展(伪)指令和格式来禁用伪指令
虽然没有伪指令的编程会很快变得烦人,但至少值得做一次,以充分理解 MIPS 体系结构。


正确地注意到 16 位偏移立即数在添加到基址寄存器之前是 符号扩展
这需要更正我称为 ADDR_H 的值,以防 ADDR_L 在被解释为 16 位二进制补码时结果为负数。
如果结果为真,则必须增加 ADDR_H
ADDR_H 的一般公式可以更正为 ADDR_H = ADDR >> 16 + ADDR[15] 其中 ADDR[15] 表示 ADDR 的第 15 位(即 ADDR_L 的符号位)的值。