Guide · RISC-V

How to decode an RV32I instruction

A five-step method and one example of each format (R, I, S, B, U and J), with how immediates are rebuilt and the most common mistakes.

Reviewed on against the site’s tools.

Decoding an RV32I instruction by hand is a mechanical procedure. If you always follow the same order, the formats with “scrambled” bits stop being a problem. This guide gives the method and applies it to one instruction of each format. All the tables are generated by the site’s decoder.

The five-step method

  1. Convert the word to binary and number the bits from 31 (left) to 0 (right). Each hex digit is 4 bits.
  2. Read the opcode (bits 6–0). It gives the group and, with it, the format. Without this step you do not know what the other bits mean.
  3. Read the fixed fields that format has: rd (11–7), funct3 (14–12), rs1 (19–15), rs2 (24–20) and funct7 (31–25).
  4. Rebuild the immediate by joining its pieces in the order the format defines, and sign-extend from bit 31.
  5. Pick the mnemonic from funct3 (and funct7 when present) and write the instruction with the ABI register names.

RV32I opcode table

opcodeGroupFormatInstructions
0110011OPRadd, sub, and, or, xor, sll, srl, sra, slt, sltu
0010011OP-IMMIaddi, andi, ori, xori, slti, sltiu, slli, srli, srai
0000011LOADIlb, lh, lw, lbu, lhu
1100111JALRIjalr
0100011STORESsb, sh, sw
1100011BRANCHBbeq, bne, blt, bge, bltu, bgeu
0110111LUIUlui
0010111AUIPCUauipc
1101111JALJjal

Three base instructions are missing: FENCE (0001111) and ECALL/EBREAK (1110011). The site’s decoder does not recognize them.

R format: 0x40B50533

Opcode 0110011 → OP group. The R format has no immediate: the 32 bits are shared by two source registers, one destination and two function fields. funct3 = 000 means add or sub, and funct7 decides: 0100000 is sub.

0x40B50533 · R-Type
FieldBitsBinaryMeaning
funct7[31:25]0100000distinguishes variants (0100000 = sub/sra)
rs2[24:20]01011register x11 (a1)
rs1[19:15]01010register x10 (a0)
funct3[14:12]000selects the operation within the group
rd[11:7]01010register x10 (a0)
opcode[6:0]0110011group OP
Instructionsub a0, a0, a1

I format: 0xFFF28293

Opcode 0010011 → OP-IMM. Bits 31–20 are the whole immediate: 111111111111. Since bit 31 is 1, extending it to 32 bits fills with ones and the value is −1. Result: addi t0, t0, -1.

0xFFF28293 · I-Type
FieldBitsBinaryMeaning
imm[11:0][31:20]111111111111piece of the immediate
rs1[19:15]00101register x5 (t0)
funct3[14:12]000selects the operation within the group
rd[11:7]00101register x5 (t0)
opcode[6:0]0010011group OP-IMM
imm-1 (0xFFFFFFFF)rebuilt immediate (signed)
Instructionaddi t0, t0, -1

In immediate shifts (slli, srli, srai) bits 24–20 are the shift amount and bits 31–25 act as funct7: 0100000 tells srai from srli.

S format: 0xFEA42E23

Opcode 0100011 → STORE. A store writes no register, so the rd slot (bits 11–7) holds the 5 low bits of the immediate. The rest is in bits 31–25: imm[11:5] = 1111111 and imm[4:0] = 11100. Together: 111111111100 = −4.

0xFEA42E23 · S-Type
FieldBitsBinaryMeaning
imm[11:5][31:25]1111111piece of the immediate
rs2[24:20]01010register x10 (a0)
rs1[19:15]01000register x8 (s0)
funct3[14:12]010selects the operation within the group
imm[4:0][11:7]11100piece of the immediate
opcode[6:0]0100011group STORE
imm-4 (0xFFFFFFFC)rebuilt immediate (signed)
Instructionsw a0, -4(s0)

