Project F

RISC-V Assembler Cheat Sheet

Published

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
addAddadd rd, rs1, rs2rd = rs1 + rs2arithmetic
addiAdd Immediateaddi rd, rs1, immrd = rs1 + immarithmetic
negNegate (p)neg rd, rs2rd = -rs2arithmetic
subSubtractsub rd, rs1, rs2rd = rs1 - rs2arithmetic
mulMultiplymul rd, rs1, rs2rd = (rs1 * rs2)[31:0]multiply
mulhMultiply Highmulh rd, rs1, rs2rd = (rs1 * rs2)[63:32]multiply
mulhuMultiply High Unsignedmulhu rd, rs1, rs2rd = (rs1 * rs2)[63:32]multiply
mulhsuMultiply High Signed Unsignedmulhsu rd, rs1, rs2rd = (rs1 * rs2)[63:32]multiply
divDividediv rd, rs1, rs2rd = rs1 / rs2divide
remRemainderrem rd, rs1, rs2rd = rs1 % rs2divide

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

Bitwise Logic

InstrDescriptionUseResultGuide
andANDand rd, rs1, rs2rd = rs1 & rs2logical
andiAND Immediateandi rd, rs1, immrd = rs1 & immlogical
notNOT (p)not rd, rs1rd = ~rs1logical
orORor rd, rs1, rs2rd = rs1 | rs2logical
oriOR Immediateori rd, rs1, immrd = rs1 | immlogical
xorXORxor rd, rs1, rs2rd = rs1 ^ rs2logical
xoriXOR Immediatexori rd, rs1, immrd = rs1 ^ immlogical

Shift

InstrDescriptionUseResultGuide
sllShift Left Logicalsll rd, rs1, rs2rd = rs1 << rs2shift
slliShift Left Logical Immediateslli rd, rs1, immrd = rs1 << immshift
srlShift Right Logicalsrl rd, rs1, rs2rd = rs1 >> rs2shift
srliShift Right Logical Immediatesrli rd, rs1, immrd = rs1 >> immshift
sraShift Right Arithmeticsra rd, rs1, rs2rd = rs1 >>> rs2shift
sraiShift Right Arithmetic Immediatesrai rd, rs1, immrd = rs1 >>> immshift

Load Immediate

InstrDescriptionUseResultGuide
liLoad Immediate (p)li rd, immrd = immarithmetic
luiLoad Upper Immediatelui rd, immrd = imm << 12arithmetic
auipcAdd Upper Immediate to PCauipc rd, immrd = pc + (imm << 12)branch

Load and Store

InstrDescriptionUseResultGuide
lwLoad Wordlw rd, imm(rs1)rd = mem[rs1+imm]load
lhLoad Halflh rd, imm(rs1)rd = mem[rs1+imm][0:15]load
lhuLoad Half Unsignedlhu rd, imm(rs1)rd = mem[rs1+imm][0:15]load
lbLoad Bytelb rd, imm(rs1)rd = mem[rs1+imm][0:7]load
lbuLoad Byte Unsignedlbu rd, imm(rs1)rd = mem[rs1+imm][0:7]load
laLoad Symbol Address (p)la rd, symbolrd = &symbolload
swStore Wordsw rs2, imm(rs1)mem[rs1+imm] = rs2store
shStore Halfsh rs2, imm(rs1)mem[rs1+imm][0:15] = rs2store
sbStore Bytesb rs2, imm(rs1)mem[rs1+imm][0:7] = rs2store

Jump and Function

InstrDescriptionUseResultGuide
jJump (p)j immpc += immjump
jalJump and Linkjal rd, immrd = pc+4; pc += immjump
jalrJump and Link Registerjalr rd, rs1, immrd = pc+4; pc = rs1+immjump
callCall Function (p)call symbolra = pc+4; pc = &symbolfunction
retReturn from Function (p)retpc = rafunction

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 Equalbeq rs1, rs2, immif(rs1 == rs2) pc += immbranch
beqzBranch Equal Zero (p)beqz rs1, immif(rs1 == 0) pc += immbranch
bneBranch Not Equalbne rs1, rs2, immif(rs1 ≠ rs2) pc += immbranch
bnezBranch Not Equal Zero (p)bnez rs1, rs2, immif(rs1 ≠ 0) pc += immbranch
bltBranch Less Thanblt rs1, rs2, immif(rs1 < rs2) pc += immbranch
bltuBranch Less Than Unsignedbltu rs1, rs2, immif(rs1 < rs2) pc += immbranch
bltzBranch Less Than Zero (p)bltz rs1, immif(rs1 < 0) pc += immbranch
bgtBranch Greater Than (p)bgt rs1, rs2, immif(rs1 > rs2) pc += immbranch
bgtuBranch Greater Than Unsigned (p)bgtu rs1, rs2, immif(rs1 > rs2) pc += immbranch
bgtzBranch Greater Than Zero (p)bgtz rs1, immif(rs1 > 0) pc += immbranch
bleBranch Less or Equal (p)ble rs1, rs2, immif(rs1 ≤ rs2) pc += immbranch
bleuBranch Less or Equal Unsigned (p)bleu rs1, rs2, immif(rs1 ≤ rs2) pc += immbranch
blezBranch Less or Equal Zero (p)blez rs1, immif(rs1 ≤ 0) pc += immbranch
bgeBranch Greater or Equalbge rs1, rs2, immif(rs1 ≥ rs2) pc += immbranch
bgeuBranch Greater or Equal Unsignedbgeu rs1, rs2, immif(rs1 ≥ rs2) pc += immbranch
bgezBranch Greater or Equal Zero (p)bgez rs1, immif(rs1 ≥ 0) pc += immbranch

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

Set

InstrDescriptionUseResultGuide
sltSet Less Thanslt rd, rs1, rs2rd = (rs1 < rs2)set
sltiSet Less Than Immediateslti rd, rs1, immrd = (rs1 < imm)set
sltuSet Less Than Unsignedsltu rd, rs1, rs2rd = (rs1 < rs2)set
sltiuSet Less Than Immediate Unsignedsltui rd, rs1, immrd = (rs1 < imm)set
seqzSet Equal Zeroseqz rd, rs1rd = (rs1 == 0)set
snezSet Not Equal Zerosnez rd, rs1rd = (rs1 ≠ 0)set
sltzSet Less Than Zerosltz rd, rs1rd = (rs < 0)set
sgtzSet Greater Than Zerosgtz rd, rs1rd = (rs1 > 0)set

Counters

InstrDescriptionUseResultGuide
rdcycleCPU Cycle Count (p)rdcycle rdrd = csr_cycle[31:0]not yet avail
rdcyclehCPU Cycle Count High (p)rdcycleh rdrd = csr_cycle[63:32]not yet avail
rdtimeCurrent Time (p)rdtime rdrd = csr_time[31:0]not yet avail
rdtimehCurrent Time High (p)rdtimeh rdrd = csr_time[63:32]not yet avail
rdinstretCPU Instructions Retired (p)rdinstret rdrd = csr_instret[31:0]not yet avail
rdinstrethCPU Instructions Retired High (p)rdinstreth rdrd = 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 Orderingfence-not yet avail
mvCopy Register (p)mv rd, rs1rd = rs1arithmetic
nopNo Operation (p)nop-arithmetic

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

Key

  • imm - immediate value (normally sign extended)
  • mem - memory
  • (p) - pseudoinstruction
  • pc - program counter
  • pc+4 - next instruction on RV32
  • ra - return address register (x1)
  • rd - destination register
  • rs1 - first source register
  • rs2 - second source register
  • symbol - symbol (may be label in asm)

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