RISC-V 32 位基础指令集(RV32I)完整参考手册
RISC-V 32 位基础指令集(RV32I)完整参考手册
一、架构概述
RISC-V 是一个开源的精简指令集计算机(RISC)架构,由加州大学伯克利分校于 2010 年发起设计。
| 项目 | 说明 |
|---|---|
| 指令长度 | 固定 32 位(4 字节) |
| 寄存器数量 | 32 个通用寄存器(x0–x31) + PC |
| 寄存器宽度 | 32 位 |
| 字节序 | 小端(Little-endian) |
| 寻址方式 | 字节寻址 |
| 立即数范围 | 12 位(I/S 型)、20 位(U 型)、21 位(J 型) |
二、寄存器组详解
2.1 完整寄存器表
| 寄存器编号 | ABI 名称 | 别名 | 用途 | 调用约定 |
|---|---|---|---|---|
| x0 | zero | — | 硬连线零,读取恒为 0,写入无效 | — |
| x1 | ra | — | 返回地址(Return Address) | Caller-saved |
| x2 | sp | — | 栈指针(Stack Pointer) | Callee-saved |
| x3 | gp | — | 全局指针(Global Pointer) | — |
| x4 | tp | — | 线程指针(Thread Pointer) | — |
| x5 | t0 | — | 临时寄存器 / 链接暂存 | Caller-saved |
| x6 | t1 | — | 临时寄存器 | Caller-saved |
| x7 | t2 | — | 临时寄存器 | Caller-saved |
| x8 | s0 | fp | 保存寄存器 / 帧指针(Frame Pointer) | Callee-saved |
| x9 | s1 | — | 保存寄存器 | Callee-saved |
| x10 | a0 | — | 函数参数 0 / 返回值 0 | Caller-saved |
| x11 | a1 | — | 函数参数 1 / 返回值 1 | Caller-saved |
| x12 | a2 | — | 函数参数 2 | Caller-saved |
| x13 | a3 | — | 函数参数 3 | Caller-saved |
| x14 | a4 | — | 函数参数 4 | Caller-saved |
| x15 | a5 | — | 函数参数 5 | Caller-saved |
| x16 | a6 | — | 函数参数 6 | Caller-saved |
| x17 | a7 | — | 函数参数 7 / 系统调用号 | Caller-saved |
| x18 | s2 | — | 保存寄存器 | Callee-saved |
| x19 | s3 | — | 保存寄存器 | Callee-saved |
| x20 | s4 | — | 保存寄存器 | Callee-saved |
| x21 | s5 | — | 保存寄存器 | Callee-saved |
| x22 | s6 | — | 保存寄存器 | Callee-saved |
| x23 | s7 | — | 保存寄存器 | Callee-saved |
| x24 | s8 | — | 保存寄存器 | Callee-saved |
| x25 | s9 | — | 保存寄存器 | Callee-saved |
| x26 | s10 | — | 保存寄存器 | Callee-saved |
| x27 | s11 | — | 保存寄存器 | Callee-saved |
| x28 | t3 | — | 临时寄存器 | Caller-saved |
| x29 | t4 | — | 临时寄存器 | Caller-saved |
| x30 | t5 | — | 临时寄存器 | Caller-saved |
| x31 | t6 | — | 临时寄存器 | Caller-saved |
| — | pc | — | 程序计数器,不可直接读写 | — |
2.2 寄存器功能分组
┌─────────────────────────────────────────────────────────┐
│ 32 个通用寄存器 │
├─────────────┬───────────────────┬───────────────────────┤
│ 特殊寄存器 │ 调用相关寄存器 │ 通用工作寄存器 │
├─────────────┼───────────────────┼───────────────────────┤
│ x0 (zero) │ x1 (ra) │ x5-t0, x6-t1, x7-t2 │
│ x2 (sp) │ x8 (s0/fp) │ x28-t3, x29-t4 │
│ x3 (gp) │ x9 (s1) │ x30-t5, x31-t6 │
│ x4 (tp) │ x10-a0 ~ x17-a7 │ │
│ │ x18-s2 ~ x27-s11 │ │
└─────────────┴───────────────────┴───────────────────────┘
2.3 各寄存器详细说明
x0 (zero) — 零寄存器
- 最特殊的寄存器,硬件上恒输出 0
- 任何对 x0 的写入操作都会被忽略
- 利用 x0 可以实现许多伪指令,例如:
mv rd, rs→addi rd, rs, 0neg rd, rs→sub rd, x0, rsret→jalr x0, 0(ra)nop→addi x0, x0, 0li rd, imm(小立即数)→addi rd, x0, imm
x1 (ra) — 返回地址
jal(跳转并链接)和jalr(寄存器跳转并链接)会自动将返回地址(PC+4)写入 ra- 函数返回时通过
jalr x0, 0(ra)跳回调用点 - Caller-saved:被调函数可自由使用,调用者需自行保存
x2 (sp) — 栈指针
- 指向当前栈顶
- RISC-V 要求栈 16 字节对齐(RV32 中至少 4 字节对齐,ABI 推荐 16 字节)
- 栈从高地址向低地址增长(push 时 sp 减小)
- Callee-saved:被调函数必须保存和恢复
x3 (gp) — 全局指针
- 通常由链接器设置为指向全局数据区的中间位置
- 允许通过 gp + 12 位有符号偏移(±2KB)访问全局变量
- 在小型嵌入式程序中特别有用
- 调用约定中不归类为 caller/callee-saved,由系统管理
x4 (tp) — 线程指针
- 指向线程局部存储(TLS)区域
- 多线程环境中每个线程有独立的 tp 值
- 通常由运行时系统管理,用户代码很少直接修改
x5 (t0) — 临时寄存器 / 链接暂存
- 临时计算、中间结果
- 也被
auipc+jalr长跳转序列用作暂存 - Caller-saved
x6–x7 (t1, t2) — 临时寄存器
- 临时计算,不需要跨函数调用保持的值
- Caller-saved
x8 (s0/fp) — 保存寄存器 / 帧指针
- 双重角色:作为 s0 使用时是普通的 callee-saved 寄存器
- 作为 fp(帧指针)使用时,指向当前栈帧的固定位置
- 帧指针有助于调试器进行栈回溯(stack unwinding)
- Callee-saved
x9 (s1) — 保存寄存器
- 需要跨函数调用保持的局部变量
- Callee-saved
x10–x11 (a0, a1) — 参数 / 返回值寄存器
- 传递函数的前 2 个整数参数
- 函数返回值放在这两个寄存器中(可返回 64 位值:a0 低 32 位,a1 高 32 位)
- Caller-saved
x12–x17 (a2–a7) — 参数寄存器
- 传递函数的第 3–8 个整数参数
- a7 同时用于传递系统调用号(Linux 约定)
- Caller-saved
x18–x27 (s2–s11) — 保存寄存器
- 需要跨函数调用保持的局部变量(共 10 个)
- 被调函数如果使用了这些寄存器,必须在入口保存、出口恢复
- Callee-saved
x28–x31 (t3–t6) — 临时寄存器
- 额外的临时寄存器(共 4 个)
- Caller-saved
PC — 程序计数器
- 指向下一条要执行的指令地址
- 不能作为指令的源/目的寄存器直接访问
- 只能通过分支、跳转、异常等间接修改
2.4 Caller-saved 与 Callee-saved
Caller-saved(调用者保存)— 共 16 个:
ra, t0-t6, a0-a7
┌──────────────────────────────────────────────┐
│ 调用者如果需要在函数调用后继续使用这些寄存器, │
│ 必须在调用前自行保存到栈上。 │
│ 被调函数可以自由使用这些寄存器。 │
└──────────────────────────────────────────────┘
Callee-saved(被调者保存)— 共 13 个:
sp, s0-s11
┌──────────────────────────────────────────────┐
│ 被调函数如果要使用这些寄存器, │
│ 必须在函数入口保存原值,函数出口恢复原值。 │
│ 保证调用者看到的值不变。 │
└──────────────────────────────────────────────┘
2.5 函数调用示例
# int add(int a, int b) { return a + b; }
# 调用约定:a=a0, b=a1, 返回值=a0
add_func:
add a0, a0, a1 # a0 = a + b
ret # 返回(jalr x0, 0(ra))
# 调用 add(3, 5)
caller:
addi sp, sp, -16 # 分配栈帧
sw ra, 12(sp) # 保存返回地址(ra 是 caller-saved)
sw s0, 8(sp) # 保存 s0(callee-saved)
li a0, 3 # 第一个参数
li a1, 5 # 第二个参数
call add_func # 调用(等价于 jal ra, add_func)
# 返回值在 a0 中,值为 8
lw s0, 8(sp) # 恢复 s0
lw ra, 12(sp) # 恢复返回地址
addi sp, sp, 16 # 释放栈帧
ret
三、指令格式
3.1 六种基本格式
RISC-V 定义了 6 种 32 位指令格式:
R-type(寄存器-寄存器运算):
31 25 24 20 19 15 14 12 11 7 6 0
┌─────────┬───────┬───────┬──────┬──────┬─────────┐
│ funct7 │ rs2 │ rs1 │funct3│ rd │ opcode │
└─────────┴───────┴───────┴──────┴──────┴─────────┘
7 位 5 位 5 位 3 位 5 位 7 位
I-type(立即数运算 / 加载):
31 20 19 15 14 12 11 7 6 0
┌─────────────────┬───────┬──────┬──────┬─────────┐
│ imm[11:0] │ rs1 │funct3│ rd │ opcode │
└─────────────────┴───────┴──────┴──────┴─────────┘
12 位 5 位 3 位 5 位 7 位
S-type(存储):
31 25 24 20 19 15 14 12 11 7 6 0
┌─────────┬───────┬───────┬──────┬─────────┬─────────┐
│imm[11:5]│ rs2 │ rs1 │funct3│imm[4:0] │ opcode │
└─────────┴───────┴───────┴──────┴─────────┴─────────┘
7 位 5 位 5 位 3 位 5 位 7 位
B-type(条件分支):
31 30 25 24 20 19 15 14 12 11 8 7 6 0
┌───┬─────────┬───────┬───────┬──────┬───────┬───┬─────────┐
│12 │imm[10:5]│ rs2 │ rs1 │funct3│imm[4:1]│11 │ opcode │
└───┴─────────┴───────┴───────┴──────┴───────┴───┴─────────┘
1 位 6 位 5 位 5 位 3 位 4 位 1 位 7 位
U-type(高位立即数):
31 12 11 7 6 0
┌─────────────────────────────┬──────┬─────────┐
│ imm[31:12] │ rd │ opcode │
└─────────────────────────────┴──────┴─────────┘
20 位 5 位 7 位
J-type(无条件跳转):
31 30 21 20 19 12 11 7 6 0
┌───┬─────────────┬───┬─────────────┬──────┬─────────┐
│20 │ imm[10:1] │11 │ imm[19:12] │ rd │ opcode │
└───┴─────────────┴───┴─────────────┴──────┴─────────┘
1 位 10 位 1 位 8 位 5 位 7 位
3.2 立即数编码说明
| 格式 | 立即数范围 | 说明 |
|---|---|---|
| I-type | -2048 ~ +2047(12 位有符号) | 符号扩展到 32 位 |
| S-type | -2048 ~ +2047(12 位有符号) | 分为 imm[11:5] 和 imm[4:0] |
| B-type | -4096 ~ +4094(13 位有符号,步长 2) | 最低位恒为 0 |
| U-type | 0 ~ 1048575(20 位) | 直接放在高 20 位 |
| J-type | -1048576 ~ +1048574(21 位有符号,步长 2) | 最低位恒为 0 |
3.3 操作码(opcode)映射
| opcode[6:0] | 十六进制 | 格式 | 指令类别 |
|---|---|---|---|
| 0110111 | 0x37 | U-type | LUI |
| 0010111 | 0x17 | U-type | AUIPC |
| 1101111 | 0x6F | J-type | JAL |
| 1100111 | 0x67 | I-type | JALR |
| 1100011 | 0x63 | B-type | 分支指令 |
| 0000011 | 0x03 | I-type | 加载指令 |
| 0100011 | 0x23 | S-type | 存储指令 |
| 0010011 | 0x13 | I-type | 立即数算术/逻辑 |
| 0110011 | 0x33 | R-type | 寄存器算术/逻辑 |
| 0001111 | 0x0F | I-type | FENCE |
| 1110011 | 0x73 | I-type | 系统 / CSR |
3.4 funct3 编码
算术/逻辑指令(opcode = 0x13 / 0x33)
| funct3 | R-type 指令 | I-type 指令 |
|---|---|---|
| 000 | ADD / SUB | ADDI |
| 001 | SLL | SLLI |
| 010 | SLT | SLTI |
| 011 | SLTU | SLTIU |
| 100 | XOR | XORI |
| 101 | SRL / SRA | SRLI / SRAI |
| 110 | OR | ORI |
| 111 | AND | ANDI |
分支指令(opcode = 0x63)
| funct3 | 指令 | 条件 |
|---|---|---|
| 000 | BEQ | rs1 == rs2 |
| 001 | BNE | rs1 != rs2 |
| 100 | BLT | rs1 < rs2(有符号) |
| 101 | BGE | rs1 >= rs2(有符号) |
| 110 | BLTU | rs1 < rs2(无符号) |
| 111 | BGEU | rs1 >= rs2(无符号) |
加载指令(opcode = 0x03)
| funct3 | 指令 | 宽度 | 扩展方式 |
|---|---|---|---|
| 000 | LB | 8 位 | 符号扩展 |
| 001 | LH | 16 位 | 符号扩展 |
| 010 | LW | 32 位 | — |
| 100 | LBU | 8 位 | 零扩展 |
| 101 | LHU | 16 位 | 零扩展 |
存储指令(opcode = 0x23)
| funct3 | 指令 | 宽度 |
|---|---|---|
| 000 | SB | 8 位 |
| 001 | SH | 16 位 |
| 010 | SW | 32 位 |
四、RV32I 指令完整列表
4.1 算术指令
寄存器-寄存器(R-type)
| 指令 | 语法 | 操作 | 说明 |
|---|---|---|---|
| ADD | add rd, rs1, rs2 |
rd ← rs1 + rs2 | 有符号加法 |
| SUB | sub rd, rs1, rs2 |
rd ← rs1 - rs2 | 有符号减法 |
立即数算术(I-type)
| 指令 | 语法 | 操作 | 说明 |
|---|---|---|---|
| ADDI | addi rd, rs1, imm |
rd ← rs1 + sext(imm) | 加立即数(12 位有符号) |
高位立即数(U-type)
| 指令 | 语法 | 操作 | 说明 |
|---|---|---|---|
| LUI | lui rd, imm |
rd ← imm << 12 | 20 位立即数加载到高 20 位 |
| AUIPC | auipc rd, imm |
rd ← PC + (imm << 12) | PC 相对高位加载 |
加载 32 位常数示例:
lui a0, 0x12345 # a0 = 0x12345000
addi a0, a0, 0x678 # a0 = 0x12345678
注意: RV32I 没有 MUL、DIV、REM 指令,这些属于 M 扩展。
4.2 逻辑指令
| 指令 | 语法 | 操作 |
|---|---|---|
| AND | and rd, rs1, rs2 |
rd ← rs1 & rs2 |
| OR | or rd, rs1, rs2 |
rd ← rs1 | rs2 |
| XOR | xor rd, rs1, rs2 |
rd ← rs1 ^ rs2 |
| ANDI | andi rd, rs1, imm |
rd ← rs1 & sext(imm) |
| ORI | ori rd, rs1, imm |
rd ← rs1 | sext(imm) |
| XORI | xori rd, rs1, imm |
rd ← rs1 ^ sext(imm) |
特殊用法:
xori rd, rs, -1等价于按位取反(NOT)andi rd, rs, 0xFF可用于提取低 8 位andi rd, rs, 1可用于判断奇偶
4.3 移位指令
| 指令 | 语法 | 操作 | 说明 |
|---|---|---|---|
| SLL | sll rd, rs1, rs2 |
rd ← rs1 << rs2[4:0] | 逻辑左移 |
| SRL | srl rd, rs1, rs2 |
rd ← rs1 >> rs2[4:0] | 逻辑右移(补 0) |
| SRA | sra rd, rs1, rs2 |
rd ← rs1 >>> rs2[4:0] | 算术右移(补符号位) |
| SLLI | slli rd, rs1, shamt |
rd ← rs1 << shamt | 立即数逻辑左移 |
| SRLI | srli rd, rs1, shamt |
rd ← rs1 >> shamt | 立即数逻辑右移 |
| SRAI | srai rd, rs1, shamt |
rd ← rs1 >>> shamt | 立即数算术右移 |
- 移位量仅使用低 5 位(0–31)
SRAI通过 funct7 的最高位(bit 30 = 1)与SRLI(bit 30 = 0)区分
常见移位技巧:
slli a0, a0, 1 # a0 = a0 * 2
slli a0, a0, 3 # a0 = a0 * 8
srli a0, a0, 2 # a0 = a0 / 4(无符号)
srai a0, a0, 2 # a0 = a0 / 4(有符号,向负无穷取整)
4.4 比较指令
| 指令 | 语法 | 操作 | 说明 |
|---|---|---|---|
| SLT | slt rd, rs1, rs2 |
rd ← (rs1 < rs2) ? 1 : 0 | 有符号比较 |
| SLTU | sltu rd, rs1, rs2 |
rd ← (rs1 < rs2) ? 1 : 0 | 无符号比较 |
| SLTI | slti rd, rs1, imm |
rd ← (rs1 < sext(imm)) ? 1 : 0 | 有符号立即数比较 |
| SLTIU | sltiu rd, rs1, imm |
rd ← (rs1 < sext(imm)) ? 1 : 0 | 无符号立即数比较 |
注意: SLTIU 的立即数先符号扩展,然后按无符号数比较。
4.5 分支指令(B-type)
分支指令比较两个寄存器,若条件成立则跳转到 PC + offset。
| 指令 | 语法 | 跳转条件 |
|---|---|---|
| BEQ | beq rs1, rs2, offset |
rs1 == rs2 |
| BNE | bne rs1, rs2, offset |
rs1 != rs2 |
| BLT | blt rs1, rs2, offset |
rs1 < rs2(有符号) |
| BGE | bge rs1, rs2, offset |
rs1 >= rs2(有符号) |
| BLTU | bltu rs1, rs2, offset |
rs1 < rs2(无符号) |
| BGEU | bgeu rs1, rs2, offset |
rs1 >= rs2(无符号) |
- 偏移量范围:±4KB(12 位有符号,最低位恒为 0,步长 2 字节)
- 没有"大于"和"小于等于"指令,通过交换操作数实现:
bgt rs1, rs2, offset→blt rs2, rs1, offsetble rs1, rs2, offset→bge rs2, rs1, offset
循环示例:
li t0, 0 # sum = 0
li t1, 1 # i = 1
li t2, 101 # 上界 + 1
loop:
bge t1, t2, done # if (i >= 101) break
add t0, t0, t1 # sum += i
addi t1, t1, 1 # i++
j loop # 无条件跳回
done:
# t0 = 5050 (1+2+...+100)
4.6 跳转指令
JAL(Jump And Link)— J-type
| 指令 | 语法 | 操作 |
|---|---|---|
| JAL | jal rd, offset |
rd ← PC+4; PC ← PC + sext(offset) |
- 偏移量范围:±1MB(20 位有符号,最低位恒为 0)
- 典型用法:
jal ra, label— 调用函数,返回地址存入 ra
JALR(Jump And Link Register)— I-type
| 指令 | 语法 | 操作 |
|---|---|---|
| JALR | jalr rd, rs1, imm |
rd ← PC+4; PC ← (rs1 + sext(imm)) & ~1 |
- 跳转目标 =
rs1 + 立即数,最低位清零(保证 2 字节对齐) - 典型用法:
- 函数返回:
jalr x0, 0(ra) - 间接调用:
jalr ra, 0(a0) - 函数指针调用
- 函数返回:
4.7 加载指令(I-type)
| 指令 | 语法 | 操作 |
|---|---|---|
| LB | lb rd, imm(rs1) |
rd ← sext(M[rs1+imm][7:0]) |
| LBU | lbu rd, imm(rs1) |
rd ← zext(M[rs1+imm][7:0]) |
| LH | lh rd, imm(rs1) |
rd ← sext(M[rs1+imm][15:0]) |
| LHU | lhu rd, imm(rs1) |
rd ← zext(M[rs1+imm][15:0]) |
| LW | lw rd, imm(rs1) |
rd ← M[rs1+imm][31:0] |
- 偏移量:12 位有符号(-2048 ~ +2047)
LB/LH符号扩展到 32 位,LBU/LHU零扩展
4.8 存储指令(S-type)
| 指令 | 语法 | 操作 |
|---|---|---|
| SB | sb rs2, imm(rs1) |
M[rs1+imm][7:0] ← rs2[7:0] |
| SH | sh rs2, imm(rs1) |
M[rs1+imm][15:0] ← rs2[15:0] |
| SW | sw rs2, imm(rs1) |
M[rs1+imm][31:0] ← rs2[31:0] |
- 偏移量:12 位有符号(-2048 ~ +2047)
4.9 系统指令
| 指令 | 语法 | 说明 |
|---|---|---|
| ECALL | ecall |
环境调用(系统调用),陷入操作系统 |
| EBREAK | ebreak |
断点异常,用于调试器 |
| FENCE | fence pred, succ |
内存屏障,保证多核内存一致性 |
| FENCE.I | fence.i |
指令缓存同步,用于自修改代码 |
系统调用约定(Linux RISC-V):
# write(1, buffer, length)
li a7, 64 # 系统调用号 64 = write
li a0, 1 # fd = stdout
la a1, buffer # 缓冲区地址
li a2, 13 # 长度
ecall # 陷入内核
# 返回值在 a0 中
4.10 CSR 指令
CSR(Control and Status Register)用于访问特权寄存器。
| 指令 | 语法 | 操作 |
|---|---|---|
| CSRRW | csrrw rd, csr, rs1 |
rd ← CSR; CSR ← rs1 |
| CSRRS | csrrs rd, csr, rs1 |
rd ← CSR; CSR ← CSR | rs1 |
| CSRRC | csrrc rd, csr, rs1 |
rd ← CSR; CSR ← CSR & ~rs1 |
| CSRRWI | csrrwi rd, csr, uimm |
rd ← CSR; CSR ← uimm(5 位) |
| CSRRSI | csrrsi rd, csr, uimm |
rd ← CSR; CSR ← CSR | uimm |
| CSRRCI | csrrci rd, csr, uimm |
rd ← CSR; CSR ← CSR & ~uimm |
常用 CSR 寄存器:
| 地址 | 名称 | 说明 |
|---|---|---|
| 0x000 | ustatus | 用户模式状态 |
| 0x005 | utvec | 用户模式陷阱向量基址 |
| 0x041 | uepc | 用户模式异常 PC |
| 0x042 | ucause | 用户模式异常原因 |
| 0x043 | utval | 用户模式异常附加信息 |
| 0x044 | uip | 用户模式中断挂起 |
| 0x100 | sstatus | 监管者模式状态 |
| 0x104 | sie | 监管者中断使能 |
| 0x105 | stvec | 监管者陷阱向量 |
| 0x141 | sepc | 监管者异常 PC |
| 0x142 | scause | 监管者异常原因 |
| 0x143 | stval | 监管者异常附加信息 |
| 0x144 | sip | 监管者中断挂起 |
| 0x180 | satp | 监管者地址转换与保护 |
| 0x300 | mstatus | 机器模式状态 |
| 0x301 | misa | ISA 能力寄存器 |
| 0x302 | medeleg | 机器异常委托 |
| 0x303 | mideleg | 机器中断委托 |
| 0x304 | mie | 机器中断使能 |
| 0x305 | mtvec | 机器陷阱向量 |
| 0x340 | mscratch | 机器临时寄存器 |
| 0x341 | mepc | 机器异常 PC |
| 0x342 | mcause | 机器异常原因 |
| 0x343 | mtval | 机器异常附加信息 |
| 0x344 | mip | 机器中断挂起 |
| 0xB00 | mcycle | 周期计数器(低 32 位) |
| 0xB02 | minstret | 退休指令计数器(低 32 位) |
| 0xB80 | mcycleh | 周期计数器(高 32 位) |
| 0xB82 | minstreth | 退休指令计数器(高 32 位) |
| 0xF11 | mvendorid | 厂商 ID |
| 0xF12 | marchid | 架构 ID |
| 0xF13 | mimpid | 实现 ID |
| 0xF14 | mhartid | 硬件线程 ID |
五、完整伪指令表
伪指令由汇编器展开为一条或多条真实指令。
5.1 数据传输伪指令
| 伪指令 | 展开形式 | 说明 |
|---|---|---|
NOP |
addi x0, x0, 0 |
空操作 |
LI rd, imm |
addi 或 lui+addi |
加载立即数(自动选择最短序列) |
MV rd, rs |
addi rd, rs, 0 |
寄存器复制 |
NOT rd, rs |
xori rd, rs, -1 |
按位取反 |
NEG rd, rs |
sub rd, x0, rs |
算术取反 |
NEGW rd, rs |
subw rd, x0, rs |
算术取反(RV64,32 位) |
SEXT.W rd, rs |
addiw rd, rs, 0 |
符号扩展字(RV64) |
5.2 算术伪指令
| 伪指令 | 展开形式 | 说明 |
|---|---|---|
SEQZ rd, rs |
sltiu rd, rs, 1 |
rs == 0 时 rd = 1 |
SNEZ rd, rs |
sltu rd, x0, rs |
rs != 0 时 rd = 1 |
SLTZ rd, rs |
slt rd, rs, x0 |
rs < 0 时 rd = 1 |
SGTZ rd, rs |
slt rd, x0, rs |
rs > 0 时 rd = 1 |
5.3 分支伪指令
| 伪指令 | 展开形式 | 说明 |
|---|---|---|
BEQZ rs, offset |
beq rs, x0, offset |
rs == 0 时跳转 |
BNEZ rs, offset |
bne rs, x0, offset |
rs != 0 时跳转 |
BLEZ rs, offset |
bge x0, rs, offset |
rs <= 0 时跳转 |
BGEZ rs, offset |
bge rs, x0, offset |
rs >= 0 时跳转 |
BLTZ rs, offset |
blt rs, x0, offset |
rs < 0 时跳转 |
BGTZ rs, offset |
blt x0, rs, offset |
rs > 0 时跳转 |
BGT rs1, rs2, offset |
blt rs2, rs1, offset |
rs1 > rs2(有符号) |
BLE rs1, rs2, offset |
bge rs2, rs1, offset |
rs1 <= rs2(有符号) |
BGTU rs1, rs2, offset |
bltu rs2, rs1, offset |
rs1 > rs2(无符号) |
BLEU rs1, rs2, offset |
bgeu rs2, rs1, offset |
rs1 <= rs2(无符号) |
5.4 跳转伪指令
| 伪指令 | 展开形式 | 说明 |
|---|---|---|
J offset |
jal x0, offset |
无条件跳转(不保存返回地址) |
JAL offset |
jal ra, offset |
调用函数(保存返回地址到 ra) |
JR rs |
jalr x0, 0(rs) |
寄存器间接跳转 |
JALR rs |
jalr ra, 0(rs) |
寄存器间接调用 |
RET |
jalr x0, 0(ra) |
函数返回 |
CALL offset |
auipc ra, offset_hi + jalr ra, ra, offset_lo |
长距离函数调用 |
TAIL offset |
auipc t0, offset_hi + jalr x0, t0, offset_lo |
尾调用(不保存返回地址) |
LA rd, symbol |
auipc rd, offset_hi + addi/lw rd, rd, offset_lo |
加载符号地址 |
5.5 CSR 伪指令
| 伪指令 | 展开形式 | 说明 |
|---|---|---|
CSRR rd, csr |
csrrs rd, csr, x0 |
读取 CSR |
CSRW csr, rs |
csrrw x0, csr, rs |
写入 CSR |
CSRS csr, rs |
csrrs x0, csr, rs |
置位 CSR 位 |
CSRC csr, rs |
csrrc x0, csr, rs |
清除 CSR 位 |
CSRWI csr, uimm |
csrrwi x0, csr, uimm |
立即数写入 CSR |
CSRSI csr, uimm |
csrrsi x0, csr, uimm |
立即数置位 CSR |
CSRCI csr, uimm |
csrrci x0, csr, uimm |
立即数清除 CSR |
RDCYCLE rd |
csrrs rd, cycle, x0 |
读周期计数器 |
RDTIME rd |
csrrs rd, time, x0 |
读时间计数器 |
RDINSTRET rd |
csrrs rd, instret, x0 |
读退休指令计数器 |
六、内存模型
6.1 内存布局(典型 Linux 用户空间)
高地址 0xFFFF_FFFF
┌─────────────────────┐
│ 内核空间 │ ← 用户不可访问
├─────────────────────┤
│ 栈 (Stack) │ ← sp(向下增长)
│ ↓ │
│ │
│ (空闲区域) │
│ │
│ ↑ │
│ 堆 (Heap) │ ← brk/sbrk(向上增长)
├─────────────────────┤
│ .bss(未初始化数据) │
├─────────────────────┤
│ .data(已初始化数据) │ ← gp 指向附近
├─────────────────────┤
│ .rodata(只读数据) │
├─────────────────────┤
│ .text(代码段) │ ← 程序入口
└─────────────────────┘
低地址 0x0000_0000
6.2 栈操作约定
# 函数序言(Prologue)
addi sp, sp, -N # 分配 N 字节栈帧(N 必须 16 字节对齐)
sw ra, (N-4)(sp) # 保存返回地址
sw s0, (N-8)(sp) # 保存需要使用的 callee-saved 寄存器
...
# 函数尾声(Epilogue)
lw ra, (N-4)(sp) # 恢复返回地址
lw s0, (N-8)(sp) # 恢复 callee-saved 寄存器
addi sp, sp, N # 释放栈帧
ret # 返回
七、特权模式
RISC-V 定义了 3 个特权级别:
| 级别 | 编码 | 名称 | 典型用途 |
|---|---|---|---|
| 0 | 00 | User (U) | 用户应用程序 |
| 1 | 01 | Supervisor (S) | 操作系统内核 |
| 3 | 11 | Machine (M) | 固件 / 引导程序 |
- M 模式是所有实现必须支持的最低特权模式
- 嵌入式系统可仅使用 M 模式
- Linux 系统通常使用 U/S/M 三级
特权指令
| 指令 | 可用模式 | 说明 |
|---|---|---|
| ECALL | U, S, M | 环境调用 |
| EBREAK | U, S, M | 断点 |
| MRET | M | 从机器模式陷阱返回 |
| SRET | S, M | 从监管者模式陷阱返回 |
| WFI | S, M | 等待中断(低功耗) |
| SFENCE.VMA | S, M | 刷新 TLB |
八、分支预测提示
RISC-V 规范不强制要求分支预测,但常见实现会采用:
- 静态预测:后向分支预测为跳转(循环),前向分支预测为不跳转
- 动态预测:BHT(Branch History Table)/ BTB(Branch Target Buffer)
- RISC-V 的规整编码格式有利于快速分支目标计算
九、完整指令速查
9.1 按格式分类
| 格式 | 指令列表 |
|---|---|
| R-type | ADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND |
| I-type | ADDI, SLTI, SLTIU, XORI, ORI, ANDI, SLLI, SRLI, SRAI, LB, LH, LW, LBU, LHU, JALR, ECALL, EBREAK, FENCE, FENCE.I, CSRRW, CSRRS, CSRRC, CSRRWI, CSRRSI, CSRRCI |
| S-type | SB, SH, SW |
| B-type | BEQ, BNE, BLT, BGE, BLTU, BGEU |
| U-type | LUI, AUIPC |
| J-type | JAL |
9.2 按功能分类
┌────────────────────────────────────────────────────────┐
│ RV32I 指令集总览 │
├──────────┬─────────────────────────────────────────────┤
│ 算术 │ ADD, SUB, ADDI, LUI, AUIPC │
├──────────┼─────────────────────────────────────────────┤
│ 逻辑 │ AND, OR, XOR, ANDI, ORI, XORI │
├──────────┼─────────────────────────────────────────────┤
│ 移位 │ SLL, SRL, SRA, SLLI, SRLI, SRAI │
├──────────┼─────────────────────────────────────────────┤
│ 比较 │ SLT, SLTU, SLTI, SLTIU │
├──────────┼─────────────────────────────────────────────┤
│ 分支 │ BEQ, BNE, BLT, BGE, BLTU, BGEU │
├──────────┼─────────────────────────────────────────────┤
│ 跳转 │ JAL, JALR │
├──────────┼─────────────────────────────────────────────┤
│ 加载 │ LB, LBU, LH, LHU, LW │
├──────────┼─────────────────────────────────────────────┤
│ 存储 │ SB, SH, SW │
├──────────┼─────────────────────────────────────────────┤
│ 系统 │ ECALL, EBREAK, FENCE, FENCE.I │
├──────────┼─────────────────────────────────────────────┤
│ CSR │ CSRRW, CSRRS, CSRRC, CSRRWI, CSRRSI, CSRRCI│
└──────────┴─────────────────────────────────────────────┘
十、完整示例程序
10.1 计算数组元素之和
# int array_sum(int *arr, int n) {
# int sum = 0;
# for (int i = 0; i < n; i++)
# sum += arr[i];
# return sum;
# }
# 参数:a0 = arr 指针, a1 = n
# 返回值:a0 = sum
array_sum:
li t0, 0 # sum = 0
li t1, 0 # i = 0
.loop:
bge t1, t1, .done # if (i >= n) break
lw t2, 0(a0) # t2 = arr[i]
add t0, t0, t2 # sum += arr[i]
addi a0, a0, 4 # arr++(int 为 4 字节)
addi t1, t1, 1 # i++
j .loop
.done:
mv a0, t0 # 返回值 = sum
ret
10.2 字符串长度
# int strlen(const char *s) {
# int len = 0;
# while (*s++) len++;
# return len;
# }
# 参数:a0 = s
# 返回值:a0 = 长度
strlen:
li t0, 0 # len = 0
.loop:
lb t1, 0(a0) # t1 = *s
beq t1, x0, .done # if (*s == 0) break
addi t0, t0, 1 # len++
addi a0, a0, 1 # s++
j .loop
.done:
mv a0, t0 # 返回 len
ret
10.3 递归阶乘
# int factorial(int n) {
# if (n <= 1) return 1;
# return n * factorial(n-1);
# }
# 参数:a0 = n
# 返回值:a0 = n!
factorial:
addi sp, sp, -8 # 分配栈帧
sw ra, 4(sp) # 保存返回地址
sw s0, 0(sp) # 保存 s0
mv s0, a0 # s0 = n
addi t0, x0, 1 # t0 = 1
ble a0, t0, .base # if (n <= 1) goto base
addi a0, s0, -1 # a0 = n - 1
call factorial # 递归调用
# a0 = factorial(n-1)
mul a0, s0, a0 # a0 = n * factorial(n-1)(需要 M 扩展)
# 若无 M 扩展,需用移位和加法实现乘法
j .epilogue
.base:
li a0, 1 # 返回 1
.epilogue:
lw s0, 0(sp) # 恢复 s0
lw ra, 4(sp) # 恢复返回地址
addi sp, sp, 8 # 释放栈帧
ret
10.4 系统调用示例(Linux)
.section .data
msg:
.string "Hello, RISC-V!\n"
.section .text
.globl _start
_start:
# write(1, msg, 15)
li a7, 64 # syscall: write
li a0, 1 # fd: stdout
la a1, msg # buf: 消息地址
li a2, 15 # count: 15 字节
ecall
# exit(0)
li a7, 93 # syscall: exit
li a0, 0 # status: 0
ecall
十一、与其他 RISC 架构对比
| 特性 | RV32I | ARM (A32) | MIPS32 | x86-32 |
|---|---|---|---|---|
| 指令长度 | 固定 32 位 | 固定 32 位 | 固定 32 位 | 变长 1–15 字节 |
| 通用寄存器 | 32 个 | 16 个 | 32 个 | 8 个 |
| 条件执行 | 分支指令 | 条件码 | 无 | 条件码 |
| 延迟槽 | 无 | 无 | 有(MIPS I) | 无 |
| 零寄存器 | x0 = 0 | 无 | $zero = 0 | 无 |
| 编码复杂度 | 极低 | 中等 | 低 | 高 |
| 授权 | 开源免费 | 商业 | 商业 | 商业 |
附录:RV32I 指令编码汇总
指令 | opcode | funct3 | funct7 | 格式
----------|---------|--------|----------|--------
LUI | 0110111 | — | — | U
AUIPC | 0010111 | — | — | U
JAL | 1101111 | — | — | J
JALR | 1100111 | 000 | — | I
BEQ | 1100011 | 000 | — | B
BNE | 1100011 | 001 | — | B
BLT | 1100011 | 100 | — | B
BGE | 1100011 | 101 | — | B
BLTU | 1100011 | 110 | — | B
BGEU | 1100011 | 111 | — | B
LB | 0000011 | 000 | — | I
LH | 0000011 | 001 | — | I
LW | 0000011 | 010 | — | I
LBU | 0000011 | 100 | — | I
LHU | 0000011 | 101 | — | I
SB | 0100011 | 000 | — | S
SH | 0100011 | 001 | — | S
SW | 0100011 | 010 | — | S
ADDI | 0010011 | 000 | — | I
SLTI | 0010011 | 010 | — | I
SLTIU | 0010011 | 011 | — | I
XORI | 0010011 | 100 | — | I
ORI | 0010011 | 110 | — | I
ANDI | 0010011 | 111 | — | I
SLLI | 0010011 | 001 | 0000000 | I
SRLI | 0010011 | 101 | 0000000 | I
SRAI | 0010011 | 101 | 0100000 | I
ADD | 0110011 | 000 | 0000000 | R
SUB | 0110011 | 000 | 0100000 | R
SLL | 0110011 | 001 | 0000000 | R
SLT | 0110011 | 010 | 0000000 | R
SLTU | 0110011 | 011 | 0000000 | R
XOR | 0110011 | 100 | 0000000 | R
SRL | 0110011 | 101 | 0000000 | R
SRA | 0110011 | 101 | 0100000 | R
OR | 0110011 | 110 | 0000000 | R
AND | 0110011 | 111 | 0000000 | R
FENCE | 0001111 | 000 | — | I
FENCE.I | 0001111 | 001 | — | I
ECALL | 1110011 | 000 | 0000000 | I
EBREAK | 1110011 | 000 | 0000001 | I
CSRRW | 1110011 | 001 | — | I
CSRRS | 1110011 | 010 | — | I
CSRRC | 1110011 | 011 | — | I
CSRRWI | 1110011 | 101 | — | I
CSRRSI | 1110011 | 110 | — | I
CSRRCI | 1110011 | 111 | — | I
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)