RISC-V Assembler Cheat Sheet

This cheat sheet provides a handy guide to 32-bit RISC-V instructions. I’ve aimed it at software developers, so group instructions by purpose and include common pseudoinstructions. Clicking on a Guide link takes you to the relevant section of the Project F RISC-V assembler guide for instruction explanation and examples.

Instructions are from the base integer instruction set (RV32I) unless otherwise noted.

Share your thoughts with @WillFlux on Mastodon or X. If you like what I do, sponsor me. 🙏

Arithmetic

InstrDescriptionUseResultGuide
addAdd add rd, rs1, rs2 rd = rs1 + rs2 arithmetic
addiAdd Immediate addi rd, rs1, imm rd = rs1 + imm arithmetic
negNegate (p) neg rd, rs2 rd = -rs2 arithmetic
subSubtract sub rd, rs1, rs2 rd = rs1 - rs2 arithmetic
mulMultiply mul rd, rs1, rs2 rd = (rs1 * rs2)[31:0] multiply
mulhMultiply High mulh rd, rs1, rs2 rd = (rs1 * rs2)[63:32] multiply
mulhuMultiply High Unsigned mulhu rd, rs1, rs2 rd = (rs1 * rs2)[63:32] multiply
mulhsuMultiply High Signed Unsigned mulhsu rd, rs1, rs2 rd = (rs1 * rs2)[63:32] multiply
divDivide div rd, rs1, rs2 rd = rs1 / rs2 divide
remRemainder rem rd, rs1, rs2 rd = rs1 % rs2 divide

Use addi for subtract immediate too. Multiply and divide instructions require the M extension.

Bitwise Logic

InstrDescriptionUseResultGuide
andAND and rd, rs1, rs2 rd = rs1 & rs2 logical
andiAND Immediate andi rd, rs1, imm rd = rs1 & imm logical
notNOT (p) not rd, rs1 rd = ~rs1 logical
orOR or rd, rs1, rs2 rd = rs1 | rs2 logical
oriOR Immediate ori rd, rs1, imm rd = rs1 | imm logical
xorXOR xor rd, rs1, rs2 rd = rs1 ^ rs2 logical
xoriXOR Immediate xori rd, rs1, imm rd = rs1 ^ imm logical

Shift

InstrDescriptionUseResultGuide
sllShift Left Logical sll rd, rs1, rs2 rd = rs1 shift
slliShift Left Logical Immediate slli rd, rs1, imm rd = rs1 shift
srlShift Right Logical srl rd, rs1, rs2 rd = rs1 >> rs2 shift
srliShift Right Logical Immediate srli rd, rs1, imm rd = rs1 >> imm shift
sraShift Right Arithmetic sra rd, rs1, rs2 rd = rs1 >>> rs2 shift
sraiShift Right Arithmetic Immediate srai rd, rs1, imm rd = rs1 >>> imm shift

Load Immediate

