为什么我不能将 64 位正确加载到寄存器中?



我正在尝试将 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 位即时,用于luioriaddi。 但是,ori使用零扩展名,而addi使用符号扩展名。

因此,您可能认为最好的方法是将luiori一起使用,以避免符号扩展和 -1 偏移,然后需要在lui中使用 +1 。 但是,在编程中,我们经常想要一个像lui后跟lw的序列,在它们之间也形成一个 32 位常量(同时也访问内存)。 然而,由于lwaddi一样在即时执行符号扩展,社区(汇编器和链接器)提供了+1偏移,并选择不创建第二种机制(不是+1上层立即)用于ori和零扩展立即。

最新更新