【RISC-V设计-02】- RISC-V指令集及其架构
在上一篇文章中,针对 RISC-V 指令集的起源和特点予以了简要阐述,并且还将其和其他指令集进行了对比。而在本篇文章里,将会针对 RISC-V 指令集及其架构展开全面且深入的探讨。本篇文章将依据 RISC-V 非特权文档(版本 20240411)的相关内容,对 RISC-V 指令集进行介绍。文档下载地址:unpriv-isa-asciidoc.pdf
1. 指令集分类
RISC-V 指令集具备显著的模块化特点。这一特性意味着我们能够依照自身的实际需求,首先选定一个基础指令集,而后再增添若干个扩展指令集进行灵活组合。通过这样巧妙的搭配方式,便能够成功获取我们期望得到的指令集架构。进而基于这样精心构建的指令架构,去设计出与我们的需求完美贴合的 CPU 。
指令名称 | 指令类型 | 说明 |
---|---|---|
RV32I | 基础指令 | 整数指令:包含算法、分支、逻辑、访存指令,有32个32位寄存器 |
RV64I | 基础指令 | 整数指令:包含算法、分支、逻辑、访存指令,有32个64位寄存器 |
RV128I | 基础指令 | 整数指令:包含算法、分支、逻辑、访存指令,有32个128位寄存器 |
RV32E | 基础指令 | 整数指令:与RV32I一样,但只使用前16个(0~15)32位寄存器 |
RV64E | 基础指令 | 整数指令:与RV64I一样,但只使用前16个(0~15)32位寄存器 |
M | 扩展指令 | 包含乘法、除法、取模求余指令 |
F | 扩展指令 | 单精度浮点指令 |
D | 扩展指令 | 双精度浮点指令 |
Q | 扩展指令 | 四倍精度浮点指令 |
A | 扩展指令 | 原子操作指令:比如比较并交换,读改写等指令 |
C | 扩展指令 | 压缩指令:单指令长度为16位,主要用于改善程序大小 |
P | 扩展指令 | 单指令多数据(Packed-SIMD)指令 |
B | 扩展指令 | 位操作指令 |
H | 扩展指令 | 支持(Hypervisor)管理指令 |
J | 扩展指令 | 支持动态翻译语言指令 |
L | 扩展指令 | 十进制浮点指令 |
N | 扩展指令 | 用户中断指令 |
V | 扩展指令 | 向量操作指令 |
G | 通用指令 | 包含I、M、A、F、D 指令 |
Zc* | 扩展指令 | 与代码大小减少相关的扩展,包括Zca 、Zcf 、Zcd 、Zcb 、Zcmp 、Zcmt 等 |
CMO | 扩展指令 | 基本缓存管理指令 |
Zifencei | 扩展指令 | 包括FENCE.I指令,用于指令和数据内存访问的同步 |
Zicsr | 扩展指令 | 控制和状态寄存器(CSR)指令,如CSRRW、CSRRS等 |
Zicntr | 扩展指令 | 基本计数器相关指令,如RDCYCLE、RDTIME等 |
Zihpm | 扩展指令 | 硬件性能计数器相关指令 |
Zihintntl | 扩展指令 | 非临时局部性提示(NTL)指令,如NTL.P1、NTL.PALL等 |
Zihintpause | 扩展指令 | 暂停(PAUSE)指令 |
Zimop | 扩展指令 | May-Be(MOP)指令 |
Zicond | 扩展指令 | 整数条件操作指令,如czero.eqz、czero.nez等 |
Zawrs | 扩展指令 | 等待预订集(WRS)指令,如WRS.NTO 、WRS.STO |
Zacas | 扩展指令 | 原子比较和交换(CAS)指令,如AMOCAS.W 、AMOCAS.D 等 |
Ztso | 扩展指令 | 总存储排序(TSO)相关指令 |
Zfh | 扩展指令 | 半精度浮点指令,如FLH 、FSH 、FADD.H 等 |
Zfhmin | 扩展指令 | 半精度浮点的最小支持指令 |
Zfa | 扩展指令 | 额外浮点指令,如FLI.S、FMINM.S等 |
Zfinx | 扩展指令 | 与浮点在整数寄存器相关的指令 |
Zdinx | 扩展指令 | 与浮点在整数寄存器相关的指令 |
Zhinx | 扩展指令 | 与浮点在整数寄存器相关的指令 |
Zhinxmin | 扩展指令 | 与浮点在整数寄存器相关的指令 |
2. 指令集格式
RISC-V指令集具有六种基本指令格式,所有指令长度均为32位,具体格式如下:
- R类型指令:用于寄存器-寄存器操作。其指令格式包含7位的 opcode(操作码)、7位的 funct7(功能码)、3位的 funct3(功能码)、两个5位的源寄存器 rs1和 rs2,以及一个5位的目的寄存器 rd。指令的操作由 opcode、funct7 以及 funct3 共同决定,是不包含立即数的所有整数计算指令,一般表示寄存器-寄存器操作的指令;
- I类型指令:用于短立即数和访存 load 操作。包含7位 opcode、3位 funct3、一个5位的源寄存器 rs1、一个5位的目的寄存器 rd,以及高12位的立即数 imm(在执行运算时需先将12位立即数扩展到32位)。指令的操作仅由 opcode 和 funct3 两者决定,相当于将 R 类型指令格式中的一个操作数改为立即数;
- S类型指令:用于访存 store 操作。指令功能由7位 opcode 和3位 funct3 决定,包含两个5位的源寄存器 rs1和 rs2,以及由指令中的 imm(31:25)和 imm(11:7)构成的一个12位的立即数(执行指令运算时需把12位立即数扩展到32位);
- B类型指令:用于条件跳转操作。指令操作由7位 opcode 和3位 funct3 决定,包含两个5位的源寄存器 rs1和 rs2,以及一个12位的立即数。该立即数的构成是指令的第32位是 imm(12)、第7位是 imm(11)、25到30是 imm(10:5)、8到11位是 imm(4:1),执行运算时同样需把12位立即数扩展到32位;
- U类型指令:用于长立即数操作。指令操作仅由7位 opcode 决定,包含一个5位的目的寄存器 rd 和高20位表示的20位立即数 imm;
- J类型指令:用于无条件跳转指令。指令操作由7位 opcode 决定,包含一个5位的目的寄存器 rd 和一个20位的立即数 imm,其 imm 的构成是指令的31位是 imm(20)、12到19位是 imm(19:12)、20位是 imm(11)、21到30位是 imm(10:1)。
所有位全部为0是非法的 rv32i 指令,因此试图跳转到被清零的内存区域的错误跳转将会立即触发异常,这可以协助调试;类似的所有位全部都是1的指令也是非法指令,它将捕获其他常见的错误。
RISC-V 指令格式具有简洁性和规整性的特点,这有助于简化指令解码的工作,提高处理器的性能。同时,指令中要读写的寄存器标识符位置固定,且立即数字段总是符号扩展,符号位在指令中的最高位,这意味着可能成为关键路径的立即数符号扩展可以在指令解码之前进行。
此外,还有一些特殊的指令格式,如:
-
压缩指令(C扩展):包括CR、CI、CSS、CIW、CL、CS、CA、CB、CJ等格式,具体格式可参考文章中关于C扩展的相关内容。
-
其他特定指令格式:如CMO指令中的cbo.clean、cbo.flush等指令,以及F、D、Q等浮点指令的特定格式。
这些指令格式的具体定义和使用取决于指令的功能和操作数的类型。
3. 寄存器定义
在RISC-V 的规范里面定义了32 个通用寄存器。其中31个是常规寄存器,1个恒为0值的x0寄存器。RV32E/RV64E:减少整数寄存器数量至16个,即x0 - x15,其中x0仍为零寄存器。
寄存器 | ABI 名称 | 说明 |
---|---|---|
x0 | zero | 0值寄存器,硬编码为0,写入数据忽略,读取数据为0 |
x1 | ra | 用于返回地址(return address) |
x2 | sp | 用于栈指针(stack pointer) |
x3 | gp | 用于通用指针 (global pointer) |
x4 | tp | 用于线程指针 (thread pointer) |
x5 | t0 | 用于存放临时数据或者备用链接寄存器 |
x6-x7 | t1-t2 | 用于存放临时数据寄存器 |
x8 | s0/fp | 需要保存的寄存器或者帧指针寄存器 |
x9 | s1 | 需要保存的寄存器 |
x10-x11 | a0-a1 | 函数传递参数寄存器或者函数返回值寄存器 |
x12-x17 | a2-a7 | 函数传递参数寄存器 |
x18-x27 | s2-s11 | 需要保存的寄存器 |
x28-x31 | t3-t6 | 用于存放临时数据寄存器 |
此外,如果支持浮点运算,将会有32个浮点寄存器,位宽跟随基本指令集的位宽。
-
F扩展
- 寄存器数量和宽度:添加32个浮点寄存器
f0 - f31
,每个32位宽。 - 功能:大多数浮点指令操作在这些寄存器上,软件使用转换指令(如
FLW
、FSW
等)在寄存器和内存之间传输浮点值。
- 寄存器数量和宽度:添加32个浮点寄存器
-
D扩展
- 寄存器变化:将
f0 - f31
寄存器扩展为64位宽。 - 功能:用于双精度浮点运算,增加了对64位浮点值的支持。
- 寄存器变化:将
-
Q扩展
- 寄存器支持:进一步扩展浮点寄存器以支持128位浮点操作。
- 功能:提供对128位四精度浮点的支持。
-
Zfh扩展
- 功能:用于16位半精度浮点操作,提供半精度浮点的加载、存储和计算指令。
4. 指令集总结
RISC-V指令集采用模块化的设计,具有高度的灵活性和可扩展性。能够满足不同应用场景的需求,例如在嵌入式系统中可以选择仅包含必要指令集的配置,以减小芯片面积和成本;在高性能计算中可以添加更多的扩展来提高计算能力。指令集的设计简洁明了,易于理解和实现,降低了硬件设计的复杂度。
总之,RISC-V的模块化指令集是其重要的特点之一,为芯片设计和软件开发提供了更大的灵活性和可扩展性,有助于推动计算技术的创新和发展。