本章基于 RISC-V 指令集手册(Volume I: Unprivileged Spec, Version 2.1) 编写。 若存在与标准差异,请以 2.1 版本为准。
XLEN的约定
| 架构名称 | 描述 |
|---|---|
| riscv32 | XLEN = 32 的 RISC-V 架构(即 RV32I 或 RV32E),使用 32 位寄存器和地址空间。 |
| riscv64 | XLEN = 64 的 RISC-V 架构(即 RV64I 或 RV64E),使用 64 位寄存器和地址空间。 |
RV32I 是整个 RISC-V 架构的核心,所有其他扩展(如 M、A、F、D、C)都是在此基础上叠加的。
RISC-V 架构包含 32 个通用寄存器(x0–x31),每个寄存器宽度为 32 位(RV32)或 64 位(RV64)。 这些寄存器可用于整数计算、地址、参数传递等。
| 寄存器编号 | 名称 | 说明 |
|---|---|---|
| x0–x31 | 通用寄存器 | 每个都是 32 位,可用于整数计算、地址、参数传递等 |
💡 注意:
x0永远等于 0。写入它的值将被丢弃。
虽然硬件内部寄存器编号为 x0–x31,
但编译器与汇编通常使用更具语义的 ABI 命名。
这些别名在函数调用、参数传递与系统调用中非常关键。
| 编号 | ABI 名 | 含义 |
|---|---|---|
| x0 | zero | 恒为 0 |
| x1 | ra | 返回地址 (Return Address) |
| x2 | sp | 栈指针 (Stack Pointer) |
| x3 | gp | 全局指针 (Global Pointer) |
| x4 | tp | 线程指针 (Thread Pointer) |
| x5–x7 | t0–t2 | 临时寄存器 (Temporaries) |
| x8 | s0 / fp | 保存寄存器 / 帧指针 |
| x9 | s1 | 保存寄存器 |
| x10–x11 | a0–a1 | 参数 / 返回值 |
| x12–x17 | a2–a7 | 参数寄存器 |
| x18–x27 | s2–s11 | 保存寄存器(callee-saved) |
| x28–x31 | t3–t6 | 临时寄存器(caller-saved) |
| 写法 | 含义 |
|---|---|
addi x5, x1, 10 |
用编号表示(硬件角度):x5 = x1 + 10 |
addi t0, ra, 10 |
用 ABI 名(软件角度):t0 = ra + 10 |
在汇编和调试器输出中,你通常看到的是 ABI 命名,因为它更直观。
| 分类 | 寄存器 | 保存责任 |
|---|---|---|
| 临时寄存器 | t0–t6 | 调用者保存 |
| 参数/返回值 | a0–a7 | 调用者设置 |
| 保存寄存器 | s0–s11 | 被调用者保存 |
| 特殊寄存器 | sp, ra, gp, tp | 系统/编译器管理 |
RISC-V 的所有指令长度均为 32 位,但根据操作类型不同,编码格式也不同。 常见的 6 种基础格式如下:
| 格式 | 典型用途 | 举例(ABI 命名) |
|---|---|---|
| R-type | 寄存器对寄存器运算 | add a0, a1, a2 |
| I-type | 立即数运算 / 加载 / 跳转 | addi t0, sp, 16 或 lw a0, 0(sp) |
| S-type | 存储指令 | sw a1, 8(sp) |
| B-type | 条件分支 | beq a0, a1, loop |
| U-type | 高位立即数加载 | lui t0, 0x12345 |
| J-type | 无条件跳转 | jal ra, main |
以下为每种格式的结构及说明(bit 编号从右至左 0–31)。
用于立即数操作、加载指令、跳转指令等。
┌──────────────┬──────┬───────┬──────┬────────┐
│ imm[11:0] │ rs1 │ funct3│ rd │ opcode │
├──────────────┼──────┼───────┼──────┼────────┤
│ 31..20 │19..15│14..12 │11..7 │ 6..0 │
└──────────────┴──────┴───────┴──────┴────────┘
📘 示例:addi t0, ra, 10
opcode = 0010011funct3 = 000rs1 = rard = t0imm = 10┌──────────────┬──────┬──────┬───────┬──────────┬────────┐
│ imm[11:5] │ rs2 │ rs1 │ funct3│ imm[4:0] │ opcode │
├──────────────┼──────┼──────┼───────┼──────────┼────────┤
│ 31..25 │24..20│19..15│14..12 │11..7 │ 6..0 │
└──────────────┴──────┴──────┴───────┴──────────┴────────┘
📘 示例:sw a0, 8(sp)
sp + 8┌──────┬──────────┬──────┬──────┬───────┬────────┬──────┬────────┐
│imm[12]│imm[10:5]│ rs2 │ rs1 │ funct3│imm[4:1]│imm[11]│ opcode │
├──────┼──────────┼──────┼──────┼───────┼────────┼──────┼────────┤
│ 31 │30..25 │24..20│19..15│14..12 │11..8 │7 │6..0 │
└──────┴──────────┴──────┴──────┴───────┴────────┴──────┴────────┘
📘 示例:beq a0, a1, loop
a0 == a1,跳转到标签 loop┌────────────────────────┬──────┬────────┐
│ imm[31:12] │ rd │ opcode │
├────────────────────────┼──────┼────────┤
│ 31..12 │11..7 │ 6..0 │
└────────────────────────┴──────┴────────┘
📘 示例:lui t0, 0x12345
0x12345 << 12 写入 t0┌──────┬──────────┬──────┬──────────┬──────┬────────┐
│imm[20]│imm[10:1]│imm[11]│imm[19:12]│ rd │ opcode │
├──────┼──────────┼──────┼──────────┼──────┼────────┤
│31 │30..21 │20 │19..12 │11..7 │ 6..0 │
└──────┴──────────┴──────┴──────────┴──────┴────────┘
📘 示例:jal ra, func
PC+4 存入 rafunc| 类型 | 用途 | 典型例子 |
|---|---|---|
| R | 寄存器运算 | add a0, a1, a2 |
| I | 立即数/加载 | addi a0, a0, 4 |
| S | 存储 | sw a0, 0(sp) |
| B | 条件跳转 | bne a0, zero, loop |
| U | 高位立即数 | lui t0, 0x12345 |
| J | 无条件跳转 | jal ra, label |
| 格式 | 常用指令 | 用途 |
|---|---|---|
| R | add, sub, and, or, sll | 寄存器间运算 |
| I | addi, lw, jalr | 立即数或加载 |
| S | sw, sh, sb | 存储 |
| B | beq, bne | 条件跳转 |
| U | lui, auipc | 高位立即数 |
| J | jal | 无条件跳转 |