我有一项任务,我必须解释有关以下MIPS汇编代码的一些内容:
.data
x: .word 4711
y: .word 10
z: .word 0x0A91
e: .word 0
.text
.globl main
main:
lw $2, x
lw $3, y
lw $4, z
add $2, $2, $3
sub $3, $2, $4
sw $3, e
li $2, 10
syscall
第一条指令lw $2, x
在组装时分为两条指令。说明为lui $1, 0x00001001
,后跟lw $2, 0x00000000($1)
。我知道lui将十六进制值1001移动到寄存器的上半部分,此时存储在$ 1中的值是0x10010000,但我不明白1001的来源和第二条指令的含义。我真的会在这个主题上找到任何帮助。我正在使用MARS来组装和运行这个程序。
答案 0 :(得分:2)
MIPS指令长度为32位,程序使用的地址也是如此
这意味着lw
指令无法将完整的32位地址指定为立即数。
简而言之,指令lw $t, var
无效(预计极少数情况下)。
实际上,它的编码是
lw $t, offset($s)
1000 11ss ssst tttt iiii iiii iiii iiii
i 位表示只有16位用于指定地址(并且必须始终指定基址寄存器,最终可以使用$zero
寄存器)。< / p>
所以汇编程序就是这样做的:无论何时使用lw $t, var
,它都会将该指令汇编成两个指令,一个将地址的高16位加载到$at
的指令和lw
使用$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 &lt;&lt; 16 + ADDR_L = ADDR 。正如所料。
这里有微妙之处,由Mike Spivey指出(非常感谢他),见下文
这种没有直接映射到ISA的指令称为伪指令。
$at
寄存器保留给汇编程序,完全用于实现它们。
在MARS中,您可以通过取消选中设置&gt;来停用伪指令。允许扩展(伪)指令和格式 虽然没有伪指令的编程会很快变得烦人,但至少要做一次,以完全理解MIPS架构。
Mike Spivey正确地注意到16位偏移立即数是符号扩展,然后才被添加到基址寄存器。
这需要更正我称为ADDR_H
的值,以防ADDR_L
在被解释为16位二进制补码数时变为负值。
如果结果为真,则ADDR_H
必须递增
ADDR_H
的通用公式可以更正为ADDR_H = ADDR >> 16 + ADDR[15]
,其中ADDR[15]
表示ADDR
的第15位的值(ADDR_L
的符号位。< / p>