The instruction is sw a0, -4(s0): it stores a0 at address s0 − 4. Note that rs2 (a0) is the data and rs1 (s0) is the address base.

B format: 0x00050663

Opcode 1100011 → BRANCH. A branch immediate is a multiple of 2 bytes, so its bit 0 is not stored. The other 12 bits are split into four pieces: imm[12] in bit 31, imm[10:5] in 30–25, imm[4:1] in 11–8 and imm[11] in bit 7.

0x00050663 · B-Type
FieldBitsBinaryMeaning
imm[12][31]0piece of the immediate
imm[10:5][30:25]000000piece of the immediate
rs2[24:20]00000register x0 (zero)
rs1[19:15]01010register x10 (a0)
funct3[14:12]000selects the operation within the group
imm[4:1][11:8]0110piece of the immediate
imm[11][7]0piece of the immediate
opcode[6:0]1100011group BRANCH
imm12 (0xC)rebuilt immediate (signed)
Instructionbeq a0, zero, 12

In order: imm[12] = 0, imm[11] = 0, imm[10:5] = 000000, imm[4:1] = 0110, plus the implicit final 0: 0 0 000000 0110 0 = 12. beq a0, zero, 12 jumps 12 bytes (3 instructions) forward if a0 is 0.

U format: 0x123452B7

Opcode 0110111 → LUI. The upper 20 bits are the immediate and go straight into bits 31–12 of the destination register; the low 12 bits become zero. Here t0 becomes 0x12345000.

0x123452B7 · U-Type
FieldBitsBinaryMeaning
imm[31:12][31:12]00010010001101000101piece of the immediate
rd[11:7]00101register x5 (t0)
opcode[6:0]0110111group LUI
imm74565 (0x12345)rebuilt immediate (signed)
Instructionlui t0, 0x12345

J format: 0x010000EF

Opcode 1101111 → JAL. As in B, bit 0 is not stored and the rest is split: imm[20] in bit 31, imm[10:1] in 30–21, imm[11] in bit 20 and imm[19:12] in 19–12. Here only imm[4] is 1: the jump is 16 bytes and the return address is saved in ra.

0x010000EF · J-Type
FieldBitsBinaryMeaning
imm[20][31]0piece of the immediate
imm[10:1][30:21]0000001000piece of the immediate
imm[11][20]0piece of the immediate
imm[19:12][19:12]00000000piece of the immediate
rd[11:7]00001register x1 (ra)
opcode[6:0]1101111group JAL
imm16 (0x10)rebuilt immediate (signed)
Instructionjal ra, 16

Why are immediates scattered?

RISC-V fixes two things in every format: rs1, rs2 and rd are always in the same positions, and the immediate’s sign bit is always bit 31. The hardware can therefore read registers before knowing which instruction it is, and sign extension always uses the same wire. The price is that S, B and J immediates are chopped up. Between S and B very little changes: the bits are reused shifted by one position, because B does not need bit 0.

Common mistakes

  • Reading bits 31–20 as the immediate before checking the opcode: that only holds for the I format.
  • Forgetting the implicit 0 at the end of B and J immediates (the offset comes out halved).
  • Not sign-extending: 0xFFF in an I immediate is −1, not 4095.
  • For lui, forgetting that the immediate fills the upper bits: lui t0, 1 loads 4096, not 1.
  • Mixing up rs1 and rs2 in stores: the data is rs2 and the base is rs1.

Practise what you read

Decode an R-type instruction

Identify the fields of 0x40B50533. Pay attention to funct7: it is what tells add and sub apart.

0x40B50533

Open in the tool

Decode an instruction with a negative immediate

Convert 0xFFF28293 to binary and split it into fields. Give the format, the opcode, the registers, funct3 and the decimal value of the immediate.

0xFFF28293

Open in the tool

Identify the format from the opcode

Look only at the low 7 bits of each word (the last hex digit and a half) and say which format it belongs to.

Open in the tool

References