Caller-saved registers (also known as volatile registers, or call-clobbered) are used to hold temporary quantities that need not be preserved across calls. For that reason, it is the caller's responsibility to push these registers onto the stack or copy them somewhere else if it wants to restore this value after a procedure call.

Callee-saved registers (also known as non-volatile registers, or call-preserved) are used to hold long-lived values that should be preserved across calls. When the caller makes a procedure call, it can expect that those registers will hold the same value after the callee returns, making it the responsibility of the callee to save them and restore them before returning to the caller. Or to not touch them.

What are callee and caller saved registers?

x0 zero Hard-wired zero
x1 ra Return address Caller
x2 sp Stack pointer Callee
x3 gp Global pointer
x4 tp Thread pointer
x5-7 t0-2 Temporaries Caller
x8 s0, fp Saved register, frame pointer Callee
x9 s1 Saved register Callee
x10-11 a0-1 Function arguments, return values Caller
x12-17 a2-7 Function arguments Caller
x18-27 s2-11 Saved registers Callee
x28-31 t3-6 Temporaries Caller
f0-7 ft0-7 Floating point temporaries Caller
f8-9 fs0-1 Floating point saved registers Callee
f10-11 fa0-1 Floating point arguments, return values Caller
f12-17 fa2-7 Floating point arguments Caller
f18-27 fs2-11 Floating point saved registers Callee
f28-31 ft8-11 Floating point temporaries Caller

Priviledged specification

Level Name Abbrev.
Debug D
00 User U
01 Supervisor S
10 Reserved
11 Machine M

Debug is a special processor mode used for external debugging. It offers full control over the hardware, access to debug registers, and access to reserved memory regions.

0x7B0 DRW dcsr Debug control and status register
0x7B1 DRW dpc Debug program counter
0x7B2 DRW dscratch0 Debug scratch register 0
0x7B3 DRW dscratch1 Debug scratch register 1
sret Return from a trap
wfi Wait for interrupt
sfence.vma TLB flush


la rd, sym auipc rd, sym[31:12]
addi rd, rd, sym[11:0]
Load address (.option nopic)
la rd, sym auipc rd, sym@GOT[31:12]
l[wd] rd, sym@GOT[11:0](rd)
Load address (.option pic)
lla rd, sym auipc rd, sym[31:12]
addi rd, rd, sym[11:0]
Load local address
lga rd, sym auipc rd, sym@GOT[31:12]
l[wd] rd, sym@GOT[11:0](rd)
Load local address
l[bhwd] rd, sym auipc rd, sym[31:12]
l[bhwd] rd, sym[11:0](rd)
Load global
s[bhwd] rd, sym, rt auipc rt, sym[31:12]
s[bhwd] rd, sym[11:0](rt)
Store global
fl[wd] auipc rd, sym[31:12]
fl[wd] rd, sym[11:0](rt)
Floating-point load global
fs[wd] auipc rd, sym[31:12]
fs[wd] rd, sym[11:0](rt)
Floating-point store global
nop addi x0, x0, 0 No operation
li rd, imm Myriad sequences Load immediate
mv rd, rs addi rd, rs, 0 Copy register
not rd, rs xori rd, rs, -1 One's complement
neg rd, rs sub rd, x0, rs Two’s complement
negw rd, rs subw rd, x0, rs Two’s complement word
sext.b rd, rs slli rd, rs, XLEN - 8
srai rd, rd, XLEN - 8
Sign extend byte
sext.h rd, rs slli rd, rs, XLEN - 16
srai rd, rd, XLEN - 16
Sign extend half word
sext.w rd, rs addiw rd, rs, 0 Sign extend word
zext.h rd, rs slli rd, rs, XLEN - 16
srli rd, rd, XLEN - 16
Zero extend half word
zext.w rd, rs slli rd, rs, XLEN - 32
srli rd, rd, XLEN - 32
Zero extend word
seqz rd, rs sltiu rd, rs, 1 Set if equal
snez rd, rs sltu rd, x0, rs Set if not equal zero
sltz rd, rs slt rd, rs, x0 Set if less than zero
sgtz rd, rs sltiu rd, x0, rs Set if greater than zero
fmv.s rd, rs fsgnj.s rd, rs, rs Copy single-precision register
fabs.s rd, rs fsgnjx.s rd, rs, rs Single-precision absolute value
fneg.s rd, rs fsgnjn.s rd, rs, rs Single-precision negate
fmv.d rd, rs fsgnj.d rd, rs, rs Copy double-precision register
fabs.d rd, rs fsgnjx.d rd, rs, rs Double-precision absolute value
fneg.d rd, rs fsgnjn.d rd, rs, rs Double-precision negate
beqz rs, off beq rs, x0, off Branch of equal zero
bnez rs, off bne rs, x0, off Branch if not equal zero
blez rs, off bge x0, rs, off Branch if less than or equal zero
bgez rs, off bge rs, x0, off Branch if greater than or equal zero
bltz rs, off blt rs, x0, off Branch if less than zero
bgtz rs, off blt x0, rs, off Branch if greater than zero
bgt rs, rt, off blt rt, rs, off Branch if greater than
ble rs, rt, off bge rt, rs, off Branch if less than or equal
bgtu rs, rt, off bltu rt, rs, off Branch if greater than, unsigned
bleu rs, rt, off bgeu rt, rs, off Branch if greater than or equal, unsigned
j off jal x0, off Jump
jal off jal x1, off Jump and link
jr rs jalr x0, rs, 0 Jump register
jalr rs jalr x1, rs, 0 Jump and link register
ret jalr x0, x1, 0 Return from subroutine
call off auipc x6, off[31:12]
jalr x1, x6, off[11:0]
Call far-away subroutine
tail off auipc x6, off[31:13]
jalr x0, x6, off[11:0]
Tail call far-away subroutine
fence fence iorw, iorw Fence on all memory and I/O

