RISC-V

RISC-V instruction reference: RV32I/RV64I base ISA plus the M, A, C, F/D and V extensions with automatic compression.

Notation

SymbolMeaning
rdDestination register (x0–x31 or ABI name)
rs1 / rs2Source register(s)
immImmediate value
offsetBranch/jump offset or memory displacement
labelLabel reference
csrControl/status register name or address
fd / fs1 / fs2Floating-point register (f0–f31 or ABI name)
vd / vs1 / vs2Vector register (v0–v31)

ABI Register Names

ABIRegABIRegABIRegABIReg
zerox0rax1spx2gpx3
tpx4t0x5t1x6t2x7
s0/fpx8s1x9a0x10a1x11
a2x12a3x13a4x14a5x15
a6x16a7x17s2x18s3x19
s4x20s5x21s6x22s7x23
s8x24s9x25s10x26s11x27
t3x28t4x29t5x30t6x31

Base Integer ISA (RV32I)

Upper-Immediate (U-type)

lui   rd, imm                  # Load upper immediate (bits 31:12)
auipc rd, imm                  # Add upper immediate to PC

Jump (J-type / I-type)

jal   rd, label                # Jump and link (±1 MB)
jal   label                    # Jump and link (rd = ra implied)
jalr  rd, rs1, offset          # Jump and link register
jalr  rs1                      # Jump register (rd = ra, offset = 0)

Branch (B-type)

beq   rs1, rs2, label          # Branch if equal
bne   rs1, rs2, label          # Branch if not equal
blt   rs1, rs2, label          # Branch if less than (signed)
bge   rs1, rs2, label          # Branch if greater or equal (signed)
bltu  rs1, rs2, label          # Branch if less than (unsigned)
bgeu  rs1, rs2, label          # Branch if greater or equal (unsigned)

B-type branches automatically relax from 4-byte short form (±4 KiB) to 8-byte long form (±1 MiB) using inverted-branch + JAL pair.

Load (I-type)

lb    rd, offset(rs1)          # Load byte (sign-extend)
lh    rd, offset(rs1)          # Load halfword (sign-extend)
lw    rd, offset(rs1)          # Load word (sign-extend on RV64)
ld    rd, offset(rs1)          # Load doubleword (RV64 only)
lbu   rd, offset(rs1)          # Load byte (unsigned)
lhu   rd, offset(rs1)          # Load halfword (unsigned)
lwu   rd, offset(rs1)          # Load word (unsigned, RV64 only)
lw    rd, (rs1)                # Bare register = 0(rs1)

Store (S-type)

sb    rs2, offset(rs1)         # Store byte
sh    rs2, offset(rs1)         # Store halfword
sw    rs2, offset(rs1)         # Store word
sd    rs2, offset(rs1)         # Store doubleword (RV64 only)

ALU — Immediate (I-type)

addi  rd, rs1, imm             # Add immediate
slti  rd, rs1, imm             # Set if less than (signed)
sltiu rd, rs1, imm             # Set if less than (unsigned)
xori  rd, rs1, imm             # XOR immediate
ori   rd, rs1, imm             # OR immediate
andi  rd, rs1, imm             # AND immediate

Shift — Immediate

slli  rd, rs1, shamt           # Shift left logical (5-bit shamt RV32, 6-bit RV64)
srli  rd, rs1, shamt           # Shift right logical
srai  rd, rs1, shamt           # Shift right arithmetic

ALU — Register (R-type)

add   rd, rs1, rs2             # Add
sub   rd, rs1, rs2             # Subtract
sll   rd, rs1, rs2             # Shift left logical
slt   rd, rs1, rs2             # Set if less than (signed)
sltu  rd, rs1, rs2             # Set if less than (unsigned)
xor   rd, rs1, rs2             # XOR
srl   rd, rs1, rs2             # Shift right logical
sra   rd, rs1, rs2             # Shift right arithmetic
or    rd, rs1, rs2             # OR
and   rd, rs1, rs2             # AND

RV64I Extensions

W-suffix instructions operate on the lower 32 bits and sign-extend the result:

addiw rd, rs1, imm             # Add word immediate
slliw rd, rs1, shamt           # Shift left word
srliw rd, rs1, shamt           # Shift right logical word
sraiw rd, rs1, shamt           # Shift right arithmetic word
addw  rd, rs1, rs2             # Add word
subw  rd, rs1, rs2             # Subtract word
sllw  rd, rs1, rs2             # Shift left word
srlw  rd, rs1, rs2             # Shift right logical word
sraw  rd, rs1, rs2             # Shift right arithmetic word

M Extension (Multiply / Divide)

