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 名称别名用途调用约定
x0zero硬连线零,读取恒为 0,写入无效
x1ra返回地址(Return Address)Caller-saved
x2sp栈指针(Stack Pointer)Callee-saved
x3gp全局指针(Global Pointer)
x4tp线程指针(Thread Pointer)
x5t0临时寄存器 / 链接暂存Caller-saved
x6t1临时寄存器Caller-saved
x7t2临时寄存器Caller-saved
x8s0fp保存寄存器 / 帧指针(Frame Pointer)Callee-saved
x9s1保存寄存器Callee-saved
x10a0函数参数 0 / 返回值 0Caller-saved
x11a1函数参数 1 / 返回值 1Caller-saved
x12a2函数参数 2Caller-saved
x13a3函数参数 3Caller-saved
x14a4函数参数 4Caller-saved
x15a5函数参数 5Caller-saved
x16a6函数参数 6Caller-saved
x17a7函数参数 7 / 系统调用号Caller-saved
x18s2保存寄存器Callee-saved
x19s3保存寄存器Callee-saved
x20s4保存寄存器Callee-saved
x21s5保存寄存器Callee-saved
x22s6保存寄存器Callee-saved
x23s7保存寄存器Callee-saved
x24s8保存寄存器Callee-saved
x25s9保存寄存器Callee-saved
x26s10保存寄存器Callee-saved
x27s11保存寄存器Callee-saved
x28t3临时寄存器Caller-saved
x29t4临时寄存器Caller-saved
x30t5临时寄存器Caller-saved
x31t6临时寄存器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, rsaddi rd, rs, 0
    • neg rd, rssub rd, x0, rs
    • retjalr x0, 0(ra)
    • nopaddi x0, x0, 0
    • li 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-type0 ~ 1048575(20 位)直接放在高 20 位
J-type-1048576 ~ +1048574(21 位有符号,步长 2)最低位恒为 0

3.3 操作码(opcode)映射

opcode[6:0]十六进制格式指令类别
01101110x37U-typeLUI
00101110x17U-typeAUIPC
11011110x6FJ-typeJAL
11001110x67I-typeJALR
11000110x63B-type分支指令
00000110x03I-type加载指令
01000110x23S-type存储指令
00100110x13I-type立即数算术/逻辑
01100110x33R-type寄存器算术/逻辑
00011110x0FI-typeFENCE
11100110x73I-type系统 / CSR

3.4 funct3 编码

算术/逻辑指令(opcode = 0x13 / 0x33)
funct3R-type 指令I-type 指令
000ADD / SUBADDI
001SLLSLLI
010SLTSLTI
011SLTUSLTIU
100XORXORI
101SRL / SRASRLI / SRAI
110ORORI
111ANDANDI
分支指令(opcode = 0x63)
funct3指令条件
000BEQrs1 == rs2
001BNErs1 != rs2
100BLTrs1 < rs2(有符号)
101BGErs1 >= rs2(有符号)
110BLTUrs1 < rs2(无符号)
111BGEUrs1 >= rs2(无符号)
加载指令(opcode = 0x03)
funct3指令宽度扩展方式
000LB8 位符号扩展
001LH16 位符号扩展
010LW32 位
100LBU8 位零扩展
101LHU16 位零扩展
存储指令(opcode = 0x23)
funct3指令宽度
000SB8 位
001SH16 位
010SW32 位

四、RV32I 指令完整列表

4.1 算术指令

寄存器-寄存器(R-type)
指令语法操作说明
ADDadd rd, rs1, rs2rd ← rs1 + rs2有符号加法
SUBsub rd, rs1, rs2rd ← rs1 - rs2有符号减法
立即数算术(I-type)
指令语法操作说明
ADDIaddi rd, rs1, immrd ← rs1 + sext(imm)加立即数(12 位有符号)
高位立即数(U-type)
指令语法操作说明
LUIlui rd, immrd ← imm << 1220 位立即数加载到高 20 位
AUIPCauipc rd, immrd ← PC + (imm << 12)PC 相对高位加载

