在 RISC-V 规范中,写到 JAL 和 JALR 指令中的立即数被转换为跳转偏移量:
将给定的立即数符号扩展到 XLEN 位。
将 LSB 设置为零。
关于这个,我有几个问题。
问题 1
对于 JAL,这给出了一个范围:
000000000000 to 111111111110
Run Code Online (Sandbox Code Playgroud)
也就是说,4KiB。
在这里,如果 LSB 必须始终为零,为什么不将立即数视为地址的强制零 LSB 之前的 12 位,从而将地址范围增加到:
[000000000000]0 to [111111111111]0
Run Code Online (Sandbox Code Playgroud)
[ ] 表示给定的立即数偏移量,内部在给定的立即数偏移量的末尾添加一个零。那是,
左移一点点给出地址。
将结果符号扩展到 XLEN 位。
问题2
如何区分正偏移和负偏移?是否使用了给定偏移量的 MSB?
JAL有一个 20 位偏移量和一个寄存器作为操作数。
其操作是pc := pc + sxt ( imm20 << 1 ).
从公式中可以看出,分支是与 pc 相关的。立即数可以达到 +/- 1 MBJAL。立即数移位一位,真正的 LSB 始终为零,因此不进行编码。
由于 RISC V 支持 16 位倍数(两个字节)的指令,因此我们不能假设下一个 LSB 也为零,就像 MIPS(具有 32 位指令)一样。
除了执行分支之外,JAL还可以选择使用寄存器操作数来捕获返回地址。
JAL的功能是使用其 20 位范围执行相对较远的 pc 分支或调用。(与 RISC V 条件分支指令相比,RISC V 条件分支指令只有 12 位,范围为 +/- 4 KB。)
JALR有一个 12 位偏移量和两个寄存器作为操作数。
其操作是pc := ( rs1 + sxt ( imm12 ) ) & -2.
从公式中可以看出,分支是寄存器间接的,相对于 中的值rs1。
同样JAL,JALR也可以捕获返回地址。
JALR用于从函数返回(也称为RET汇编。在这种形式中,$ra 用作源寄存器,并且不捕获返回地址)。这使用零作为偏移量(即不需要偏移量)。
JALR还用于执行间接函数调用:通过函数指针、虚拟方法分派等进行调用。这些用途也使用零作为偏移量。
JALR也可以与 顺序使用AUIPC。
AUIPC有一个 20 位偏移量和一个寄存器作为操作数。
其操作是rd := pc + ( imm20 << 12 ).
它计算 pc 相对立即数的上半部分(同时还提供非相对 pc 的下半部分)。
与 结合使用JALR,可以完成 32 位 pc 相关的分支或调用。
AUIPC r5, labelFarAway # AUIPC encodes upper 20 bits of label's distance from pc
JALR r5, $ra, labelFarAway # JALR encodes the lower 12 bits of same
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2194 次 |
| 最近记录: |