我正在尝试将 64 位加载到寄存器中,所以我将其分成两个 32 位,然后在最后将它们组合在一起。
;Use lui and addi to store 0x1234587811223344 in x5
c: EQU 0x1234587811223344
lui x6, (c & 0xffffffff) >> 12
addi x6, x6, c & 0xfff
lui x7, c >> 44
addi x7, x7, (c & 0xfff00000000) >> 32
slli x7, x7, 32
or x5, x6, x7
所以第一部分工作正常。它将0x11223000加载到 x6 中,然后将最后 3 个相加以成为0x11223344。
第二部分是出于某种原因似乎没有的地方。它加载0x12345000然后当它应该添加该 32 位序列的最后 3 个时,它会将整个内容更改为 0x12344878 而不是0x12345878。
我处理这个问题的方式有什么错误吗?
RISC V 在所有 12 位即时使用符号扩展。
当尝试加载不适合有符号 12 位的常量时,各种工具将接受或给出不同的错误消息,并且这可能因使用的语法而异,例如十六进制与十进制表示法。
似乎您的汇编程序允许该值,然后创建指令addi x7, x7, 0x878
。 但是,在执行过程中,处理器将在内部创建常量0xffffffff878并将其添加到寄存器中,这当然会产生从上部 20 位中减去 1 的效果。
如果您想在单步调试中更预先看到这一点,请使用addi x8, x0, 0x878
,您将看到符号扩展,然后可能后跟add x7, x7, x8
,您将更明确地看到加法对上部的影响。
顺便说一句,将一行代码分解为更小的片段/两行代码是调试曲目中的好工具——在这里将即时的形成与其他内容的添加分开。
一些汇编程序支持li
来形成常量,la
从标签中形成地址——这些是伪指令,可以扩展到两个实际的机器指令,而另一些则支持%hi()
和%lo()
函数。
在这两种情况下,汇编程序都会看到完整的常量值,它为我们所做的是,如果设置了常量的第 12 位,它将向上(20 位)常量调整 +1,以减轻符号扩展,当两个部分一起使用时,该扩展将对上部产生 -1 影响。
显然,由于您正在使用带有硬编码常量的单个指令,因此您需要自己进行此调整。
我希望汇编程序给出错误或至少警告常量0x878不适合 12 位签名......
MIPS 使用 16 位即时,用于lui
和ori
和addi
。 但是,ori
使用零扩展名,而addi
使用符号扩展名。
因此,您可能认为最好的方法是将lui
与ori
一起使用,以避免符号扩展和 -1 偏移,然后需要在lui
中使用 +1 。 但是,在编程中,我们经常想要一个像lui
后跟lw
的序列,在它们之间也形成一个 32 位常量(同时也访问内存)。 然而,由于lw
像addi
一样在即时执行符号扩展,社区(汇编器和链接器)提供了+1偏移,并选择不创建第二种机制(不是+1上层立即)用于ori
和零扩展立即。