文章来源于漫谈嵌入式 ,作者Vinson
在谈到 RISC-V 之前,我们先梳理几个概念
1. 芯片
芯片 是所有半导体元器件的统称,它是把一定数量的常用电子元件(如电阻,电容,晶体管等),通过半导体工艺集成在一起,具有特定功能的威廉希尔官方网站
。
2. CPU
cpu 是芯片的一种,它里面包含了控制部件和运算部件,即中央处理器。1971 年, Intel 将运算器和控制器集成到一个芯片上,称为4004 微处理器,这标志着CPU 的诞生。
CPU 的工作流程分为以下5个阶段:
- 取指令
- 指令译码
- 执行指令
- 访存读取数据
- 结果写回
指令和数据统一存储在内存中,数据与指令需要从统一的存储空间存取,经由共同的总线传输,无法并行读取数据和指令。冯诺依曼结构
3. 冯诺依曼结构
冯·诺依曼结构也称普林斯顿结构,是一种将程序指令存储器和数据存储器合并在一起的存储器结构。
程序指令存储地址和数据存储地址指向同一个存储器的不同物理位置,因此程序指令和数据的宽度相同,如英特尔公司的8086中央处理器的程序指令和数据都是16位宽。
数学家冯·诺依曼提出了计算机制造的三个基本原则,即采用二进制逻辑、程序存储执行以及计算机由五个部分组成:
现代计算机发展所遵循的基本结构形式始终是冯·诺依曼机结构。这种结构特点是“ 程序存储,共享数据,顺序执行 ”,需要 CPU 从存储器取出指令和数据进行相应的计算
(1)单处理机结构,机器以运算器为中心;
(2)采用程序存储思想;
(3)指令和数据一样可以参与运算;
(4) 数据以二进制表示;
(5)将软件和硬件完全分离;
(6) 指令由操作码和操作数组成;
(7)指令顺序执行。
这套理论被称为冯·诺依曼体系结构。
4. 哈佛结构
哈佛结构是一种将程序指令存储和数据存储分开的存储器结构,如下图所示。中央处理器首先到程序指令存储器中读取程序指令内容,解码后得到数据地址,再到相应的数据存储器中读取数据,并进行下一步的操作(通常是执行)。
程序指令存储和数据存储分开,可以使指令和数据有不同的数据宽度,如Microchip公司的PIC16芯片的程序指令是14位宽度,而数据是8位宽度。
哈佛结构的微处理器通常具有较高的执行效率。其程序指令和数据指令分开组织和存储的,执行时可以预先读取下一条指令。
哈佛结构是指程序和数据空间独立的体系结构, 目的是为了减轻程序运行时的访存瓶颈。
哈佛结构能基本上解决取指和取数的冲突问题。
5. 混合式结构
- 使用两个独立的存储器模块,分别存储指令和数据,每个存储模块都不允许指令和数据并存;
- 具有一条独立的地址总线和一条独立的数据总线,利用公用地址总线访问两个存储模块(程序存储模块和数据存储模块),公用数据总线则被用来完成程序存储模块或数据存储模块与CPU之间的数据传输;
- 两条总线由程序存储器和数据存储器分时共用。
6. CISC
从前面的内容中,我们已经得知 CPU 就是不断的执行指令,来实现程序的执行,最后实现相应的功能。但是一颗CPU 能实现多少条指令,每条指令完成多少功能,却是值得细细考量的问题。
CISC的英文全称为“Complex InstrucTIon Set Computer”,即“复杂指令系统计算机”,从计算机诞生以来,人们一直沿用CISC指令集方式。早期的桌面软件是按CISC设计的,并一直沿续到现在。目前,桌面计算机流行的x86体系结构即使用CISC。
CISC 的优势在于,用少量的指令就能实现非常多的功能,程序自身大小也会下降,减少内存空间占用。
缺点:这些复杂指令集,包含的指令数量多且功能复杂,设计复杂。
7. RISC
RISC的英文全称为“Reduced InstrucTIon Set Computer”,即“精简指令集计算机”,是一种执行较少类型计算机指令的微处理器,起源于80年代的MIPS主机(即RISC机),RISC机中采用的微处理器统称RISC处理器。
这样一来,它能够以更快的速度执行操作(每秒执行更多百万条指令,即MIPS)。因为计算机执行每个指令类型都需要额外的晶体管和威廉希尔官方网站
元件,计算机指令集越大就会使微处理器更复杂,执行操作也会更慢。
RISC 设计方案非常简约,通常有20 多条简化的指令集。每条指令长度固定,由专用的加载和储存指令用于访问内存,减少了内存的寻址方式,大多数运算指令只能访问操作寄存器。
CPU 中配有大量的寄存器,这些指令的选取都是工程中使用频率最高的指令。由于指令长度一致,功能单一,操作依赖于寄存器,这些特性使得CPU 指令预取、分支预测、指令流水线等部件的效能大大发挥,几乎一个时钟周期能执行多条指令
RISC 的代表产品是 ARM 和 RISC-V。现在,两者已经没有明显的界限了,开始相互融合了
8. 流水线
谈到指令并行,就不得不谈到CPU 核心的流水线。现代处理器都是流水线结构。
流水线(Pipeline)技术是指程序在执行时候多条指令重叠进行操作的一种准并行处理实现技术。通俗的讲将一个时序过程,分解成若干个子过程,每个过程都能有效的与其他子过程同时执行。这种思想最初是在RISC的架构中出现的,旨在提高处理器处理效率,争取在一个时钟周期中完成一条指令。
一般常见的5级流水线有:
- 取指:指令取指(Instruction Fetch)是指将指令从存储器中读取出来的过程。
- 译码:指令译码(Instruction Decode)是指将存储器中取出的指令进行翻译的过程。经过译码之后得到指令需要的操作数寄存器索引,可以使用此索引从通用寄存器组(Register File)中将操作数读出。
- 执行:指令译码之后所需要进行的计算类型都已得知,并且已经从通用寄存器组中读取出了所需的操作数,那么接下来便进行指令执行(Instruction Execute)。指令执行是指对指令进行真正运算的过程。譬如,如果指令是一条加法运算指令,则对操作数进行加法操作;如果是减法运算指令,则进行减法操作。在“执行”阶段的最常见部件为算术逻辑部件运算器(Arithmetic Logical Unit,ALU),作为实施具体运算的硬件功能单元。
- 访存:存储器访问指令往往是指令集中最重要的指令类型之一,访存(Memory Access)是指存储器访问指令将数据从存储器中读出,或者写入存储器的过程。
- 写回:写回(Write-Back)是指将指令执行的结果写回通用寄存器组的过程。如果是普通运算指令,该结果值来自于“执行”阶段计算的结果;如果是存储器读指令,该结果来自于“访存”阶段从存储器中读取出来的数据。
无流水线:
有流水线:
它增加了四组寄存器,每一个流水线级数内部都有各自的组合逻辑数据通路,彼此之间没有复用资源,因此,其面积开销是比较大的,但是由于可以让不同的流水线级数同时做不同的事情,而达到流水的效果,提高了性能,优化了时序,增加了吞吐率。
9. RISC-V
在了解了 RISC 和 CISC 两种计算机指令设计架构后。我们来看看 RISC-V。
RISC-V 的 “V”, 有两层意思,一方面代表第5代 RISC;另一方面, “V”取Variation 之意代表变化。
9.1 RISC-V 是什么?
RISC-V 是一套开放许可证书、免费的、由基金维护的、一个整数运算指令集外加多个扩展指令集的CPU 结构规范(ISA)。
整数运算指令集 + 扩展指令集
任何硬件开发商或者组织都可以免费使用这套规范,构建CPU 芯片产品。
9.2 指令集命名方式
以RV 为2前缀,然后是位宽,最后代表是指令集的字母集合:
RV[###][abc......xyz]
符号 |
说明 |
---|
RV |
RISC-V 缩写 |
[###] |
用于标识处理器位宽,取值[32, 64,128],也就是处理器的寄存器位宽 |
[abc...xyz] |
标识该处理器支持的指令模块集合 |
比如:RV64IMAC, 表示64 位 RISC-V, 支持整数指令、乘除法指令、原子指令和压缩指令。
9.3 指令集模块
指令集模块是一款CPU架构的主要组成部分,是CPU 和 上层软件交互的核心,也是cpu主要功能体现。
RISC-V 规范只定义了CPU 需要包含的基础整型操作指令:
其他指令为可选指令或者用户扩展指令。比如:
- 乘
- 除
- 取模
- 单精度浮点
- 双精度浮点
- 压缩
- 原子指令
- 等。
扩展指令是芯片工程师根据需求自定义。
所以 RISC-V 采用的是模块化的指令集,易于扩展、组装。它适用于不同的应用场景,可以降低 CPU 实现成本。
9.4 RISC-V 寄存器
指令的操作数来源于寄存器,精简指令架构的CPU,都会提供大量的寄存器。
RISC-V 的规范定义了32个通用寄存器以及一个PC寄存器,这对于RV32I、RV64I、RV128I 指令集都是一样的,只是寄存器的位宽不一样。
如果要实现支持F/D扩展指令集的CPU,则需要额外支持32个浮点寄存器。而如果实现只支持RV32E指令集的嵌入式CPU,则可以将32个通用寄存器缩减为16个通用寄存器。
寄存器 |
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 |
用于存放临时数据寄存器 |
ABI: 应用程序二进制接口,可以理解为寄存器别名,高级语言在生成汇编会用到。
9.5 RSIC-V 特权级
不同的 指令集架构都有特权级的概念,RSIC-V 也不例外,我们来看看RISC-V 的特权级。
不同的特权级能访问的系统资源不同,高特权级的能访问低特权级的资源,反之却不行。
RISC-V 的规范文档定义了四个特权级别(privilege level),特权等级由高到低排列,如下表所示。
名称 |
级别 |
缩写 |
编码 |
---|
用户,应用程序特权级 |
0 |
U |
00 |
管理员特权级 |
1 |
S |
01 |
虚拟机监视特权级 |
2 |
H |
10 |
机器特权级 |
3 |
M |
11 |
一个RISC-V 硬件线程(hart),相当于一个CPU 内独立的可执行核心,在任意时刻,只能运行在某一个特权级上,这个特权级由CSR(控制和状态寄存器)指定配置。
具体分级如下:
- 机器特权级(M):RISC-V 中 hart 可以执行的最高权限模式。在M 模式下运行的 hart,对内存、I/O 和一些必要的底层功能(启动和系统配置)有着完全的控制权。它是唯一一个所有标准RISC-V CPU 都必须实现的权限级。
- 虚拟机监视特权级(H):为了支持虚拟机监视器而定义的特权级。
- 管理员特权级(S):主要用于支持现代操作系统,如Linux、FreeBSD和 windows 等
- 用户应用特权级(U):用于运行应用程序,同样也适用于嵌入式系统。
特权级的存在,是给指令加上了权力,从而去控制指令编写应用程序。应用程序只能干应用程序该干的事情,不能越权操作。操作系统则拥有更高的权力,能对系统资源进行管理。
10. 总结
本文梳理了 芯片、CPU、流水线,指令与架构等基础概念,引出了RISC-V 基础介绍,简单介绍了RISC-V 由来。后续针对risc-v 会根据自身学习情况做相应介绍。
参考文档:
riscv-privileged-20190608.pdf
riscv-spec-20191213.pdf
RISC-V-Reader-Chinese-v2p1.pdf