Project F

RISC-V Assembler Cheat Sheet

Published · Updated

This cheat sheet provides a handy reference to 32-bit RISC-V instructions, registers, and concepts. Aimed at software developers, it groups instructions by purpose and includes 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.

Arithmetic | Bitwise Logic | Shift | Load Immediate | Load and Store | Jump and Function | Branch | Set | Counters | Misc Instructions | Instruction Terminology | RV32 ABI Registers | RISC-V Concepts

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

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 table.

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 Zero (p)seqz rd, rs1rd = (rs1 == 0)set
snezSet Not Equal Zero (p)snez rd, rs1rd = (rs1 ≠ 0)set
sltzSet Less Than Zero (p)sltz rd, rs1rd = (rs < 0)set
sgtzSet Greater Than Zero (p)sgtz 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 Zicntr and Zicsr extensions but were originally part of the base instruction set.

Misc Instructions

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.

Instruction Terminology

  • 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)

RV32 ABI Registers

ABI NameRegisterDescriptionPreserved
zerox0always 0 (zero)n/a
rax1return addressno
spx2stack pointeryes
gpx3global pointer*n/a
tpx4thread pointer*n/a
t0x5temporaryno
t1x6temporaryno
t2x7temporaryno
fp (s0)x8frame pointer†yes
s1x9saved registeryes
a0x10function argument‡no
a1x11function argument‡no
a2x12function argumentno
a3x13function argumentno
a4x14function argumentno
a5x15function argumentno
a6x16function argumentno
a7x17function argumentno
s2x18saved registeryes
s3x19saved registeryes
s4x20saved registeryes
s5x21saved registeryes
s6x22saved registeryes
s7x23saved registeryes
s8x24saved registeryes
s9x25saved registeryes
s10x26saved registeryes
s11x27saved registeryes
t3x28temporaryno
t4x29temporaryno
t5x30temporaryno
t6x31temporaryno

*Let the compiler/linker use the global gp and thread tp pointers; ignore them in your own code.
†The frame pointer fp supports local variables but can be used as a regular saved register.
‡Argument registers a0 and a1 also handle the function return value.

RISC-V Concepts

Important RISC-V concepts, briefly explained.

What’s Next?

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

Get in touch on Mastodon, Bluesky, or X. If you enjoy my work, please sponsor me. 🙏

References