RISC-V加载常量(立即数或地址)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了RISC-V加载常量(立即数或地址)相关的知识,希望对你有一定的参考价值。


RISC-V使用​​I-type​​​格式的指令和​​U-type​​​格式的指令加载立即数,​​I-type​​​格式包含12位立即数,​​U-type​​​格式包含20位立即数,而且这20位是加载到寄存器的高20位的。所以,一条​​I-type​​​指令加上一条​​U-type​​​指令就可以加载32位的常量,包括32位的立即数或内存地址。有些情况下只需要一条​​I-type​​​指令,或者一条​​U-type​​指令就可以了。

mingdu.zheng at gmail dot com

​I-type​​​和​​U-type​​指令格式定义如下:

RISC-V加载常量(立即数或地址)_寄存器

小常量

这里的小常量是指 ​​-2048 ~ 2047​​​ 之间的常量,​​I-type​​​格式的12位立即数是表示成有符号数的,所以其立即数能表示的范围就是 ​​-2048 ~ 2047​​​ ,这个范围内的小常量只需要使用一条 ​​I-type​​​指令就可以了,不需要额外的​​U-type​​指令。例如加载常量1234到寄存器x14:

addi  x14,x0,1234

低12位为零的32位常量

这种常量值需要​​U-type​​​指令,不需要额外的​​I-type​​指令,例如加载常量0x12345000:

lui   x14,0x12345

其它32位常量

除了上述两种特殊情况之外的其它32位常量,都需要​​I-type​​​指令和​​U-type​​指令配合加载常量,例如加载常量0x12345678:

lui   x15,0x12345 # 首先加载常量的高20位
addi x15,x15,0x678 # 再将低12位加到高20位

和 Cortex-M 对比

相比之下,Cortex-M 加载32位常量,通常要把常量存储在代码段,然后通过​​LDR​​指令从代码段读取。RISC-V加载32位常量使用2条指令,占用8个字节;Cortex-M加载常量使用1条指令和1条常量,占用6个字节或8个字节(有16位长的LDR指令,也有32位长的LDR指令)。RISC-V使用2条指令,只需要访问指令总线,没有存储器加载的延时和总线冲突,Cortex-M因为要从代码段加载,既要访问指令总线也要访问数据总线,会有存储器加载延时和可能的总线冲突。

RV32 加载64位常量

在RV32架构下,需要两个寄存器来存储64位数,理论上讲可以使用两组​​I-type​​​和​​U-type​​组合就可以加载64位常量,例如加载常量0x1234567812345678:

# 低32位存储在x14
lui x14,0x12345
addi x14,x14,0x678
# 高32位存储在x15
lui x15,0x12345
addi x15,x15,0x678

但是,目前GCC给出的编译结果如下:

lui   x14,0x8000
lw x12,0(x14)
lw x13,4(x14)

首先把64位常量存储在代码段,然后使用​​lw​​指令加载。

RV64 加载64位常量

也是先把64位常量存储在代码段,然后使用​​ld​​指令加载,RV64使用1个寄存器就可以存储64位数了,所以这回只需要加载一次:

lui   x14,0x8000
ld x14,0(x14)


以上是关于RISC-V加载常量(立即数或地址)的主要内容,如果未能解决你的问题,请参考以下文章

ARM 汇编指令 ADR 与 LDR 使用

汇编语言中啥是立即数

使用 C# 中的方法更改另一个范围内的变量值

如何立即从范围内取消Kotlin协程(返回)?]

RISC-V指令集介绍 - 整数基本指令集

如何定义常量在全局范围内nodejs