10 RISC V Addressing for Wide Immediates and Addresses
Wide Immediate Operands
尽管常数很多时候少于 12 比特,但是也有更长的时候。
lui
(load upper immediate
)可以将 20 比特常数加载到寄存器的 12 到 31 位。最右边的 12 个比特位置为零。因此 32 比特的常数可以通过两个指令表示出来。lui
是 U 型指令,相比其他类型指令,能够处理更大的常数。
Loading a 32-Bit Constant
如何将如下 32 位常数加载到寄存器 x19
中?
lui
加载 12 到 31 比特。
此时 x19
寄存器的值是
然后再加上低 12 比特的值。
可以想见,立即数的大小还会限制加载或存储内存的地址的范围。RISC-V 的汇编语言并没有这个限制,但是汇编器的作者不得不考虑这个问题。
Addressing in Branches
跳转指令只有 12 比特大小的立即数,那么只能表示 4K 大小,后面会解释一种特殊的编码,使得跳转范围可以是 。bne
是 SB 类型的指令,7 位操作码,3 位函数码,两个 5 比特长度表示寄存器信息,只有 12 比特表示立即数了。
jal
类似,只是立即数有 20 比特大小。
如果跳转范围只有 20 比特的地址,那么程序必须很小,不合理。不过,这个值可以表示基于某个寄存器的偏移量,这样的话就能跳转到任意位置。
现在的问题是:以哪个寄存器为准?大部分(SPEC 基准测试有一半分值跳转)if, while
跳转的地址在当前地址的 16 个指令以内,所以基于 PC 寄存器,可以分支跳转到偏移量在 以内的字(word
)处或者跳转到 字处。这足够大部分场景使用了,所以 PC 是一个不错的选择。这种方法称为相对 PC 寻址(PC-relative addressing
)。
但是不得不考虑超过这个范围的情况。RISC-V 提供了两条指令来完成这个事情,lui
加载 12 到 31 比特信息到某个寄存器,jalr
有 12 位的立即数,跳转到寄存器加上 12 位立即数的地方。
RISC-V 指令四字节长,不过设计时希望支持二字节长的指令,所以跳转指令的偏移量表示从寄存器的基准地址偏移半字的长度,所以支持的跳转范围比 字节大一倍。jal
是 半字,即 的范围,12 比特的分支跳转范围也是半字,范围是 13 个比特能够表示的范围。
Showing Branch Offset in Machine Language
之前有一段简单的 C 代码
对应的汇编代码是Loop: slli x10, x22, 2 // Temp reg x10 = i * 4
add x10, x10, x25 // x10 = address of save[i]
lw x9, 0(x10) // Temp reg x9 = save[i]
bne x9, x24, Exit // go to Exit if save[i] != k
addi x22, x22, 1 // i = i + 1
beq x0, x0, Loop // go to Loop
Exit:
Address | Instruction | Instruction | Instruction | Instruction | Instruction | Instruction |
---|---|---|---|---|---|---|
80000 | 0000000 | 00010 | 10110 | 001 | 01010 | 0010011 |
80004 | 0000000 | 11001 | 01010 | 000 | 01010 | 0110011 |
80008 | 0000000 | 00000 | 01010 | 011 | 01001 | 0000011 |
80012 | 0000000 | 11000 | 01001 | 001 | 01100 | 1100011 |
80016 | 0000000 | 00001 | 10110 | 000 | 10110 | 0010011 |
80020 | 1111111 | 00000 | 00000 | 000 | 01101 | 1100011 |
第一个 bne
是从当前位置 80012 向后跳转到 80020 的后面,所以偏移量是 12,第二个 bne
回到循环头部,偏移量是 -20。这里感觉原书有一个印刷错误,最后一行倒数第二个值应该是 01100,和前面的 1111111 是 -20 的补码。
偶尔需要跳转到 12 比特地址之外的地方,那么一个可行的方式是反转条件跳转的判断条件,后面跟着一个无条件跳转。比如下面的例子。
Branching Far Away
下面的汇编是根据 x10
是否等于零跳转到 L1
RISC-V Addressing Mode Summary
多种寻址方式称为寻址模式(addressing modes
)。下图展示了 RISC-V 支持的几种寻址模式。
* 立即寻址(immediate addressing
):操作数是常量,包含在指令里
* 寄存器寻址(register addressing
):操作数是寄存器。
* 基地址寻址(Base or displacement addressing
):操作数是内存的某个地址,地址寄存器的值与指令的立即数之和。
* 相对 PC 寻址(PC-relative addressing
):跳转地址是 PC 地址和偏移量之和。