# 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

Instr | Description | Use | Result | Guide |
---|---|---|---|---|

add | Add | `add rd, rs1, rs2` | `rd = rs1 + rs2` | arithmetic |

addi | Add Immediate | `addi rd, rs1, imm` | `rd = rs1 + imm` | arithmetic |

neg | Negate (p) | `neg rd, rs2` | `rd = -rs2` | arithmetic |

sub | Subtract | `sub rd, rs1, rs2` | `rd = rs1 - rs2` | arithmetic |

mul | Multiply | `mul rd, rs1, rs2` | `rd = (rs1 * rs2)[31:0]` | multiply |

mulh | Multiply High | `mulh rd, rs1, rs2` | `rd = (rs1 * rs2)[63:32]` | multiply |

mulhu | Multiply High Unsigned | `mulhu rd, rs1, rs2` | `rd = (rs1 * rs2)[63:32]` | multiply |

mulhsu | Multiply High Signed Unsigned | `mulhsu rd, rs1, rs2` | `rd = (rs1 * rs2)[63:32]` | multiply |

div | Divide | `div rd, rs1, rs2` | `rd = rs1 / rs2` | divide |

rem | Remainder | `rem rd, rs1, rs2` | `rd = rs1 % rs2` | divide |

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

## Bitwise Logic

Instr | Description | Use | Result | Guide |
---|---|---|---|---|

and | AND | `and rd, rs1, rs2` | `rd = rs1 & rs2` | logical |

andi | AND Immediate | `andi rd, rs1, imm` | `rd = rs1 & imm` | logical |

not | NOT (p) | `not rd, rs1` | `rd = ~rs1` | logical |

or | OR | `or rd, rs1, rs2` | `rd = rs1 | rs2` | logical |

ori | OR Immediate | `ori rd, rs1, imm` | `rd = rs1 | imm` | logical |

xor | XOR | `xor rd, rs1, rs2` | `rd = rs1 ^ rs2` | logical |

xori | XOR Immediate | `xori rd, rs1, imm` | `rd = rs1 ^ imm` | logical |

## Shift

Instr | Description | Use | Result | Guide |
---|---|---|---|---|

sll | Shift Left Logical | `sll rd, rs1, rs2` | `rd = rs1 << rs2` | shift |

slli | Shift Left Logical Immediate | `slli rd, rs1, imm` | `rd = rs1 << imm` | shift |

srl | Shift Right Logical | `srl rd, rs1, rs2` | `rd = rs1 >> rs2` | shift |

srli | Shift Right Logical Immediate | `srli rd, rs1, imm` | `rd = rs1 >> imm` | shift |

sra | Shift Right Arithmetic | `sra rd, rs1, rs2` | `rd = rs1 >>> rs2` | shift |

srai | Shift Right Arithmetic Immediate | `srai rd, rs1, imm` | `rd = rs1 >>> imm` | shift |

## Load Immediate

Instr | Description | Use | Result | Guide |
---|---|---|---|---|

li | Load Immediate (p) | `li rd, imm` | `rd = imm` | arithmetic |

lui | Load Upper Immediate | `lui rd, imm` | `rd = imm << 12` | arithmetic |

auipc | Add Upper Immediate to PC | `auipc rd, imm` | `rd = pc + (imm << 12)` | branch |

## Load and Store

Instr | Description | Use | Result | Guide |
---|---|---|---|---|

lw | Load Word | `lw rd, imm(rs1)` | `rd = mem[rs1+imm]` | load |

lh | Load Half | `lh rd, imm(rs1)` | `rd = mem[rs1+imm][0:15]` | load |

lhu | Load Half Unsigned | `lhu rd, imm(rs1)` | `rd = mem[rs1+imm][0:15]` | load |

lb | Load Byte | `lb rd, imm(rs1)` | `rd = mem[rs1+imm][0:7]` | load |

lbu | Load Byte Unsigned | `lbu rd, imm(rs1)` | `rd = mem[rs1+imm][0:7]` | load |

la | Load Symbol Address (p) | `la rd, symbol` | `rd = &symbol` | load |

sw | Store Word | `sw rs2, imm(rs1)` | `mem[rs1+imm] = rs2` | store |

sh | Store Half | `sh rs2, imm(rs1)` | `mem[rs1+imm][0:15] = rs2` | store |

sb | Store Byte | `sb rs2, imm(rs1)` | `mem[rs1+imm][0:7] = rs2` | store |

## Jump and Function

Instr | Description | Use | Result | Guide |
---|---|---|---|---|

j | Jump (p) | `j imm` | `pc += imm` | jump |

jal | Jump and Link | `jal rd, imm` | `rd = pc+4; pc += imm` | jump |

