RISC-V
RISC-V instruction reference: RV32I/RV64I base ISA plus the M, A, C, F/D and V extensions with automatic compression.
Notation
| Symbol | Meaning |
|---|---|
rd | Destination register (x0–x31 or ABI name) |
rs1 / rs2 | Source register(s) |
imm | Immediate value |
offset | Branch/jump offset or memory displacement |
label | Label reference |
csr | Control/status register name or address |
fd / fs1 / fs2 | Floating-point register (f0–f31 or ABI name) |
vd / vs1 / vs2 | Vector register (v0–v31) |
ABI Register Names
| ABI | Reg | ABI | Reg | ABI | Reg | ABI | Reg |
|---|---|---|---|---|---|---|---|
zero | x0 | ra | x1 | sp | x2 | gp | x3 |
tp | x4 | t0 | x5 | t1 | x6 | t2 | x7 |
s0/fp | x8 | s1 | x9 | a0 | x10 | a1 | x11 |
a2 | x12 | a3 | x13 | a4 | x14 | a5 | x15 |
a6 | x16 | a7 | x17 | s2 | x18 | s3 | x19 |
s4 | x20 | s5 | x21 | s6 | x22 | s7 | x23 |
s8 | x24 | s9 | x25 | s10 | x26 | s11 | x27 |
t3 | x28 | t4 | x29 | t5 | x30 | t6 | x31 |
Base Integer ISA (RV32I)
Upper-Immediate (U-type)
lui rd, imm # Load upper immediate (bits 31:12)
auipc rd, imm # Add upper immediate to PCJump (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 immediateShift — 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 arithmeticALU — 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 # ANDRV64I 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 wordM 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 remainderRV64M 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 doublewordAtomic 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-releaseCSR 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 fencePrivileged
mret # Machine return
sret # Supervisor return
wfi # Wait for interrupt
sfence.vma rs1, rs2 # Supervisor fence (address + ASID)
sfence.vma # Full TLB flushPseudo-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
lidecomposition correctly handles sign-extension edge cases (e.g.,li a0, 0x80000000produces 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 immediateCJ-type (Jump)
c.j label # Unconditional jump (±2 KB)Misc
c.nop # No operation
c.ebreak # Environment breakpointAuto-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-narrowingCompressed 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 KBMemory 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)