加载 32 位常数示例:

lui  a0, 0x12345       # a0 = 0x12345000
addi a0, a0, 0x678     # a0 = 0x12345678

注意: RV32I 没有 MUL、DIV、REM 指令,这些属于 M 扩展。

4.2 逻辑指令

指令语法操作
ANDand rd, rs1, rs2rd ← rs1 & rs2
ORor rd, rs1, rs2rd ← rs1 | rs2
XORxor rd, rs1, rs2rd ← rs1 ^ rs2
ANDIandi rd, rs1, immrd ← rs1 & sext(imm)
ORIori rd, rs1, immrd ← rs1 | sext(imm)
XORIxori rd, rs1, immrd ← rs1 ^ sext(imm)

特殊用法:

  • xori rd, rs, -1 等价于按位取反(NOT)
  • andi rd, rs, 0xFF 可用于提取低 8 位
  • andi rd, rs, 1 可用于判断奇偶

4.3 移位指令

指令语法操作说明
SLLsll rd, rs1, rs2rd ← rs1 << rs2[4:0]逻辑左移
SRLsrl rd, rs1, rs2rd ← rs1 >> rs2[4:0]逻辑右移(补 0)
SRAsra rd, rs1, rs2rd ← rs1 >>> rs2[4:0]算术右移(补符号位)
SLLIslli rd, rs1, shamtrd ← rs1 << shamt立即数逻辑左移
SRLIsrli rd, rs1, shamtrd ← rs1 >> shamt立即数逻辑右移
SRAIsrai rd, rs1, shamtrd ← 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 比较指令

指令语法操作说明
SLTslt rd, rs1, rs2rd ← (rs1 < rs2) ? 1 : 0有符号比较
SLTUsltu rd, rs1, rs2rd ← (rs1 < rs2) ? 1 : 0无符号比较
SLTIslti rd, rs1, immrd ← (rs1 < sext(imm)) ? 1 : 0有符号立即数比较
SLTIUsltiu rd, rs1, immrd ← (rs1 < sext(imm)) ? 1 : 0无符号立即数比较

注意: SLTIU 的立即数先符号扩展,然后按无符号数比较。

4.5 分支指令(B-type)

分支指令比较两个寄存器,若条件成立则跳转到 PC + offset

指令语法跳转条件
BEQbeq rs1, rs2, offsetrs1 == rs2
BNEbne rs1, rs2, offsetrs1 != rs2
BLTblt rs1, rs2, offsetrs1 < rs2(有符号)
BGEbge rs1, rs2, offsetrs1 >= rs2(有符号)
BLTUbltu rs1, rs2, offsetrs1 < rs2(无符号)
BGEUbgeu rs1, rs2, offsetrs1 >= rs2(无符号)
  • 偏移量范围:±4KB(12 位有符号,最低位恒为 0,步长 2 字节)
  • 没有"大于"和"小于等于"指令,通过交换操作数实现:
    • bgt rs1, rs2, offsetblt rs2, rs1, offset
    • ble rs1, rs2, offsetbge 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
指令语法操作
JALjal rd, offsetrd ← PC+4; PC ← PC + sext(offset)
  • 偏移量范围:±1MB(20 位有符号,最低位恒为 0)
  • 典型用法:jal ra, label — 调用函数,返回地址存入 ra
JALR(Jump And Link Register)— I-type
指令语法操作
JALRjalr rd, rs1, immrd ← PC+4; PC ← (rs1 + sext(imm)) & ~1
  • 跳转目标 = rs1 + 立即数,最低位清零(保证 2 字节对齐)
  • 典型用法:
    • 函数返回:jalr x0, 0(ra)
    • 间接调用:jalr ra, 0(a0)
    • 函数指针调用

4.7 加载指令(I-type)