jalr | Jump and Link Register | `jalr rd, rs1, imm` | `rd = pc+4; pc = rs1+imm` | jump |

call | Call Function (p) | `call symbol` | `ra = pc+4; pc = &symbol` | function |

ret | Return 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.

Instr | Description | Use | Result | Guide |
---|---|---|---|---|

beq | Branch Equal | `beq rs1, rs2, imm` | `if(rs1 == rs2) pc += imm` | branch |

beqz | Branch Equal Zero (p) | `beqz rs1, imm` | `if(rs1 == 0) pc += imm` | branch |

bne | Branch Not Equal | `bne rs1, rs2, imm` | `if(rs1 ≠ rs2) pc += imm` | branch |

bnez | Branch Not Equal Zero (p) | `bnez rs1, rs2, imm` | `if(rs1 ≠ 0) pc += imm` | branch |

blt | Branch Less Than | `blt rs1, rs2, imm` | `if(rs1 < rs2) pc += imm` | branch |

bltu | Branch Less Than Unsigned | `bltu rs1, rs2, imm` | `if(rs1 < rs2) pc += imm` | branch |

bltz | Branch Less Than Zero (p) | `bltz rs1, imm` | `if(rs1 < 0) pc += imm` | branch |

bgt | Branch Greater Than (p) | `bgt rs1, rs2, imm` | `if(rs1 > rs2) pc += imm` | branch |

bgtu | Branch Greater Than Unsigned (p) | `bgtu rs1, rs2, imm` | `if(rs1 > rs2) pc += imm` | branch |

bgtz | Branch Greater Than Zero (p) | `bgtz rs1, imm` | `if(rs1 > 0) pc += imm` | branch |

ble | Branch Less or Equal (p) | `ble rs1, rs2, imm` | `if(rs1 ≤ rs2) pc += imm` | branch |

bleu | Branch Less or Equal Unsigned (p) | `bleu rs1, rs2, imm` | `if(rs1 ≤ rs2) pc += imm` | branch |

blez | Branch Less or Equal Zero (p) | `blez rs1, imm` | `if(rs1 ≤ 0) pc += imm` | branch |

bge | Branch Greater or Equal | `bge rs1, rs2, imm` | `if(rs1 ≥ rs2) pc += imm` | branch |

bgeu | Branch Greater or Equal Unsigned | `bgeu rs1, rs2, imm` | `if(rs1 ≥ rs2) pc += imm` | branch |

bgez | Branch 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

Instr | Description | Use | Result | Guide |
---|---|---|---|---|

slt | Set Less Than | `slt rd, rs1, rs2` | `rd = (rs1 < rs2)` | set |

slti | Set Less Than Immediate | `slti rd, rs1, imm` | `rd = (rs1 < imm)` | set |

sltu | Set Less Than Unsigned | `sltu rd, rs1, rs2` | `rd = (rs1 < rs2)` | set |

sltiu | Set Less Than Immediate Unsigned | `sltui rd, rs1, imm` | `rd = (rs1 < imm)` | set |

seqz | Set Equal Zero | `seqz rd, rs1` | `rd = (rs1 == 0)` | set |

snez | Set Not Equal Zero | `snez rd, rs1` | `rd = (rs1 ≠ 0)` | set |

sltz | Set Less Than Zero | `sltz rd, rs1` | `rd = (rs < 0)` | set |

sgtz | Set Greater Than Zero | `sgtz rd, rs1` | `rd = (rs1 > 0)` | set |

## Counters

Instr | Description | Use | Result | Guide |
---|---|---|---|---|

rdcycle | CPU Cycle Count (p) | `rdcycle rd` | `rd = csr_cycle[31:0]` | not yet avail |

rdcycleh | CPU Cycle Count High (p) | `rdcycleh rd` | `rd = csr_cycle[63:32]` | not yet avail |

rdtime | Current Time (p) | `rdtime rd` | `rd = csr_time[31:0]` | not yet avail |

rdtimeh | Current Time High (p) | `rdtimeh rd` | `rd = csr_time[63:32]` | not yet avail |

rdinstret | CPU Instructions Retired (p) | `rdinstret rd` | `rd = csr_instret[31:0]` | not yet avail |

rdinstreth | CPU 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

Instr | Description | Use | Result | Guide |
---|---|---|---|---|

ebreak | Environment Break (Debugger Call) | `ebreak` | `-` | not yet avail |

ecall | Environment Call (OS Function) | `ecall` | `-` | not yet avail |

fence | I/O Ordering | `fence` | `-` | not yet avail |

mv | Copy Register (p) | `mv rd, rs1` | `rd = rs1` | arithmetic |

nop | No 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

- RISC-V Technical Specifications (riscv.org)