本篇定位 :RISC-V 专题第 8 篇。模块化是 RISC-V 的灵魂,你天天用
-march=rv32imac但未必系统理清每个扩展是什么、怎么选、怎么和 -mabi 配。本篇给你完整扩展表 + -march/-mabi 匹配矩阵 + 选型评估方法。读完能给新芯片选型出技术意见、能配对工具链、能评估自定义扩展。
模块化 = 按需付费RISC-V 不是一坨大 ISA,是 base + 扩展拼装。你不用的扩展一点不占代码空间(编译器不生成那类指令)。这对资源受限 MCU 是优势:rv32i 极简核连乘法都没有,代码最小;要乘法加 M,要浮点加 F。选扩展 = 在代码体积/性能/硬件成本间权衡。
一、标准扩展全表
按字母顺序,加粗是常用:
| 扩展 | 全名 | 是什么 | 你的场景 |
|---|---|---|---|
| I(base) | Integer | 整数 base ISA,~40 指令,必选 | 所有 RISC-V 都有 |
| M | Multiply/Divide | 乘除法硬件(mul/div/rem) | 无 M 则软件 __divsi3 |
| A | Atomic | 原子指令(LR/SC/amo) | 多核同步、无锁队列 |
| F | Single-Precision Float | 单精度浮点(FPU + 32个f寄存器) | 浮点运算 |
| D | Double-Precision Float | 双精度浮点(64位f寄存器) | 高精度浮点 |
| C | Compressed | 16位压缩指令 | 省 ~30% 代码,MCU 必备 |
| V | Vector | 向量指令(VLEN可配) | AI 加速、DSP,你公司方向 |
| B | Bit Manipulation | 位操作(ctlz/popcount/旋转) | 加密、通信 |
| K | Cryptography | 加密指令(AES/SHA/SM) | 安全芯片(AEGIX 功能安全) |
| H | Hypervisor | 虚拟化扩展 | 虚拟机监控器 |
| P | Packed SIMD | 打包 SIMD(DSP) | 音频/视频(已较少用) |
| J | Dynamically Translated | 动态翻译(JIT) | 罕用 |
| Q | Quad-Precision Float | 四精度浮点 | 科学计算,罕见 |
| Zicsr | CSR 指令(独立扩展) | 必选,配 trap/中断用 | |
| Zifencei | fence.i 指令(独立扩展) | 自修改代码用 | |
| Zba/Zbb/Zbc/Zbs | Bit Manip 子集 | B 扩展的细分 | 按需 |
| Zfh/Zfhmin | Half-Precision Float | 半精度浮点(FP16) | AI 推理 |
| Zmmul | Multiply only | 只有乘法(无除法) | 极简核 |
| X* | Non-Standard | 自定义扩展 | 你公司 AI 加速器指令 |
1.1 Z 扩展(子扩展)
新版 RISC-V 把一些小扩展独立成 Z 开头,可以单独启用:
- Zicsr :CSR 读写指令(csrrw/csrrs...),几乎必选(没有它没法配 trap/中断)
- Zifencei:fence.i 指令,自修改代码/缓存同步用
- Zba/Zbb/Zbc/Zbs:B 扩展的四个子集,可单独选
- Zfh:半精度浮点(FP16),AI 推理常用
- Zmmul:只有乘法没除法,比 M 轻
新版 -march 写法:rv32imac_zicsr_zifencei(显式带 Z),老版 rv32imac 隐含 Zicsr。
1.2 base 位宽
| base | 位宽 | 寄存器 | 典型场景 |
|---|---|---|---|
| rv32i | 32 | x0-x31(32位) | MCU(你主战场) |
| rv64i | 64 | x0-x31(64位) | 应用处理器(Linux) |
| rv128i | 128 | x0-x31(128位) | 超算,罕见 |
二、各扩展详解(你用得到的)
2.1 M 扩展(乘除法)
mul rd, rs1, rs2 # rd = rs1 * rs2(低32位)
mulh rd, rs1, rs2 # 高32位(有符号)
mulhu rd, rs1, rs2 # 高32位(无符号)
div rd, rs1, rs2 # 有符号除法
divu rd, rs1, rs2 # 无符号
rem rd, rs1, rs2 # 有符号余数
remu rd, rs1, rs2 # 无符号
- 有 M:硬件指令,1-几十周期
- 无 M:编译器调
__mulsi3/__divsi3(软件实现,你 \[C++资源受限优化] 固化过) - 无 M 的核,除法极慢------这是你 ROM 固化软算术的根因
2.2 A 扩展(原子)
lr.w rd, (rs1) # Load-Reserved
sc.w rd, rs2, (rs1) # Store-Conditional
amoadd.w rd, rs2, (rs1) # 原子加
amoswap.w rd, rs2, (rs1) # 原子交换
amoand.w / amoor.w / amoxor.w # 原子与/或/异或
amomax.w / amomin.w # 原子最大/最小
- 多核同步必备(自旋锁、无锁队列)
- 单核 MCU 也可能用(原子操作防中断打断,替代关中断)
- A 扩展指令隐含内存屏障,不用额外 fence
2.3 F/D 扩展(浮点)
- F:32 个单精度浮点寄存器(f0-f31),单精度指令(fadd/fmul/fdiv...)
- D:扩展 f 寄存器到 64 位,双精度指令
- 有 F/D:浮点运算硬件加速
- 无 F/D:软件
__mulsf3/__adddf3(你固化过) - F/D 决定 -mabi 后缀(ilp32f/ilp32d)
2.4 C 扩展(压缩)⭐ MCU 必备
- 16 位压缩指令,省 ~30% 代码
- 硬件自动识别 16/32 位混合(看最低 2 位)
- 栈回溯变复杂(②专题讲过)
- MCU 几乎都开 C(Flash 紧)
2.5 V 扩展(向量)⭐
-
向量寄存器组(v0-v31,每寄存器 VLEN 位)
-
VLEN 可配(128/256/512...),芯片实现定
-
一条指令处理多个数据(SIMD)
-
用于 AI 推理、信号处理、图像
vadd.vv vd, vs2, vs1 # 向量+向量
vle32.v vd, (rs1) # 向量 load
vse32.v vs3, (rs1) # 向量 store
2.6 B/K 扩展(位操作/加密)
- B:位计数(ctz/clz/popcount)、位提取、旋转------加密/通信加速
- K:AES/SHA/SM2/SM3/SM4 指令------安全芯片用
- 功能安全(ISO 26262)可能用 K 扩展做加密加速
2.7 X 扩展(自定义)
- RISC-V 允许厂商加自定义指令(X 前缀)
- 编译器不认识,要用 inline asm 或厂商提供的 intrinsic
- 不走标准编码,栈回溯/反汇编可能识别为非法指令(注意)
三、-march 详解
-march 告诉编译器"目标 CPU 支持哪些扩展",编译器据此生成对应指令。
3.1 写法
-march=rv32imac # 32位 base + I + M + A + C
-march=rv32imafc # + F(单精度浮点)
-march=rv32imafdc # + D(双精度)
-march=rv64gc # 64位 + G(=IMAFD) + C
-march=rv32imac_zicsr_zifencei # 显式带 Z
3.2 G 的简写
G = IMAFD 组合,常和 C 一起:rv64gc = rv64 + IMAFD + C(Linux 常用)。
3.3 -march 选错的后果
| 情况 | 后果 |
|---|---|
| -march 比实际多扩展 | 生成 CPU 不支持的指令,执行触发非法指令异常(cause 2) |
| -march 比实际少扩展 | 退化用软件实现(如无 M 则软除法),性能差但能跑 |
| -march 不带 C | 代码体积大 ~30%,但栈回溯简单 |
保守策略:-march 只写 CPU 确定支持的扩展;不确定时宁可少写(软件实现能跑)。
四、-mabi 详解
-mabi 告诉编译器"调用约定用哪种",决定参数传递、浮点寄存器使用。
4.1 ABI 后缀
| -mabi | 整数位宽 | 浮点参数 | 浮点寄存器 |
|---|---|---|---|
| ilp32 | 32 | 软浮点(走整数寄存器/栈) | 不用 f 寄存器 |
| ilp32f | 32 | 单精度走 f0-f7 | 用 f 寄存器 |
| ilp32d | 32 | 双精度走 f 寄存器 | 用 f 寄存器 |
| lp64 | 64 | 软浮点 | --- |
| lp64f | 64 | 单精度 | --- |
| lp64d | 64 | 双精度 | --- |
4.2 -march 和 -mabi 必须匹配
| -march | 合法 -mabi | 说明 |
|---|---|---|
| rv32imac | ilp32 | 无浮点扩展,只能软浮点 |
| rv32imafc | ilp32 或 ilp32f | 有 F,可选硬浮点 |
| rv32imafdc | ilp32/ilp32f/ilp32d | 有 D,可选双精度 |
| rv64gc | lp64/lp64f/lp64d | 同理 |
-march/-mabi 不匹配 = 运行时崩
-march=rv32imafc -mabi=ilp32:有 FPU 但用软浮点 ABI,FPU 闲置(浪费但能跑)-march=rv32imac -mabi=ilp32f:无 FPU 但用硬浮点 ABI,编译器生成 f 寄存器指令,CPU 不支持→非法指令异常
不匹配不报编译错,运行时才崩------极难查。固化前锁死双方 -march/-mabi。
五、选型评估:新芯片怎么挑
评估 D23/N310 这类新芯片,从扩展角度看:
5.1 评估清单
| 维度 | 看什么 | 为什么 |
|---|---|---|
| base 位宽 | rv32 还是 rv64 | rv64 能寻址更大、跑 Linux 更顺 |
| 乘除法 | 有无 M | 无 M 软除法慢,或固化 |
| 浮点 | F/D/Zfh | AI/控制算法要浮点;FP16(Zfh)对 AI 推理 |
| 压缩 | 有无 C | 省 Flash,MCU 几乎必要 |
| 向量 | V 扩展,VLEN | AI 加速关键 |
| 原子 | 有无 A | 多核同步必备 |
| 加密 | K 扩展 | 安全芯片 |
| 自定义 | X 扩展 | 厂商差异化(AI/通信) |
| 中断 | PLIC 还是 AIA | 影响中断架构(⑤) |
| PMP 区数 | 16 还是更多 | 隔离需求 |
5.2 决策树
要跑 Linux? → rv64gc 起步
纯 MCU bare-metal? → rv32imac 起步
要浮点? → 加 F(单精度)或 D(双精度)
要 AI? → 加 V,看 VLEN
要多核? → 必须有 A
要安全? → 看 K
六、-march/-mabi 配置实战
6.1 CMake 配置
cmake
set(RISCV_MARCH "rv32imac" CACHE STRING "")
set(RISCV_MABI "ilp32" CACHE STRING "")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} \
-march=${RISCV_MARCH} -mabi=${RISCV_MABI} \
-msmall-data-limit=8")
6.2 常见组合
| 场景 | -march | -mabi |
|---|---|---|
| 极简 MCU(无乘除无浮点) | rv32ic | ilp32 |
| 标准 MCU(乘除,无浮点) | rv32imac | ilp32 |
| MCU + 单精度浮点 | rv32imafc | ilp32f |
| MCU + 双精度浮点 | rv32imafdc | ilp32d |
| 64位 Linux | rv64gc | lp64d |
| AI 加速核 | rv64imafdcv + X | lp64d |
6.3 验证当前芯片支持的扩展
bash
# 看 misa CSR(运行时)
csrr t0, misa
# misa[31:30]=MXL(位宽:1=32,2=64,3=128)
# misa[25:0]=扩展位图(I=8位,M=12位,A=0位,C=2位...)
# 或编译时看芯片手册
七、自定义扩展(X)使用
7.1 inline asm
c
// 假设厂商提供指令编码
#define AI_MATMUL(a, b, c) \
asm volatile(".word 0x0B123456" : : "r"(a), "r"(b), "r"(c))
7.2 厂商 intrinsic
c
#include "vendor_ai.h"
ai_matmul(buf_a, buf_b, buf_c); // 厂商提供的库函数,内部用 X 指令
7.3 注意事项
- X 指令不走标准编码,反汇编器(gdb/objdump)可能显示为
.word 0x...或误识别为非法指令 - 栈回溯扫到 X 指令可能误判(你 \[ARM vs RISC-V 栈回溯技术] 算法要排除 X 指令区)
- 编译器不知道 X 指令的副作用,要在 inline asm 里正确声明 clobber
八、本篇小结
- RISC-V = base I + 扩展拼装,常用 M/A/F/D/C/V/B/K + Z 子扩展 + X 自定义
- -march 告诉编译器目标支持什么扩展,-mabi 告诉调用约定(含浮点传递)
- -march/-mabi 必须匹配,不匹配运行时崩(非编译错)
- M 扩展决定有无硬件乘除(无 M 软除法,可 ROM 固化)
- C 扩展省 ~30% 代码,MCU 必备,但栈回溯复杂
- V 扩展是 AI 方向,X 扩展是厂商自定义
- 选型评估:按 Linux/MCU/浮点/AI/多核/安全需求选扩展组合
- misa CSR 运行时查 CPU 支持的扩展
速查表
| 场景 | -march/-mabi |
|---|---|
| 标准 MCU 无浮点 | rv32imac / ilp32 |
| MCU 单精度浮点 | rv32imafc / ilp32f |
| MCU 双精度浮点 | rv32imafdc / ilp32d |
| 64位 Linux | rv64gc / lp64d |
| 极简核 | rv32ic / ilp32 |
| 查 CPU 扩展 | csrr t0, misa |
| 省 30% 代码 | 带 C |
| 多核同步 | 需 A 扩展 |
| AI 推理 | V 扩展 + X 自定义 |
💡技术之路漫漫,分享是为了更好地交流。如果本文的内容对你有启发,希望能得到你的 点赞 👍 和 收藏 ⭐。
如果你在调试过程中遇到了其他问题,欢迎在 评论区 💬 留言,我们一起探讨。也欢迎 关注 👀 我,一起交流底层开发的那些事儿。