InstrDescriptionUseResultGuide
liLoad Immediate (p) li rd, imm rd = imm arithmetic
luiLoad Upper Immediate lui rd, imm rd = imm arithmetic
auipcAdd Upper Immediate to PC auipc rd, imm rd = pc + (imm branch

Load and Store

InstrDescriptionUseResultGuide
lwLoad Word lw rd, imm(rs1) rd = mem[rs1+imm] load
lhLoad Half lh rd, imm(rs1) rd = mem[rs1+imm][0:15] load
lhuLoad Half Unsigned lhu rd, imm(rs1) rd = mem[rs1+imm][0:15] load
lbLoad Byte lb rd, imm(rs1) rd = mem[rs1+imm][0:7] load
lbuLoad Byte Unsigned lbu rd, imm(rs1) rd = mem[rs1+imm][0:7] load
laLoad Symbol Address (p) la rd, symbol rd = &symbol load
swStore Word sw rs2, imm(rs1) mem[rs1+imm] = rs2 store
shStore Half sh rs2, imm(rs1) mem[rs1+imm][0:15] = rs2 store
sbStore Byte sb rs2, imm(rs1) mem[rs1+imm][0:7] = rs2 store

Jump and Function

InstrDescriptionUseResultGuide
jJump (p) j imm pc += imm jump
jalJump and Link jal rd, imm rd = pc+4; pc += imm jump
jalrJump and Link Register jalr rd, rs1, imm rd = pc+4; pc = rs1+imm jump
callCall Function (p) call symbol ra = pc+4; pc = &symbol function
retReturn from Function (p) ret pc = ra function

You can use a label in place of a jump immediate, for example: j label_name

Branch

This page lists all branch instructions but you may prefer the branch instruction summary.

InstrDescriptionUseResultGuide
beqBranch Equal beq rs1, rs2, imm if(rs1 == rs2) pc += imm branch
beqzBranch Equal Zero (p) beqz rs1, imm if(rs1 == 0) pc += imm branch
bneBranch Not Equal bne rs1, rs2, imm if(rs1 ≠ rs2) pc += imm branch
bnezBranch Not Equal Zero (p) bnez rs1, rs2, imm if(rs1 ≠ 0) pc += imm branch
bltBranch Less Than blt rs1, rs2, imm if(rs1 < rs2) pc += imm branch
bltuBranch Less Than Unsigned bltu rs1, rs2, imm if(rs1 < rs2) pc += imm branch
bltzBranch Less Than Zero (p) bltz rs1, imm if(rs1 < 0) pc += imm branch
bgtBranch Greater Than (p) bgt rs1, rs2, imm if(rs1 > rs2) pc += imm branch
bgtuBranch Greater Than Unsigned (p) bgtu rs1, rs2, imm if(rs1 > rs2) pc += imm branch
bgtzBranch Greater Than Zero (p) bgtz rs1, imm if(rs1 > 0) pc += imm branch
bleBranch Less or Equal (p) ble rs1, rs2, imm if(rs1 ≤ rs2) pc += imm branch
bleuBranch Less or Equal Unsigned (p) bleu rs1, rs2, imm if(rs1 ≤ rs2) pc += imm branch
blezBranch Less or Equal Zero (p) blez rs1, imm if(rs1 ≤ 0) pc += imm branch
bgeBranch Greater or Equal bge rs1, rs2, imm if(rs1 ≥ rs2) pc += imm branch
bgeuBranch Greater or Equal Unsigned bgeu rs1, rs2, imm if(rs1 ≥ rs2) pc += imm branch
bgezBranch Greater or Equal Zero (p) bgez rs1, imm if(rs1 ≥ 0) pc += imm branch

You can use a label in place of a branch immediate, for example: beq t0, t1, label_name

Set

InstrDescriptionUseResultGuide
sltSet Less Than slt rd, rs1, rs2 rd = (rs1 < rs2) set
sltiSet Less Than Immediate slti rd, rs1, imm rd = (rs1 < imm) set
sltuSet Less Than Unsigned sltu rd, rs1, rs2 rd = (rs1 < rs2) set
sltiuSet Less Than Immediate Unsigned sltui rd, rs1, imm rd = (rs1 < imm) set
seqzSet Equal Zero seqz rd, rs1 rd = (rs1 == 0) set
snezSet Not Equal Zero snez rd, rs1 rd = (rs1 ≠ 0) set
sltzSet Less Than Zero sltz rd, rs1 rd = (rs < 0) set
sgtzSet Greater Than Zero sgtz rd, rs1 rd = (rs1 > 0) set

Counters

InstrDescriptionUseResultGuide
rdcycleCPU Cycle Count (p) rdcycle rd rd = csr_cycle[31:0] not yet avail
rdcyclehCPU Cycle Count High (p) rdcycleh rd rd = csr_cycle[63:32] not yet avail
rdtimeCurrent Time (p) rdtime rd rd = csr_time[31:0] not yet avail
rdtimehCurrent Time High (p) rdtimeh rd rd = csr_time[63:32] not yet avail
rdinstretCPU Instructions Retired (p) rdinstret rd rd = csr_instret[31:0] not yet avail
rdinstrethCPU Instructions Retired High (p) rdinstreth rd rd = csr_instret[63:32] not yet avail

The counter instructions require the Zicsr extension but were originally part of the base instruction set.

Misc

InstrDescriptionUseResultGuide
ebreakEnvironment Break (Debugger Call) ebreak - not yet avail
ecallEnvironment Call (OS Function) ecall - not yet avail
fenceI/O Ordering fence - not yet avail
mvCopy Register (p) mv rd, rs1 rd = rs1 arithmetic
nopNo Operation (p) nop - arithmetic

The fence instruction requires the Zifencei extension but was originally part of the base instruction set.

Key

What’s Next?

Check out all my FPGA & RISC-V Tutorials and my series on early Macintosh History.

If you enjoyed this post, please sponsor me. Sponsors help me create more FPGA and RISC-V projects for everyone, and they get early access to blog posts and source code. 🙏

References