# 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
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 << rs2`shift
slliShift Left Logical Immediate`slli rd, rs1, imm``rd = rs1 << imm`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

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

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

• 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. 🙏