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
pc
topc + 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
pc
topc + 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
/E3
for conditional jumps67
/E7
for jalr6F
/EF
for jal