指令语法操作
LBlb rd, imm(rs1)rd ← sext(M[rs1+imm][7:0])
LBUlbu rd, imm(rs1)rd ← zext(M[rs1+imm][7:0])
LHlh rd, imm(rs1)rd ← sext(M[rs1+imm][15:0])
LHUlhu rd, imm(rs1)rd ← zext(M[rs1+imm][15:0])
LWlw rd, imm(rs1)rd ← M[rs1+imm][31:0]
  • 偏移量:12 位有符号(-2048 ~ +2047)
  • LB/LH 符号扩展到 32 位,LBU/LHU 零扩展

4.8 存储指令(S-type)

指令语法操作
SBsb rs2, imm(rs1)M[rs1+imm][7:0] ← rs2[7:0]
SHsh rs2, imm(rs1)M[rs1+imm][15:0] ← rs2[15:0]
SWsw rs2, imm(rs1)M[rs1+imm][31:0] ← rs2[31:0]
  • 偏移量:12 位有符号(-2048 ~ +2047)

4.9 系统指令

指令语法说明
ECALLecall环境调用(系统调用),陷入操作系统
EBREAKebreak断点异常,用于调试器
FENCEfence pred, succ内存屏障,保证多核内存一致性
FENCE.Ifence.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)用于访问特权寄存器。

指令语法操作
CSRRWcsrrw rd, csr, rs1rd ← CSR; CSR ← rs1
CSRRScsrrs rd, csr, rs1rd ← CSR; CSR ← CSR | rs1
CSRRCcsrrc rd, csr, rs1rd ← CSR; CSR ← CSR & ~rs1
CSRRWIcsrrwi rd, csr, uimmrd ← CSR; CSR ← uimm(5 位)
CSRRSIcsrrsi rd, csr, uimmrd ← CSR; CSR ← CSR | uimm
CSRRCIcsrrci rd, csr, uimmrd ← CSR; CSR ← CSR & ~uimm

常用 CSR 寄存器:

地址名称说明
0x000ustatus用户模式状态
0x005utvec用户模式陷阱向量基址
0x041uepc用户模式异常 PC
0x042ucause用户模式异常原因
0x043utval用户模式异常附加信息
0x044uip用户模式中断挂起
0x100sstatus监管者模式状态
0x104sie监管者中断使能
0x105stvec监管者陷阱向量
0x141sepc监管者异常 PC
0x142scause监管者异常原因
0x143stval监管者异常附加信息
0x144sip监管者中断挂起
0x180satp监管者地址转换与保护
0x300mstatus机器模式状态
0x301misaISA 能力寄存器
0x302medeleg机器异常委托
0x303mideleg机器中断委托
0x304mie机器中断使能
0x305mtvec机器陷阱向量
0x340mscratch机器临时寄存器
0x341mepc机器异常 PC
0x342mcause机器异常原因
0x343mtval机器异常附加信息
0x344mip机器中断挂起
0xB00mcycle周期计数器(低 32 位)
0xB02minstret退休指令计数器(低 32 位)
0xB80mcycleh周期计数器(高 32 位)
0xB82minstreth退休指令计数器(高 32 位)
0xF11mvendorid厂商 ID
0xF12marchid架构 ID
0xF13mimpid实现 ID
0xF14mhartid硬件线程 ID

五、完整伪指令表

伪指令由汇编器展开为一条或多条真实指令。

5.1 数据传输伪指令

伪指令展开形式说明
NOPaddi x0, x0, 0空操作
LI rd, immaddilui+addi加载立即数(自动选择最短序列)
MV rd, rsaddi rd, rs, 0寄存器复制
NOT rd, rsxori rd, rs, -1按位取反
NEG rd, rssub rd, x0, rs算术取反
NEGW rd, rssubw rd, x0, rs算术取反(RV64,32 位)
SEXT.W rd, rsaddiw rd, rs, 0符号扩展字(RV64)

5.2 算术伪指令

伪指令展开形式说明
SEQZ rd, rssltiu rd, rs, 1rs == 0 时 rd = 1
SNEZ rd, rssltu rd, x0, rsrs != 0 时 rd = 1
SLTZ rd, rsslt rd, rs, x0rs < 0 时 rd = 1
SGTZ rd, rsslt rd, x0, rsrs > 0 时 rd = 1