mul    rd, rs1, rs2            # Multiply (low bits)
mulh   rd, rs1, rs2            # Multiply high (signed × signed)
mulhsu rd, rs1, rs2            # Multiply high (signed × unsigned)
mulhu  rd, rs1, rs2            # Multiply high (unsigned × unsigned)
div    rd, rs1, rs2            # Signed divide
divu   rd, rs1, rs2            # Unsigned divide
rem    rd, rs1, rs2            # Signed remainder
remu   rd, rs1, rs2            # Unsigned remainder

RV64M W-suffix

mulw  rd, rs1, rs2             # Multiply word
divw  rd, rs1, rs2             # Divide word (signed)
divuw rd, rs1, rs2             # Divide word (unsigned)
remw  rd, rs1, rs2             # Remainder word (signed)
remuw rd, rs1, rs2             # Remainder word (unsigned)

A Extension (Atomics)

Load-Reserved / Store-Conditional

lr.w   rd, (rs1)               # Load reserved word
lr.d   rd, (rs1)               # Load reserved doubleword (RV64)
sc.w   rd, rs2, (rs1)          # Store conditional word
sc.d   rd, rs2, (rs1)          # Store conditional doubleword

Atomic Memory Operations

amoswap.w  rd, rs2, (rs1)     # Atomic swap
amoadd.w   rd, rs2, (rs1)     # Atomic add
amoand.w   rd, rs2, (rs1)     # Atomic AND
amoor.w    rd, rs2, (rs1)     # Atomic OR
amoxor.w   rd, rs2, (rs1)     # Atomic XOR
amomax.w   rd, rs2, (rs1)     # Atomic max (signed)
amomaxu.w  rd, rs2, (rs1)     # Atomic max (unsigned)
amomin.w   rd, rs2, (rs1)     # Atomic min (signed)
amominu.w  rd, rs2, (rs1)     # Atomic min (unsigned)

All atomics support .d suffix for 64-bit (RV64) and ordering suffixes:

amoswap.w.aq   rd, rs2, (rs1) # Acquire
amoswap.w.rl   rd, rs2, (rs1) # Release
amoswap.w.aqrl rd, rs2, (rs1) # Acquire-release

CSR Instructions

Standard CSR Operations

csrrw  rd, csr, rs1            # CSR read/write
csrrs  rd, csr, rs1            # CSR read and set bits
csrrc  rd, csr, rs1            # CSR read and clear bits
csrrwi rd, csr, uimm5          # CSR read/write immediate
csrrsi rd, csr, uimm5          # CSR read and set bits (immediate)
csrrci rd, csr, uimm5          # CSR read and clear bits (immediate)

CSR Pseudo-Instructions

csrr  rd, csr                  # Read CSR (csrrs rd, csr, x0)
csrw  csr, rs1                 # Write CSR (csrrw x0, csr, rs1)
csrs  csr, rs1                 # Set bits in CSR
csrc  csr, rs1                 # Clear bits in CSR
csrwi csr, uimm5               # Write CSR (immediate)
csrsi csr, uimm5               # Set bits (immediate)
csrci csr, uimm5               # Clear bits (immediate)

~50 named CSRs are supported (e.g., mstatus, mtvec, mepc, mcause, mhartid, cycle, time, instret, etc.).

System

ecall                          # Environment call (syscall)
ebreak                         # Environment breakpoint
fence                          # Memory fence
fence.i                        # Instruction fence

Privileged

mret                           # Machine return
sret                           # Supervisor return
wfi                            # Wait for interrupt
sfence.vma rs1, rs2            # Supervisor fence (address + ASID)
sfence.vma                     # Full TLB flush

Pseudo-Instructions

nop                            # No operation (addi x0, x0, 0)
li    rd, imm                  # Load immediate (multi-instruction for large values)
la    rd, label                # Load address (AUIPC + ADDI pair)
mv    rd, rs1                  # Move register (addi rd, rs1, 0)
not   rd, rs1                  # Bitwise NOT (xori rd, rs1, -1)
neg   rd, rs1                  # Negate (sub rd, x0, rs1)
negw  rd, rs1                  # Negate word (subw rd, x0, rs1)
seqz  rd, rs1                  # Set if equal to zero (sltiu rd, rs1, 1)
snez  rd, rs1                  # Set if not zero (sltu rd, x0, rs1)
sltz  rd, rs1                  # Set if less than zero (slt rd, rs1, x0)
sgtz  rd, rs1                  # Set if greater than zero (slt rd, x0, rs1)
j     label                    # Unconditional jump (jal x0, label)
jr    rs1                      # Jump register (jalr x0, rs1, 0)
ret                            # Return (jalr x0, ra, 0)
call  label                    # Far call (AUIPC + JALR pair)
tail  label                    # Far tail call (AUIPC + JALR pair)
sext.w rd, rs1                 # Sign-extend word (addiw rd, rs1, 0)

