RISC-V 寄存器系统概览
RISC-V 架构将寄存器分为三个主要类别:通用寄存器(GPRs)、程序计数器(PC)和控制状态寄存器(CSRs)。
1. 通用寄存器 (General Purpose Registers, GPRs)
RISC-V 提供了 32 个通用寄存器,编号从 $x0$ 到 $x31$。为了方便汇编编程和遵循调用约定(ABI),它们拥有特定的别名和用途。
| 寄存器编号 | ABI 别名 | 作用描述 | 调用约定 |
|---|---|---|---|
| $x0$ | zero | 硬编码为零,写入无效。 | - |
| $x1$ | ra | 返回地址。用于存储函数调用后的返回位置。 | 调用者保存 |
| $x2$ | sp | 栈指针。指向当前栈帧的栈顶。 | 被调用者保存 |
| $x3$ | gp | 全局指针。用于优化对全局静态数据的访问。 | - |
| $x4$ | tp | 线程指针。指向线程局部存储 (TLS) 或当前 CPU 私有数据。 | - |
| $x5-x7$ | t0-t2 | 临时寄存器。用于临时计算,无需在函数调用中保留。 | 调用者保存 |
| $x8$ | s0/fp | 被保存寄存器 / 帧指针。通常用于栈回溯。 | 被调用者保存 |
| $x9$ | s1 | 被保存寄存器。 | 被调用者保存 |
| $x10-x11$ | a0-a1 | 函数参数/返回值。$a0$ 也用于系统调用的第一个参数和返回值。 | 调用者保存 |
| $x12-x17$ | a2-a7 | 函数参数 $2$ 到 $7$。 | 调用者保存 |
| $x18-x27$ | s2-s11 | 被保存寄存器。函数调用时必须由被调用者保留其值。 | 被调用者保存 |
| $x28-x31$ | t3-t6 | 临时寄存器。 | 调用者保存 |
调用约定说明
- 调用者保存 (Caller-Saved): 如果调用函数(Caller)希望在被调用函数(Callee)返回后保留这些寄存器的值,则必须在调用前将它们保存在栈上。
- 被调用者保存 (Callee-Saved): 如果被调用函数(Callee)需要使用这些寄存器,它必须在函数入口保存它们的原始值,并在返回前恢复它们。
2. 程序计数器 (Program Counter, PC)
PC 是一个独立的、非编号的寄存器,它:
- 作用: 存储下一条要执行的指令地址。
- 访问方式: 无法通过通用寄存器指令直接读写。通过 JAL、JALR、分支指令以及硬件的指令提取机制隐式修改。
- 非特权级寄存器: PC 不属于 CSRs 集合。
3. 控制状态寄存器 (Control and Status Registers, CSRs)
CSRs 是 RISC-V 架构中的特权级寄存器,用于控制系统操作、处理中断和异常、以及管理内存保护。它们只能通过专用的原子指令(如 CSRRW, CSRRS, CSRRC)访问。
对于操作系统内核常用的 S 模式(Supervisor Mode),主要的 CSRs 包括:
| CSR 寄存器 | 作用描述 | 类别 |
|---|---|---|
| sstatus | Supervisor 状态寄存器。包含全局中断使能(SIE)和栈保护(SPP, SPIE)等关键状态位。 | 状态 |
| sepc | Supervisor 异常程序计数器。保存发生异常或中断时,被中断指令的地址。 | 异常 |
| scause | Supervisor 异常原因。记录导致陷阱(Trap)发生的原因(是中断还是异常)。 | 异常 |
| stval | Supervisor 陷阱值。在地址无效或指令无效等异常中,保存相关的错误值(如错误地址)。 | 异常 |
| satp | Supervisor 地址翻译和保护。包含当前页表的基地址(Page Table Base)和地址转换模式(如 Sv39)。 | 内存管理 |
| sie | Supervisor 中断使能。控制 S 模式下对特定中断源(如时钟、外部设备)的接收开关。 | 中断 |
| sip | Supervisor 中断待处理。指示哪些中断事件已发生,但尚未被 CPU 处理。 | 中断 |