Pseudoinstructions for accessing control and status registers

rdinstret[h] rd csrrs rd, instret[h], x0 Read instructions-retired counter
rdcycle[h] rd csrrs rd, cycle[h], x0 Read cycle counter
rdtime[h] rd csrrs rd, time[h], x0 Read real-time clock
csrr rd, csr csrrs rd, csr, x0 Read CSR
csrw csr, rs csrrw x0, csr, rs Write CSR
csrs csr, rs csrrs x0, csr, rs Set bits in CSR
csrc csr, rs csrrc x0, csr, rs Clear bits in CSR
csrwi csr, imm csrrwi x0, csr, imm Write CSR, immediate
csrsi csr, imm csrrsi x0, csr, imm Set bits in CSR, immediate
csrci csr, imm csrrci x0, csr, imm Clear bits in CSR, immediate
frcsr rd csrrs rd, fcsr, x0 Read FP control/status register
fscsr rd, rs csrrw rd, fcsr, rs Swap FP control/status register
fscsr rs csrrw x0, fcsr, rs Write FP control/status register
frrm rd csrrs rd, frm, x0 Read FP rounding mode
fsrm rd, rs csrrw rd, frm, rs Swap FP rounding mode
fsrm rs csrrw x0, frm, rs Write FP rounding mode
fsrmi rd, imm csrrwi rd, frm, imm Swap FP rounding mode, immediate
fsrmi imm csrrwi x0, frm, imm Write FP rounding mode, immediate
frflags rd csrrs rd, fflags, x0 Read FP exception flags
fsflags rd, rs csrrw rd, fflags, rs Swap FP exception flags
fsflags rs csrrw x0, fflags, rs Write FP exception flags
fsflagsi rd, imm csrrwi rd, fflags, imm Swap FP exception flags, immediate
fsflagsi imm csrrwi x0, fflags, imm Write FP exception flags, immediate


OpenSBI loads firmware at the address 0x80000000. It then performs initial setup, does hart lottery which selects a single hart that will continue the boot process. Other harts are put into a loop and continuosly wait for interrupts. It then transfers control to the supervisor, at address 0x80200000.

.option push
.option norelax
la gp, _global_pointer
.option pop
la sp, _stack_end
add fp, sp, zero
j main

Other references

Licensed under CC BY-SA 4.0.