Branch Pseudo-Instructions

beqz  rs1, label               # Branch if zero (beq rs1, x0, label)
bnez  rs1, label               # Branch if not zero
blez  rs1, label               # Branch if ≤ 0 (bge x0, rs1, label)
bgez  rs1, label               # Branch if ≥ 0
bltz  rs1, label               # Branch if < 0
bgtz  rs1, label               # Branch if > 0
bgt   rs1, rs2, label          # Branch if > (blt rs2, rs1, label)
ble   rs1, rs2, label          # Branch if ≤
bgtu  rs1, rs2, label          # Branch if > (unsigned)
bleu  rs1, rs2, label          # Branch if ≤ (unsigned)

64-bit Load Immediate (RV64)

For large 64-bit constants, li produces an optimal multi-instruction sequence using LUI/ADDI/SLLI:

li    a0, 0xDEADBEEFCAFEBABE   # Up to 8 instructions (32 bytes)

The li decomposition correctly handles sign-extension edge cases (e.g., li a0, 0x80000000 produces positive 2^31 on RV64).

C Extension (Compressed — 16-bit)

CR-type (Register)

c.mv    rd, rs2                # Move (rd ≠ x0, rs2 ≠ x0)
c.add   rd, rs2                # Add (rd ≠ x0, rs2 ≠ x0)
c.jr    rs1                    # Jump register (rs1 ≠ x0)
c.jalr  rs1                    # Jump and link register (rs1 ≠ x0)

CI-type (Immediate)

c.li     rd, imm               # Load 6-bit signed immediate
c.lui    rd, imm               # Load upper immediate (rd ≠ x0, x2)
c.addi   rd, imm               # Add 6-bit signed immediate (imm ≠ 0)
c.addiw  rd, imm               # Add word immediate (RV64, rd ≠ x0)
c.addi16sp imm                 # Add to SP (scaled ×16, imm ≠ 0)
c.slli   rd, shamt             # Shift left (rd ≠ x0)
c.lwsp   rd, offset            # Load word, SP-relative
c.ldsp   rd, offset            # Load double, SP-relative (RV64)

CSS-type (Stack Store)

c.swsp  rs2, offset            # Store word, SP-relative
c.sdsp  rs2, offset            # Store double, SP-relative (RV64)

CIW-type (Wide Immediate)

c.addi4spn rd', imm            # Add scaled immediate to SP (rd' = x8–x15)

CL/CS-type (Load/Store)

c.lw    rd', offset(rs1')      # Load word (compact registers x8–x15)
c.ld    rd', offset(rs1')      # Load double (RV64)
c.sw    rs2', offset(rs1')     # Store word
c.sd    rs2', offset(rs1')     # Store double (RV64)

CA-type (Arithmetic)

c.sub   rd', rs2'              # Subtract (compact registers)
c.xor   rd', rs2'              # XOR
c.or    rd', rs2'              # OR
c.and   rd', rs2'              # AND
c.subw  rd', rs2'              # Subtract word (RV64)
c.addw  rd', rs2'              # Add word (RV64)

CB-type (Branch)

c.beqz  rs1', label            # Branch if zero (±256 B)
c.bnez  rs1', label            # Branch if not zero (±256 B)
c.srli  rd', shamt             # Shift right logical
c.srai  rd', shamt             # Shift right arithmetic
c.andi  rd', imm               # AND immediate

CJ-type (Jump)

c.j     label                  # Unconditional jump (±2 KB)

Misc

c.nop                          # No operation
c.ebreak                       # Environment breakpoint

Auto-Narrowing

Enable automatic compression of full-width instructions to C-extension equivalents when constraints are met:

.option rvc                    # Enable auto-narrowing
addi  a0, a0, 1               # → c.addi a0, 1 (2 bytes instead of 4)
add   a0, a0, a1              # → c.add a0, a1
lw    a0, 0(sp)               # → c.lwsp a0, 0
.option norvc                  # Disable auto-narrowing

Compressed Branch Relaxation

c.beqz  a0, far_label         # Widens to inverted-B + JAL (8B, ±1 MiB)
c.bnez  a0, far_label         # when target exceeds ±256 B
c.j     far_label              # Widens to JAL (4B, ±1 MiB)
                                # when target exceeds ±2 KB

Memory Addressing

RISC-V uses offset(register) memory addressing:

lw  a0, 0(sp)                 # Load word from [sp + 0]
sw  a0, 8(sp)                 # Store word to [sp + 8]
lw  a0, -4(s0)                # Negative offset
lw  a0, (sp)                  # Bare register = 0(sp)