5.3 分支伪指令

伪指令展开形式说明
BEQZ rs, offsetbeq rs, x0, offsetrs == 0 时跳转
BNEZ rs, offsetbne rs, x0, offsetrs != 0 时跳转
BLEZ rs, offsetbge x0, rs, offsetrs <= 0 时跳转
BGEZ rs, offsetbge rs, x0, offsetrs >= 0 时跳转
BLTZ rs, offsetblt rs, x0, offsetrs < 0 时跳转
BGTZ rs, offsetblt x0, rs, offsetrs > 0 时跳转
BGT rs1, rs2, offsetblt rs2, rs1, offsetrs1 > rs2(有符号)
BLE rs1, rs2, offsetbge rs2, rs1, offsetrs1 <= rs2(有符号)
BGTU rs1, rs2, offsetbltu rs2, rs1, offsetrs1 > rs2(无符号)
BLEU rs1, rs2, offsetbgeu rs2, rs1, offsetrs1 <= rs2(无符号)

5.4 跳转伪指令

伪指令展开形式说明
J offsetjal x0, offset无条件跳转(不保存返回地址)
JAL offsetjal ra, offset调用函数(保存返回地址到 ra)
JR rsjalr x0, 0(rs)寄存器间接跳转
JALR rsjalr ra, 0(rs)寄存器间接调用
RETjalr x0, 0(ra)函数返回
CALL offsetauipc ra, offset_hi + jalr ra, ra, offset_lo长距离函数调用
TAIL offsetauipc t0, offset_hi + jalr x0, t0, offset_lo尾调用(不保存返回地址)
LA rd, symbolauipc rd, offset_hi + addi/lw rd, rd, offset_lo加载符号地址

5.5 CSR 伪指令

伪指令展开形式说明
CSRR rd, csrcsrrs rd, csr, x0读取 CSR
CSRW csr, rscsrrw x0, csr, rs写入 CSR
CSRS csr, rscsrrs x0, csr, rs置位 CSR 位
CSRC csr, rscsrrc x0, csr, rs清除 CSR 位
CSRWI csr, uimmcsrrwi x0, csr, uimm立即数写入 CSR
CSRSI csr, uimmcsrrsi x0, csr, uimm立即数置位 CSR
CSRCI csr, uimmcsrrci x0, csr, uimm立即数清除 CSR
RDCYCLE rdcsrrs rd, cycle, x0读周期计数器
RDTIME rdcsrrs rd, time, x0读时间计数器
RDINSTRET rdcsrrs 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 个特权级别:

级别编码名称典型用途
000User (U)用户应用程序
101Supervisor (S)操作系统内核
311Machine (M)固件 / 引导程序
  • M 模式是所有实现必须支持的最低特权模式
  • 嵌入式系统可仅使用 M 模式
  • Linux 系统通常使用 U/S/M 三级

特权指令

指令可用模式说明
ECALLU, S, M环境调用
EBREAKU, S, M断点
MRETM从机器模式陷阱返回
SRETS, M从监管者模式陷阱返回
WFIS, M等待中断(低功耗)
SFENCE.VMAS, M刷新 TLB

八、分支预测提示

RISC-V 规范不强制要求分支预测,但常见实现会采用:

  • 静态预测:后向分支预测为跳转(循环),前向分支预测为不跳转
  • 动态预测:BHT(Branch History Table)/ BTB(Branch Target Buffer)
  • RISC-V 的规整编码格式有利于快速分支目标计算

九、完整指令速查

9.1 按格式分类

格式指令列表
R-typeADD, SUB, SLL, SLT, SLTU, XOR, SRL, SRA, OR, AND
I-typeADDI, 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-typeSB, SH, SW
B-typeBEQ, BNE, BLT, BGE, BLTU, BGEU
U-typeLUI, AUIPC
J-typeJAL

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 架构对比

特性RV32IARM (A32)MIPS32x86-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
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