Day 36: RISC-V assembly and the calling convention
Assembly and the calling convention
RISC-V assembly is readable once you know the register ABI names: ra (return address), sp (stack pointer), a0–a7 (arguments/return values), t0–t6 (temporaries), s0–s11 (saved registers). The calling convention is the agreement about who saves what across a call: arguments go in a0–a7, results come back in a0/a1, the caller preserves t*, and the callee preserves s* and ra.
# int add3(int a, int b, int c) { return a + b + c; }
add3:
add a0, a0, a1 # a0 = a + b
add a0, a0, a2 # a0 = (a+b) + c
ret # pseudo for: jalr x0, ra, 0
# caller: x = add3(1, 2, 3);
li a0, 1 # li -> addi a0, x0, 1
li a1, 2
li a2, 3
jal ra, add3 # jump-and-link: ra = pc+4, pc = add3
# result now in a0Why this matters for ChipX
Your Stage-4 firmware is compiled C. The compiler emits calls, stack frames, and register saves that assume this exact convention — so ChipX only runs real programs if it faithfully implements the ISA the convention is built on. Getting jal/jalr and the stack right is what turns 'passes an instruction test' into 'runs a C program'.
Key terms
- ABI
- Application binary interface — the register-name and calling conventions compiled code relies on.
- ra / sp
- Return-address and stack-pointer registers (x1 and x2).
- Caller-saved (t*) / callee-saved (s*)
- Registers the caller must preserve vs those the callee must preserve across a call.
- jal / jalr
- Jump-and-link (relative) / jump-and-link-register (indirect) — the call/return primitives storing pc+4 in rd.
- Stack frame
- The region of the stack a function uses for saved registers and locals.
Before moving on, you should be able to
When a function makes a call, which registers must it save first if it needs their values afterward?