最近这三年的工作时间大部分的工作,都是基于riscv的cpu和接口ip开发适配驱动,时不时的就要debug测试代码,面对很多都是汇编,所以也是整理下积累的一点点笔记,系列博客将总结下riscv相关的内容,一是给有需要的人一点点帮助,另外给自己梳理下方便日后查阅。
虽然现在大部分的程序都不在使用汇编,但是在一些特殊场景下:底层驱动、引导程序、高性能算法库等等,汇编还是扮演着重要作用。对于嵌入式驱动开发,虽然可能不要求熟练的coding汇编,但是至少做到能够看懂理解和编写一些简单的汇编程序。
先从汇编最基础的概念以及相关的知识开始简单了解,后续慢慢会继续更新完善。
1 riscv简介
1.1 ISA
ISA (Instruction Set Architecture) 指令集架构,可以说是CPU的灵魂,是软硬件之间的桥梁;定义了指令集(指令类型和编码、寻址方式)、数据类型、存储模型、系统模型(中断、异常、特权等级等)、软件可见的处理器状态(通用寄存器、PC、处理器状态等)。
1.2 CISC和RISC
指令集架构主要分为:
- 复杂指令集(Complex Instruction Set Computer)
- 精简指令集( Reduced Instruction Set Computer, RISC )
CISC与RISC的区别如下:
VS | 复杂指令集(CISC) | 精简指令集(RISC) |
---|---|---|
指令数量 | 多 | 少 |
指令系统复杂度 | 复杂 | 简单 |
指令长度 | 变长,不固定 | 等长,固定 |
寻址方式 | 多 | 少 |
指令格式 | 多 | 少且规整 |
各指令使用频率 | 相差很大 | 相差不大 |
指令执行时间 | 相差很大 | 相差不大 |
指令周期 | 多周期为主 | 单周期为主(流水线技术,大部分指令在一个机器周期完成) |
cpu寄存器数量 | 少 | 多(增加寄存器,以减少访存) |
指令并行性 | 低 | 高 |
可访存指令 | 不加限制 | 只有load/store等访存指令才能访问内存(减少了访存周期) |
优化编译实现 | 很难 | 较容易(依靠编译程序的优化来更有效的支持高级语言) |
代表架构 | x86 | ARM,MIPS,PowerPC,LoongArch,RISC-V等 |
目前主流的CISC就是x86,而RISC的代表则是ARM。
这里介绍的RISC-V是第5代精简指令集,也时属于RISC阵营一员,RISC-V架构主要由美国加州大学伯克利分校(简称伯克利)的Krste Asanovic 教授、Andrew Waterman 和Yunsup Lee等开发人员于2010年发明,并且得到了计算机体系结构领域的泰斗David Patterson 的大力支持。
另外,RISC-V(英文读作“ risk-five"),是一种全新的指令集架构。“V”包含两层意思, 一是这是Berkeley 从RISC I开始设计的第五代指令集架构: 二是它代表了变化( Variation )和向量( Vectors ) 。
关于RISC-V更多的介绍以及其他ISA的介绍,感兴趣自行搜索学习了解。
这里有一点主观观点要说一下——未来RISC-V一定会越来越好(可以学习了来评论区讨论下,就不具体展开啦)。
1.3 march
1.3.1 RISC-V指令架构有以下特点:
- 完全开放
- 指令简单
- 模块化设计,易于扩展
RISC-V 的指令集使用模块化的方式进行组织,每一个模块使用一个英文字母来表示。正是由于RISC-V模块化特点,RISC-V架构也有一套命名标准来描述当前CPU所支持指令集;比如:RV32I、RV64G、RV32IMA这样。
1.3.2通用的命名格式
如下:
RV[n][I/F/D/Q/M/C/A/B/E/H/K/V/P/J/T/N]
其中:
- RV代表这是RISC-V指令集
- n代表当前指令集是几位的,32位还是64位
- 后面的是指令集模块,模块含义如下表格
module name | class | description |
---|---|---|
RV32I | 基础指令 | 整数指令:包含算法、分支、逻辑、访存指令,有32个32位寄存器。能寻址32位地址空间 |
RV64I | 基础指令 | 整数指令:包含算法、分支、逻辑、访存指令,有32个64位寄存器。能寻址64位地址空间 |
RV128I | 基础指令 | 整数指令:包含算法、分支、逻辑、访存指令,有32个128位寄存器。能寻址128位地址空间 |
RV32E | 基础指令 | 与RV32I一样,只不过只使用前16个(0~15)32位寄存器 |
M | 扩展指令 | 包含乘法、除法、取模求余指令 |
F | 扩展指令 | 单精度浮点指令 |
D | 扩展指令 | 双精度浮点指令 |
Q | 扩展指令 | 四倍精度浮点指令 |
A | 扩展指令 | 原子操作指令:比如比较并交换,读改写等指令 |
C | 扩展指令 | 压缩指令:单指令长度为16位,主要用于改善程序大小 |
P | 扩展指令 | 单指令多数据(Packed-SIMD)指令 |
B | 扩展指令 | 位操作指令 |
K | 扩展指令 | 密码运算扩展指令集(Key) |
V | 扩展指令 | 可伸缩矢量扩展指令集(Vector) |
T | 扩展指令 | 事务内存指令集(Transactional Memory) |
H | 扩展指令 | 支持(Hypervisor)管理指令 |
J | 扩展指令 | 支持动态翻译语言指令 |
L | 扩展指令 | 十进制浮点指令 |
N | 扩展指令 | 用户中断指令 |
G | 通用指令 | 包含I、M、A、F、D 指令 |
以上模块的一个特定组合“ IMAFD ”,也被称为“通用”组合,用英文字母G 表示。因此RV32G 表示RV32IMAFD ,同理RV64G 表示RV64IMAFD 。通过以上的模块化指令集,能够选择不同的组合来满足不同的应用。例如,追求小面积、低功耗的嵌入式场景可以选择使用RV32EC 架构;而大型的64 位架构则可以选择RV64G
2 RISC-V寄存器
在RISC-V 架构中,寄存器组主要包括通用寄存器(General Purpose Registers )和控制状态寄存器( Control and Status Register, CSR)。
2.1 通用寄存器组
RISC-V架构通用寄存器设计规范包括:
- 基础整数指令集寄存器配置
a、标准配置(I扩展集):
RISC-V基础指令集架构默认配置32个整数寄存器组,编号为x0至x31。其中x0寄存器具有硬连线常数0特性(写入操作无效,读取始终返回0值),其余31个寄存器(x1-x31)为全功能通用寄存器。b、寄存器位宽定义:
架构通过XLEN参数声明寄存器物理位宽:
RV32I架构:XLEN=32,寄存器采用32位存储单元
RV64I架构:XLEN=64,寄存器扩展为64位存储空间
- 嵌入式场景优化配置
- 精简配置(E扩展集):
面向资源敏感型嵌入式场景,架构提供寄存器组精简方案:- 寄存器数量缩减至16个(x0-x15)
- x0寄存器仍保持零值特性
- 仅支持RV32E架构(强制限定XLEN=32)
- 浮点运算扩展配置
- 浮点寄存器组,当系统启用单精度(F扩展)或双精度(D扩展)浮点指令时:
- 新增独立浮点寄存器组(f0-f31)
- 32个浮点寄存器支持标量运算操作
- 寄存器位宽随浮点标准动态调整(F扩展对应32位,D扩展对应64位)
另外为提升代码可读性,汇编器支持寄存器功能别名映射。寄存器别名系统:
例如:x0 → zero(零值寄存器)x1 → ra(返回地址寄存器)x2 → sp(栈指针寄存器) 等,整体汇总如下:
register | ABI name | description | Saver |
---|---|---|---|
x0 | zero | Hard-wired zero, | 常数0 |
x1 | ra | Return address | caller |
x2 | sp | Stack pointer | callee |
x3 | gp | Global pointer | - |
x4 | tp | Thread pointer | - |
x5 | t0 | Temporary/alternate link register | caller |
x6-7 | t1-2 | Temporaries | caller |
x8 | s0/fp | Saved register/frame pointer | callee |
x9 | s1 | Saved register | callee |
x10-11 | a0-1 | Function arguments/return values | caller |
x12-17 | a2-7 | Function arguments | caller |
x18-27 | s2-11 | Saved registers | callee |
x28-31 | t3-6 | Temporaries | caller |
f0-7 | ft0-7 | FP temporaries | caller |
f8-9 | fs0-1 | FP saved temporaries | caller |
f10-11 | fa0-1 | FP arguments/return temporaries | caller |
f12-17 | fa2-7 | FP arguments temporaries | caller |
f18-27 | fs2-11 | FP saved temporaries | caller |
f28-31 | ft0-11 | FP temporaries | caller |
其中:
- ABI(Application Binary Interface)
- Caller :调用者
- Callee : 被调用函数【这里可以视为在 Caller (函数)中调用 Callee (函数)】
Caller 维护的寄存器,在运行被调函数前不会被保存,函数返回时这些寄存器可能会被改变,所以在调用前由 Caller 保存维护。Callee 维护的寄存器,在运行被调函数前会被保存,函数返回后这些寄存器与运行被调函数前相同。
2.2 CSR寄存器
RISC-V 的架构中定义了一些控制和状态寄存器( Control and Status Register, CSR )
基础特性:
- 专用地址空间:独立编址的12位地址域(0x000-0xFFF),通过csrrw/csrrs等专用指令访问
- 特权级关联:寄存器访问权限与特权模式(Machine/Supervisor/User)强关联,部分CSR需特定权限操作
- 功能范畴:系统配置、异常处理、性能监控、调试支持
主要寄存器分类:
机器模式核心CSR
- mstatus (0x300):全局状态控制(中断开关、特权模式栈)
- mtvec (0x305):异常处理入口基址寄存器
- mepc/mcause (0x341/0x342):异常返回地址与原因编码
- mip/mie (0x344/0x304):中断状态与使能位图
计时与计数单元
- mcycle/minstret (0xB00/0xB02):时钟周期与指令执行计数器
- mcountinhibit (0x320):性能计数器启停控制
调试支持单元
- dcsr/dpc (0x7B0/0x7B1):调试模式控制与断点PC存储
扩展功能关联
- 浮点扩展:fcsr (0x003) 聚合浮点状态
- 向量扩展:vcsr (0x008) 配置向量参数
- 用户级只读:cycle/time (0xC00系列)
访问控制机制:
- 权限隔离:用户模式仅可访问非特权CSR(如ustatus)
- 原子操作:提供csrrw(写后读)、csrrc(位清除)等原子指令
- 影子寄存器:部分CSR(如stvec)在不同特权级拥有独立副本
参考
- 指令集架构知识汇总
- riscv-spec-20240411.pdf
- 胡振波 手把手教你设计CPU
- 跟我学RISC-V】(一)认识RISC-V指令集并搭建实验环境