Before a CPU can add, compare or jump, it needs somewhere to keep the numbers it's working on right now. Those little holding slots are registers — the most-used storage in the whole machine. Today we'll meet RISC-V's 32 registers, the magical "always-zero" one, and the friendly names engineers give them — all in plain English.
A register is a tiny, super-fast storage slot inside the CPU that holds one number. That's it. When the processor adds two numbers, both numbers sit in registers, and the answer goes into a register too.
Registers are like the items on your desk — right in front of you, grabbable instantly. Memory (RAM) is the warehouse down the hall — huge, but slow to fetch from. You keep what you're actively using on the desk (registers) and only walk to the warehouse (memory) when you must. A CPU works the same way: do the math in registers, touch memory only when needed.
Speed. Reading a register takes effectively no time (it's right inside the core), while reaching out to main memory is dramatically slower. So RISC-V is a "load-store" architecture: arithmetic instructions work only on registers, and there are special instructions just for moving data between registers and memory (we'll meet lw/sw on Day 13). Keep that in mind — it shapes the whole instruction set.
RV32I gives you exactly 32 general-purpose registers, named x0, x1, x2, … x31. Each one is 32 bits wide (remember the "32" in RV32I — that's the size of each register). Picture them as a numbered row of 32 boxes, each holding a 32-bit number:
Collectively this set of registers is called the register file — and building it in Verilog is exactly what we'll do on Day 9.
One register is special. x0 is hardwired to the value 0. Read it → you always get 0. Write to it → the write is silently thrown away. It sounds useless, but it's a brilliant trick that makes the instruction set smaller:
add x5, x6, x0 copies x6 into x5 (no separate "move" instruction needed).This is why RISC-V needs fewer real instructions — many handy operations are just clever uses of x0.
Numbers like x18 tell you nothing about a register's job. So RISC-V defines ABI names — human-friendly aliases — as part of the calling convention (the agreed rules that let separately-written code work together, like the AAPCS in ARM). They're the same physical registers, just named by role:
| Register | ABI name | Role |
|---|---|---|
| x0 | zero | constant 0 (hardwired) |
| x1 | ra | return address (where a function returns to) |
| x2 | sp | stack pointer |
| x3 | gp | global pointer |
| x4 | tp | thread pointer |
| x5–x7 | t0–t2 | temporaries (scratch, caller-saved) |
| x8 | s0 / fp | saved register / frame pointer |
| x9 | s1 | saved register (callee-saved) |
| x10–x11 | a0–a1 | function arguments & return values |
| x12–x17 | a2–a7 | more function arguments |
| x18–x27 | s2–s11 | saved registers (callee-saved) |
| x28–x31 | t3–t6 | more temporaries (caller-saved) |
Don't memorize this — just know the common ones: a0–a7 pass arguments (and a0 returns the result), ra remembers where a function should return, sp points at the stack, and t/s registers are scratch vs. preserved. We'll use them naturally as we go (full calling convention on Day 5).
There's one more vital register that's not one of the 32: the Program Counter (PC). It holds the address of the instruction currently being run — basically a bookmark in your program. After each instruction the PC normally advances by 4 (instructions are 4 bytes = 32 bits each) to point at the next one; a branch or jump changes the PC to somewhere else, which is how loops and if-statements work. Building the PC is Day 8.
Here's a tiny RISC-V program that shows registers, x0, and ABI names working together. Copy or download it — by Day 15 our CPU will actually run code like this:
# Show how registers are used. Result ends up in a0.
li t0, 7 # t0 (x5) = 7 ("load immediate")
li t1, 5 # t1 (x6) = 5
add t2, t0, t1 # t2 (x7) = 7 + 5 = 12
add a0, t2, zero # a0 (x10) = t2 + x0 -> copy result into a0 (=12)
# x0/zero tricks:
add t3, zero, zero # t3 = 0 + 0 = 0 (clear a register)
# 'li' and 'mv' are pseudo-instructions the assembler turns into
# real RV32I ops (e.g. addi t0, x0, 7).
Notice add a0, t2, zero — that's the x0 copy trick from §4. And li/mv are pseudo-instructions: convenient shorthands the assembler expands into real RV32I instructions (e.g. li t0, 7 becomes addi t0, x0, 7). We'll unpack instruction encodings on Day 3.
RV32I has 32 fast 32-bit registers (x0–x31) where the CPU does its work; x0 is always 0 (a handy free constant); registers also have ABI names (a0–a7, ra, sp, t/s…) describing their job; and a separate Program Counter tracks which instruction is running. Arithmetic happens in registers — memory is touched only via load/store.
add rd, rs, x0), discard results.lw/sw.A tiny, very fast storage slot inside the CPU holding one value the processor is actively working on.
32 general-purpose registers (x0–x31), each 32 bits wide, plus a separate program counter.
It's hardwired to 0 — reads give 0, writes are ignored — which provides a free constant and simplifies the instruction set.
Role-based aliases (a0–a7, ra, sp, t0–t6, s0–s11) for the numbered registers, defined by the calling convention.