Control Flow Instructions
| instr | description |
|---|---|
| beq rs1, rs2, imm[12:1] | Branch to pc + sext(imm) if rs1 = rs2 |
| bne rs1, rs2, imm[12:1] | Branch to pc + sext(imm) if rs1 ≠ rs2 |
| blt rs1, rs2, imm[12:1] | Branch to pc + sext(imm) if (int)rs1 < (int)rs2_ |
| bltu rs1, rs2, imm[12:1] | Branch to pc + sext(imm) if (uint)rs1 < (uint)rs2 |
| bge rs1, rs2, imm[12:1] | Branch to pc + sext(imm) if (int)rs1 >= (int)rs2_ |
| bgeu rs1, rs2, imm[12:1] | Branch to pc + sext(imm) if (uint)rs1 >= (uint)rs2 |
| jal rd, imm[20:1] | Jump and link |
| jalr rd, rs1, imm[11:0] | Jump and link register |
Conditional branches
A conditional jump to anywhere in range of ±4 KiB (1K instructions)
relative to pc (at 16 bit boundary).
Jump-and-link
jal rd, imm[20:1] (jump-and-link):
- writes the address of the subsequent instruction (
pc + 4) to rd - sets
pctopc + sext(imm), allowing for jumps in a ±1MiB range.
Note: a one-way "goto" can be jal x0, offset to discard the "return" address.
"Long jumps" (to an arbitrary 32-bit offset) can be done with:
auipc x1, offset[31:12]
jalr x0, offset[11:0](x1)
Jump-and-link-register
jalr rd, rs1, imm[11:0] allows for indirect jumps (switch statements, function returns, indirect function calls, vtable dispatch, etc):
- write the address of the next instruction (
pc + 4) into rd - set
pctopc + rs1 + sext(imm)
TODO: if rd is rs1, does it use the original value?
Encoding
jal is UJ-type.
| imm[20,10:1,11,19:12] | rd | opcode | |
|---|---|---|---|
| jal | 11 011 11 |
jalr is I-type.
| imm[11:0] | rs1 | funct3 | rd | opcode | |
|---|---|---|---|---|---|
| jalr | 000 | 11 001 11 |
Conditional branches are SB-type
| imm[12,10:5] | rs2 | rs1 | funct3 | imm[4:1,11] | opcode | |
|---|---|---|---|---|---|---|
| beq | 000 | 11 000 11 | ||||
| bne | 001 | 11 000 11 | ||||
| blt | 100 | 11 000 11 | ||||
| bge | 101 | 11 000 11 | ||||
| bltu | 110 | 11 000 11 | ||||
| bgeu | 111 | 11 000 11 |
Least significant byte 6_/E_ encodes a branch instruction:
63/E3for conditional jumps67/E7for jalr6F/EFfor jal