If you want to truly understand a processor, write assembly for it β and RISC-V is the best ISA in decades to learn on. It is clean, regular, and free of legacy cruft, which is exactly why universities are adopting it to teach computer architecture. This tutorial gets you from zero to a running RISC-V program, with no RISC-V hardware required.

Why Learn on RISC-V?
Compared to x86βs decades of accumulated complexity, RISC-V is a breath of fresh air: a small, orthogonal instruction set, fixed-length encodings, and a tidy register model. You can hold the whole base ISA in your head. That is why it shines for education β and why it is a joy to learn.
The Registers
RV32I/RV64I have 32 general-purpose registers, x0βx31. Each also has an ABI name describing its conventional role:
| Register | ABI name | Role |
|---|---|---|
x0 | zero | Hardwired to 0 |
x1 | ra | Return address |
x2 | sp | Stack pointer |
x5βx7 | t0βt2 | Temporaries |
x8βx9 | s0βs1 | Saved registers |
x10βx17 | a0βa7 | Arguments / return values |
x18βx27 | s2βs11 | Saved registers |
x28βx31 | t3βt6 | Temporaries |
The trick worth remembering: x0 is always zero. Writes to it are discarded, reads always return 0. This single design choice eliminates the need for many special instructions β a mov is just addi rd, rs, 0, and a nop is addi x0, x0, 0.
Instruction Formats
Every base instruction is 32 bits wide and falls into one of a few regular formats β R, I, S, B, U, J. You do not need to memorize the bit layouts to start, but the key idea is regularity: the source and destination register fields sit in the same place across formats, which makes the hardware decoder simple (and the microarchitecture cheaper). The optional compressed (C) extension adds 16-bit forms for code density.
The Core Instructions
A handful of instructions covers most of what you will write:
addi a0, a0, 5 # a0 = a0 + 5 (add immediate)
add a0, a1, a2 # a0 = a1 + a2
sub a0, a1, a2 # a0 = a1 - a2
li a0, 42 # load immediate (pseudo-instruction)
mv a1, a0 # copy a0 -> a1 (pseudo: addi a1, a0, 0)
ld a0, 0(sp) # load 64-bit word from address in sp
sd a0, 0(sp) # store 64-bit word to address in sp
beq a0, a1, label # branch if equal
jal ra, func # jump and link (call), saving return addr in ra
ret # return (pseudo: jalr x0, 0(ra))
ecall # environment call (syscall / SBI request)Note how many are pseudo-instructions β li, mv, ret, nop β that the assembler expands into real ones. They make assembly readable without bloating the ISA.
Your First Program: Hello, RISC-V
Here is a complete Linux hello world using the write and exit syscalls via ecall:
.section .data
msg: .ascii "Hello, RISC-V!\n"
.equ len, 15
.section .text
.global _start
_start:
li a7, 64 # syscall number: write
li a0, 1 # fd = stdout
la a1, msg # buffer address
li a2, len # length
ecall # invoke kernel
li a7, 93 # syscall number: exit
li a0, 0 # exit code 0
ecallThe Linux RISC-V syscall convention: the syscall number goes in a7, arguments in a0βa5, and ecall traps into the kernel (in supervisor mode). The return value comes back in a0.
Assemble, Link, Run
You need a RISC-V toolchain and QEMU β no RISC-V hardware:
# Assemble and link
riscv64-linux-gnu-as -o hello.o hello.s
riscv64-linux-gnu-ld -o hello hello.o
# Run under QEMU user-mode emulation on your x86/Arm machine
qemu-riscv64 ./hello
# -> Hello, RISC-V!That is the entire loop. Edit, assemble, run β watch your instructions execute. For deeper inspection, run it under GDB and single-step to see registers change.
Reading Compiler Output
A powerful way to learn: write tiny C functions and inspect what the compiler emits.
riscv64-linux-gnu-gcc -O2 -S add.c -o add.s # see the assembly
riscv64-linux-gnu-objdump -d a.out # disassemble a binaryComparing your hand-written assembly to the compilerβs output teaches the ABI, calling conventions, and clever optimizations quickly.
The Bottom Line
RISC-V assembly is approachable precisely because the ISA was designed to be clean: 32 regular registers (with x0 hardwired to zero), fixed-width instructions, and a small core set rounded out by readable pseudo-instructions. Write the hello-world above, run it in QEMU, then disassemble some C β you will understand the machine far better than any diagram could teach. It is the single best way to feel why RISC-V is special.
Part of my RISC-V series. Next: Debugging RISC-V with GDB & OpenOCD and the memory model & atomics.



