RISC-V 中 JAL 和 JALR 指令的偏移地址
Offset address for JAL and JALR instrctions in RISC-V
在RISC-V规范中,写了JAL和JALR指令中的立即数转换为跳转偏移量为:
将给定的立即数符号扩展到 XLEN 位。
将 LSB 设置为零。
关于这个我有几个问题。
问题 1
对于 JAL,这给出了一个范围:
000000000000 to 111111111110
也就是4KiB。
在这里,如果 LSB 必须始终为零,为什么立即数不被视为地址的强制性 0 LSB 之前的 12 位,从而将地址范围增加到:
[000000000000]0 to [111111111111]0
[ ]表示给定的立即数偏移量,在给定的立即数偏移量的末尾内部添加一个零。也就是说,
左移一位给地址
将结果符号扩展为 XLEN 位。
问题 2
如何区分正偏移和负偏移?是否使用了给定偏移量的 MSB?
JAL
有一个 20 位偏移量和一个寄存器作为操作数。
它的运算是pc := pc + sxt ( imm20 << 1 )
.
从公式可以看出,分支是相对于 pc 的。立即数可以从 JAL
本身达到 +/- 1 MB。立即数移动一位,真正的 LSB 始终为零,因此未编码。
因为 RISC V 支持 16 位(两个字节)的倍数指令,我们不能假设下一个 LSB 也为零,就像 MIPS(具有 32 位指令)一样。
除了执行分支之外,JAL
中的寄存器操作数可选择用于捕获 return 地址。
JAL
的功能是使用其 20 位范围执行适度远的 pc 相关分支或调用。 (与 RISC V 条件分支指令对比,后者只有 12 位用于 +/- 4 KB 范围。)
JALR
有一个 12 位偏移量和两个寄存器作为操作数。
它的运算是pc := ( rs1 + sxt ( imm12 ) ) & -2
.
从公式可以看出,分支是寄存器间接的,相对于rs1
中的值。
像JAL
一样,JALR
也可以捕获return地址。
JALR
用于从函数 return(在汇编中又名 RET
。在这种形式中 $ra 用作源寄存器,没有 return地址被捕获)。这使用零作为偏移量(即不需要偏移量)。
JALR
也用于执行间接函数调用:通过函数指针调用、虚拟方法分派等。这些使用也使用零作为偏移量。
JALR
也可以和AUIPC
顺序使用。
AUIPC
有一个 20 位偏移量和一个寄存器作为操作数。
它的运算是rd := pc + ( imm20 << 12 )
.
它计算与 pc 相关的立即数的上半部分(同时还提供与 pc 无关的下半部分)。
结合JALR
,可以完成32位pc-relative分支或调用。
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
在RISC-V规范中,写了JAL和JALR指令中的立即数转换为跳转偏移量为:
将给定的立即数符号扩展到 XLEN 位。
将 LSB 设置为零。
关于这个我有几个问题。
问题 1
对于 JAL,这给出了一个范围:
000000000000 to 111111111110
也就是4KiB。
在这里,如果 LSB 必须始终为零,为什么立即数不被视为地址的强制性 0 LSB 之前的 12 位,从而将地址范围增加到:
[000000000000]0 to [111111111111]0
[ ]表示给定的立即数偏移量,在给定的立即数偏移量的末尾内部添加一个零。也就是说,
左移一位给地址
将结果符号扩展为 XLEN 位。
问题 2
如何区分正偏移和负偏移?是否使用了给定偏移量的 MSB?
JAL
有一个 20 位偏移量和一个寄存器作为操作数。
它的运算是pc := pc + sxt ( imm20 << 1 )
.
从公式可以看出,分支是相对于 pc 的。立即数可以从 JAL
本身达到 +/- 1 MB。立即数移动一位,真正的 LSB 始终为零,因此未编码。
因为 RISC V 支持 16 位(两个字节)的倍数指令,我们不能假设下一个 LSB 也为零,就像 MIPS(具有 32 位指令)一样。
除了执行分支之外,JAL
中的寄存器操作数可选择用于捕获 return 地址。
JAL
的功能是使用其 20 位范围执行适度远的 pc 相关分支或调用。 (与 RISC V 条件分支指令对比,后者只有 12 位用于 +/- 4 KB 范围。)
JALR
有一个 12 位偏移量和两个寄存器作为操作数。
它的运算是pc := ( rs1 + sxt ( imm12 ) ) & -2
.
从公式可以看出,分支是寄存器间接的,相对于rs1
中的值。
像JAL
一样,JALR
也可以捕获return地址。
JALR
用于从函数 return(在汇编中又名 RET
。在这种形式中 $ra 用作源寄存器,没有 return地址被捕获)。这使用零作为偏移量(即不需要偏移量)。
JALR
也用于执行间接函数调用:通过函数指针调用、虚拟方法分派等。这些使用也使用零作为偏移量。
JALR
也可以和AUIPC
顺序使用。
AUIPC
有一个 20 位偏移量和一个寄存器作为操作数。
它的运算是rd := pc + ( imm20 << 12 )
.
它计算与 pc 相关的立即数的上半部分(同时还提供与 pc 无关的下半部分)。
结合JALR
,可以完成32位pc-relative分支或调用。
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