RISC-V

<image>

RISC-V（英语发音为“risk-five”）是一个基于精简指令集（RISC）原则的开源指令集架构（ISA），简易解释为与开源软件运动相对应的一种“开源硬件”。该项目于2010年在加州大学柏克莱分校启动，但许多贡献者是该大学以外的志愿者和行业工作者。

与大多数指令集相比，RISC-V指令集可以自由地用于任何目的，允许任何人设计、制造和销售RISC-V芯片和软件而不必支付给任何公司专利费。虽然这不是第一个开源指令集，但它具有重要意义，因为其设计使其适用于现代计算设备（如仓库规模云计算机、高端移动电话和微小嵌入式系统）。设计者考虑到了这些用途中的性能与功率效率。该指令集还具有众多支持的软件，这解决了新指令集通常的弱点。

RISC-V指令集的设计考虑了小型、快速、低功耗的现实情况来实做，但并没有对特定的微架构做过度的设计。

截至2021年12月，RISC-V工作小组已经批准了版本 20191213 的非特权指令集（Unprivileged ISA，曾经称为用户级指令集 User-Level ISA），以及版本 20211203 的特权指令集（Privileged ISA）。

## 意义

RISC-V的作者们旨在提供数种可以在BSD许可证之下自由使用的CPU设计。该许可证允许像是RISC-V芯片设计等衍生作品可以像RISC-V本身一样是公开且自由发行，也可以是闭源或者是专有财产。

相比而言，ARM控股和MIPS科技等商业芯片供应商会对使用其专利者收取高额的许可费用。他们也要求在接收其描述设计优点的文件和指令集前，还需要签署保密协议。许多设计优点为完全专有，从来不会披露给客户。这种保密制度阻碍了公共教育用途和安全审核，以及开发公共、低成本的自由及开放源代码软件编译器和操作系统。

处理器设计需要多种专业的设计知识，包括电子逻辑、编译器和操作系统，这种资源很难在专业工程团队之外见到。所以现代且高质量的通用计算机指令集近年来除了学术环境以外并没有在任何地方被广泛使用，甚至没有被阐述。正因如此，许多RISC-V贡献者将此视为整个社群付出的成果，而这也是RISC-V有很多工程上的应用的一项原因。

RISC-V的作者们还有大量研究和使用者经验来验证他们在硅片和仿真中的设计。RISC-V指令集是从一系列的学术计算机设计项目直接发展而来的。它一开始的目的有一部分是为了帮助这些项目。

## 历史

### 前身

RISC的历史可追溯到1980年左右。在此之前，人们觉得简单的计算机可能会有用，但是没有很多人去阐述其设计原则。这种简单而有效的计算机一直都是学术界的兴趣。

学术界的学者们为了出版第一版的《计算机体系结构：量化研究方法》（Computer Architecture: A Quantitative Approach）ISBN 978-1558600690，所以于1990年订立了RISC指令集DLX。大卫·帕特森（David Patterson）是其中一位作者，后来协助RISC-V的开发。但是DLX只用于教育用途，学术界和业余爱好者使用FPGA来实做它，但并没有取得商业运用。

版本2及更早版本的ARM CPU具有公共域指令集，并且仍有GCC的支持。该指令集有三个开源内核，但从未被制造。

OpenRISC是一款基于DLX的开源指令集，并且具有相关的RISC设计。OpenRISC 完全支持GCC并且有实做在Linux上，但是它很少有商业上的实做。

### RISC-V基金会及RISC-V国际协会

加州柏克莱分校的Krste Asanović教授发现开放源代码的电脑系统有很多用途。在2010年他决定用三个月的时间来开发并发表一个开放源代码的电脑系统。这个计划是用来帮助包括学术以及工业的使用者。柏克莱分校的大卫·帕特森教授也参加了这个计划。帕特森也是原来伯克利分校RISC的设计者，RISC-V只是他众多RISC CPU研究计划的一个．RISC-V计划早期一些经费来自DARPA。

有参与支援RISC-V基金会的公司以及机构包括了超微半导体、晶心科技、英国航太系统、加州大学伯克利分校、Bluespec、Cortus、Google、GreenWaves Technology、慧与科技、华为、IBM、Imperas Software、中国科学院、北京清华大学、印度理工学院、莱迪思半导体、迈伦科技、美高森美、美光科技、辉达、恩智浦半导体、甲骨文公司、高通、Rambus、西部数据、SiFive、阿里巴巴集团、红帽公司、成为资本。

2019年6月，图灵奖得主、RISC-V基金会创始人之一大卫·帕特森（David Patterson）在瑞士宣布，将依托清华—伯克利深圳学院（TBSI），在内部建设RISC-V国际开源实验室（RISC-V International Open Source Laboratory），又称大卫帕特森RIOS图灵实验室。清华大学称实验室将瞄准世界CPU产业战略发展新方向和粤港澳大湾区产业创新需求，聚焦于开源指令集CPU研究，建设以深圳为根节点的RISC-V全球创新网络和以技术成果转移为主要使命的非营利组织，全面提升RISC-V生态系至最先进可商用水平。预判届时将面对国际大厂法律层面发起挑战问题上，伯克利加州大学和清华大学的法学院将与之建立联系。

2020年3月，RISC-V基金会为规避美国对中国的贸易限制而将总部搬迁至瑞士，并更名为RISC-V国际协会（RISC-V International），以非盈利商业协会的身份在瑞士注册。

### 奖项

- 2017： The Linley Group's Analyst's Choice Award for Best Technology（对其指令集）

<image>

## 激励要求

RISC设计者们认为指令集因为位于硬件和软件之间，所以是电脑主要的沟通桥梁，因此如果有一个设计良好的指令集是开源而且可以被任何人使用的，就可以让更多的资源能够重复利用，而大大的减少软件的成本。而这样的指令集也会增加硬件供应商市场的竞争力，因为硬件供应商们可以挪用更多资源来进行设计，减少处理软件支援的事务。

设计者声称在指令集设计领域里，新的设计准则渐渐变得罕见，而近四十年中，大多数成功的设计变得越来越相似。至于那些失败的指令集，大多数是因为他们的赞助商赚不了钱，而不是因为其指令集在技术上有多差。所以，一个在成熟的设计准则之下开发且设计良好的开源指令集想必能吸引许多供应商长期的支援。

许多先前的开源指令集架构使用GNU通用公共授权条款来鼓励使用者们允许他们的实作方法被其他人复制或是使用。

设计者们表示，RISC-V指令集是给实际上的电脑使用的，它不像其他学术上的指令集设计，只有为了比较好阐述理念而做最佳化。而RISC-V指令集有一些功能是可以增加电脑速度又可以减少成本和电源使用。这些特色包含，Load/store架构，在CPU里面的位元表示方法来简化数据多工器（MUX），以标准为基础来简化的浮点数，架构中立的设计和把最高有效位（Most significant bit，MSB）放到固定位置来加速符号扩充（Sign extension）。而sign extension常常就是静态时序分析里面的关键路径（Critical timing path）。

RISC-V 指令集是设计来给各式各样的用途使用的，而它支援三个不同的字组大小，分别是32位元、64位元、128位元以及与这三种字组大小有关的各式各样的指令子集。而这些指令子集的定义会按照那三个字组大小来做些微的改动。透过这些指令子集的向量处理器与资料中心等级的机柜式平行电脑/平行运算来帮助嵌入式系统、个人电脑和超级电脑。

该指令集采取不固定的编码长度而且还可以再扩充，因此在未来，还可以一直加入更多位元的编码方式。该指令集有特别留空间给128位元的延伸版本，因为60年的产业界经验显示在指令集设计领域里，最无法复原的错误就是缺少内存定址空间。截至2016年，128位元的指令集仍然刻意地维持在“未冻结 (软件工程)”的状态，这是因为到现在为止，人们很少有实际上操作这么大内存的系统的经验。

然而，RISC-V也可以拿来做学术上的使用。它拥有简化的整数指令子集允许学生拿来做基本的练习，而整数指令子集就是一个简单的指令集架构（ISA）让软件可以控制研究上的机器。而不定长度的指令集架构也允许扩充功能来满足研究或是学生练习上的需求。分割出来的特权指令集可以支援在不重新设计编译器的情况下，进行操作系统方面的研究。RISC-V的开放的知识产权允许相关的设计被发布、使用和修改。

## 软件

一个新的CPU指令集通常的问题是缺少CPU的硬件设计跟软件的支援。在RISC-V的网站有一个user mode指令集的规格，还有一个用来支援操作系统模式的优先指令集的初步规格。

市面上已经有好几个使用RISC-V开源架构的CPU设计可以供参考，包括64-bit Berkeley Out of Order Machine（BOOM）、64-bit Rocket、柏克莱设计的五个32-bit Sodor CPU、Clifford Wolf 的 picorv32、Syntacore 的 scr1、苏黎世联邦理工学院／波隆纳大学的 PULPino （Riscy and Zero-Riscy），以及很多其他的设计。使用三层指令分段的 Sodor CPU 是一个适合嵌入式设计的小型CPU。Rocket可能适用在小型低功耗的个人电脑或其他个人装置。BOOM 使用了大部分Rocket的架构，但是功能更加强大，适合个人电脑、服务器或超级电脑。picorv 跟 scr1 都是使用Verilog 设计的 32位元 MCU 等级的 RV32IMC。PULPino的核心使用了一个适合微控制器的简单的 RV32IMC ISA架构(Zero-Riscy)，以及另外一个更强大的DSP版本 RV32IMFC ISA 可以支援一些嵌入式信号处理的特别 DSP 指令集。

设计软件包括了一个设计编译器 Chisel (硬件描述语言)，它可把设计编译成Verilog代码。网站上还有测试用的参考资料可以用来验证设计的正确性。

RISC-V目前提供的软件有 GNU Compiler Collection （GCC） toolchain（具有侦错器 GDB）、一套 LLVM toolchain、OVPsim模拟器（以及RISC-V快速处理器模式的软件参考库）、Spike 模拟器，以及一套在QEMU上运行的模拟器。

操作系统的支援包括 Linux 核心、FreeBSD，以及 NetBSD，但是监督模式的指令直到版本 1.11 的特权指令集才被标准化，所以这方面的支援还不是正式的。有一个早期的 RISC-V 的FreeBSD 操作系统已经在2016年2月上传到开放源代码社群，而且包含在 FreeBSD 11.0。Debian跟Fedora的版本也有人在移植，并且在逐渐稳定中。已经有人做了一个 Das U-Boot 的移植版本。UEFI Spec v2.7 定义了RISC-V UFEI 的规格，而且慧与科技公司的工程师已经做好一个 TianoCore 的移植版本，并且将会上传到开放源代码社群。已经有人做好了一个 L4 microkernel family 的移植。还有一个在网页上用JavaScript写的 RISC-V Linux 系统模拟器。

## 设计

### 指令子集

RISC-V 指令使用模块化设计，包括几个可以互相替换的基本指令集，以及额外可以选择的扩充指令集。所有基本跟扩充的指令集都是由科技产业、研究机构跟学术界合作开发的。基本指令集规范了指令跟他们的编码、控制流程、暂存器数目（以及它们的长度）、内存跟定址方式、逻辑（整数）运算以及其他。只要有软件以及一个通用的编译器的支援，只用基本指令集就可以制作一个简单的通用型的电脑。

标准的扩充指令集可以搭配所有的基本指令集以及其他扩充指令集，而不会发生冲突。

很多 RISC-V 电脑可能使用精简扩充指令集来降低电力消耗、程式的大小以及内存的使用。未来也有计划支援hypervisor和虚拟化。

只要再加上一个监督指令集 (S) 的扩充，以及以下 RVGC 指令集，就有足够的指令可以支援一个 Unix-style 操作系统。

指令集名称｜描述｜版本｜状态

基本指令集

RVWMO｜RISC-V 弱内存模型｜2.0｜已批准

RV32I｜基本整数指令集, 32位元｜2.1｜已批准

RV32E｜基本整数指令集(嵌入式系统), 32位元, 16 个暂存器｜2.0｜已批准

RV64I｜基本整数指令集, 64位元｜2.1｜已批准

RV64E｜基本整数指令集(嵌入式系统), 64位元, 16 个暂存器｜2.0｜已批准

RV128I｜基本整数指令集, 128位元｜1.7｜开放

标准扩充指令集

M｜整数乘除法标准扩充｜2.0｜已批准

A｜不可中断指令(Atomic)标准扩充｜2.1｜已批准

F｜单精度浮点标准扩充｜2.2｜已批准

D｜双精度浮点标准扩充｜2.2｜已批准

Zicsr｜控制与状态暂存器｜2.0｜已批准

Zifencei｜指令抓取屏障｜2.0｜已批准

G｜所有以上的扩充指令集以及基本指令集的总和的简称｜不适用｜不适用

Q｜四精度浮点标准扩充｜2.2｜已批准

L｜十进制浮点标准扩充｜0.0｜开放

C｜压缩指令标准扩充｜2.0｜已批准

B｜位元运算标准扩充｜1.0｜已批准

J｜动态指令翻译标准扩充｜0.0｜开放

T｜顺序内存存取标准扩充｜0.0｜开放

P｜单指令多资料流（SIMD）运算标准扩充｜0.9.10｜开放

V｜向量运算标准扩充｜1.0｜开放

Zk｜标量加密标准扩充｜1.0.1｜已批准

H｜Hypervisor 标准扩充｜1.0｜已批准

S｜Supervisor 标准扩充｜1.12｜已批准

Zam｜非对齐不可中断指令标准扩充｜0.1｜开放

Zihintpause｜暂停提示｜2.0｜已批准

Zihintntl｜非时间局部性提示｜0.3｜已批准

Zfa｜额外浮点运算指令标准扩充｜1.0｜已批准

Zfh｜半精度浮点标准扩充｜1.0｜已批准

Zfhmin｜半精度浮点最小集标准扩充｜1.0｜已批准

Zfinx｜整数寄存器单精度浮点标准扩充｜1.0｜已批准

Zdinx｜整数寄存器双精度浮点标准扩充｜1.0｜已批准

Zhinx｜整数寄存器半精度浮点标准扩充｜1.0｜已批准

Zhinxmin｜整数寄存器半精度浮点最小集标准扩充｜1.0｜已批准

Zmmul｜整数纯乘法标准扩充｜1.0｜已批准

Ztso｜全存储排序标准扩充｜1.0｜冻结

为了分辨各种不同的指令组合，非特权指令集标准中订定了一些专有名词。首先先指明基本指令集的种类，包括表示 RISC-V 的代号 RV，然后是暂存器的宽度跟其他变化，例如 RV64I 或 RV32E。然后用上表的字母（以及表列的顺序）表示用了哪种扩充指令，例如 RV64IMAFD。

基本指令集、扩充整数或浮点运算、多CPU系统使用的同步指令扩充，标准扩充指令MAFD被认为是大部分的一般运算都需要的，所以有一个字母的简称 G 用来表示 IMAFDZicsr_Zifencei。

使用嵌入式系统的一个小的32位元电脑可能用 RV32EC，而大型的64位元电脑可以用 RV64GC，即 RV64IMAFDCZicsr_Zifencei 的简称。

随着扩充指令集数量的增加，指令集标准提供了另外一种命名方式，用 Z 字首紧接着字母名称表示标准扩充，例如 Zifencei 表示指令抓取屏障扩充。

### 寄存器集

RISC-V 有 32 个整数暂存器（在嵌入式版本则是 16 个）。当浮点延伸集被实作的时候，还有 32 个浮点暂存器。除了“内存存取指令”之外，一般指令“只能”定址暂存器而无法存取内存。

如同有些 RISC 指令集（MIPS, SPARC, DEC Alpha），其中一个暂存器为“零暂存器”（zero register），剩下的暂存器为通用暂存器。在 RISC-V 当中，第一个整数暂存器是零暂存器，储存数值到零暂存器是没有作用的，而读取零暂存器的数值将始终得到 0。使用零暂存器可以让指令集设计更简单。比方说，把“暂存器 X 复制到暂存器 Y” (MOV Y, X)，可以使用“将暂存器 X 与 0 相加后，复制到暂存器 Y” (ADD Y, X, r0) 实作。

RISC-V 有提供“控制暂存器”及“状态暂存器”，但是 user-mode 程式只能存取用来“量测效能”及“浮点管理”的部分。

RISC-V 并没有指令可以储存和回复（save and restore。注：通常用于 context-switch，中断处理，或是函数呼叫）多个暂存器。这些设计在 RISC-V 当中，被认为是不必要的，过于复杂的，可能过慢的设计。

### 内存存取

就像许多的 RISC 一样，RISC-V 属于载入-储存架构，只有 load 与 store 指令可以存取内存。

Load 和 Store 指令可以直接使用程式码中的常数、在堆叠中的本地变数、或是资料结构中的内容。定址的方式是使用基底暂存器与 12-bit 的 signed 相对地址 (± 2KB)。如果基底暂存器是 0，则资料或是常数可以在低位址，或是高位址（负的相对地址，导致绕回到高的内存地址。比方说 ROM 的内存地址）。

内存的定址单位是 8-bit 的 byte，以 little-endian 存放在内存。Load 与 Store 支援的资料长度从 8-bit 到电脑的 word 大小。内存存取并不需要对齐到 word 的大小，不过如果有对齐的话，可以增加效能。这项功能可以减小程式码大小，而且透过软件的模拟，还可以简化硬件的设计（会触发一个“对齐失败”的中断）。

和其他类似成功的电脑一样，RISC-V 也是 little-endian。这稍稍降低了复杂度与成本，因为所有大小的 word 的读取都遵循一样的顺序。举例来说，RISC-V 的指令集都是从最低位址的 byte 开始解码。RISC-V 的规格书保留了实作 big-endian 的可能性。

如同许多的 RISC 指令集一样，RISC-V 并没有可以“写入多个暂存器”的定址模式。比方说：不支援 auto-incrementing（像是 *ptr++ 就无法使用一个指令完成，而必须拆解成“一个 load 指令”及“一个 ADDI 指令”。）

RISC-V 管理 CPU 与 thread 之间的共用内存的方式是确保在单一的 thread 当中，内存存取指令的执行顺序永远是遵照原本的编译顺序。不过在不同的 thread 以及在 I/O 装置之间，RISC-V 不保证存取的顺序──除非有像 FENCE 这样的指令出现。

FENCE 保证在其之前的执行结果，一定会被其后的 thread 或 I/O 装置看到。FENCE 有 8-bit 可以分别指定 memory read/write 与 I/O read/write 的各种组合顺序。透过这些组合，FENCE 可以保证内存与 memory-mapped I/O 之间的执行顺序。比方说：其中一个组合是可以在不影响 I/O 运算的情况下，只保证内存的读取和写入顺序。也就是说，如果 I/O 运算可以和内存同时执行的话，FENCE 不会强迫他们之间要互相等待。单一 CPU 上执行单一 thread 的情况下，可以把 FENCE 视作 NOP 指令。

有些 RISC CPUs（例如：MIPS、PowerPC、DLX、Berkeley's RISC-I）在 Load/Save 指令当中使用 16-bit 位移。使用 load upper word 指令来设定最高的 16-bit。这让最高的 16-bit 资料可以很容易被设定，而不需要位移指令。然而，大部分使用 load upper word 的时机都是为了要载入一个常数（比如：地址）。RISC-V 则是使用类似 SPARC 12-bit 与 20-bit 的设计，而 RISC-V 所采用的 12-bit 设计可以让指令更小。也就是说，这使得 32-bit 的 load/store 指令，就算需要在 32 个暂存器（需要 5-bit 定址）当中选两个来用（一共 10-bit），还是有足够的 bit 数目来支援 RISC-V 的可变长度指令编码 (variable-length instruction coding)。

注：请参考 32-bit 的 I-type 指令格式，就会发现这个 12-bit 位移比 16-bit 来得优异的地方。这使得 32-bit 的空间当中，扣掉 12-bit 的常数值，以及最低的两个 bit 为 11（表示这是一个 32-bit 长的指令），再扣掉两个 5-bit 的暂存器位址，还有将近 8-bit 的空间可以留给 opcode 及 func3。如果是使用 16-bit immediate 的话，会使得空间不够放下两个 5-bit 的暂存器位址。举例来说，SLLI Rd, Rs, immediate (Shift Left Logical Immediate) 将会被迫拆解成两个指令来完成：LDR Ri, immediate; SLLI Rd, Rs, Ri。

### 立即数

RISC-V 读取 32-bit 常数与位址是透过设定 upper 20-bit 的指令达到的。LUI 指令（Load Upper Immediate）把（指令中的）20-bit 读取到暂存器的 31~12 bits 当中。

另一个 AUIPC 指令，也是一样读取 upper 20-bit，同时又加上 PC（Program Counter）之后，存放到某个基底暂存器。这个指令让地址无关代码能够支援“相对于程式码位置的 32-bit 地址”。

这个基底暂存器可以再搭配 12-bit 位移，使用在 Load 与 Store 指令当中。如果需要的话，也可以使用 ADDI 指令，将 lower 12-bit 的常数加到一个暂存器中（注：这样就完成一个完整的 32-bit 常数读取）。在 64-bit 架构下，LUI 与 AUIPC 执行的结果会被位元扩充至 64-bit。

有些高速的 CPU 会把一些指令“融合”成一个指令。比如说：上述的 LUI 与 AUIPC 就很适合和 Load/Save 指令一起融合。

### 函数呼叫、跳跃和分支

RISC-V 的函数呼叫 JAL（Jump and Link）把回传地址放入一个暂存器。由于相较于其他把回传地址存入堆叠的设计，它省下了一次对堆叠内存的存取，所以在许多的处理器设计中是比较快速的。

JAL 有一个 20-bit signed 位移。这个位移会被乘上 2 之后，加到 PC 当中，以产生指向 32 位元指令的相对位址。如果该位址没有对齐到 32-bit 位址（即不可被 4 整除），CPU 会触发一个例外。

RISC-V 的 JALR（Jump and Link Register）指令与 JAL 相似，但是 JALR 是把一个 12-bit 的相对位移和某一个暂存器相加，而 JAL 是用 20-bit 的相对位移与 PC 相加。

JALR 的指令格式与使用暂存器的 load/store 指令相似。搭配另一个设定高位 20-bit 的基底暂存器，可以组成一个 32-bit 的地址（可以是绝对位址，例如 LUI；或是相对于 PC 的位址，例如 AUIPC）。（使用零暂存器当基底暂存器，则可以跳到 0 ± 2KB 的绝对位址）

透过使用零暂存器，两种无条件跳跃：“20-bit PC 相对位址”以及“暂存器为底的 12-bit”，分别使用 JAL 与 JALR 两个指令来实作。在这个情况下，因为目的地暂存器是零存器，所以回传位址会被丢弃。

如同许多的 RISC 系统，在一个函数呼叫当中，RISC-V 编译器必须使用多个指令将暂存器一个一个地存到堆叠当中，然后在函数结束的时候，一个一个地将暂存器自堆叠中还原。RISC-V 没有“储存多个”或是“还原多个”暂存器的指令，因为这些指令被认为会让 CPU 变得过于复杂，而且可能更慢。然而 RISC-V 的这种设计会增加程式大小，而设计者原本的规划是透过呼叫子程序来减少程式大小。

RISC-V 没有条件码暂存器。设计者相信条件码暂存器会让高速 CPU 的设计更加复杂，因为它强迫了不同执行阶段的指令之间进行交互。这样的设计会使得高精度计算变得更复杂，有些数值计算需要更多的能量。

相反地，RISC-V 透过比较两个暂存器来实现分支，指令包括：相等、不相等、小于、无号数小于、大于、无号数大于。十种“比较分支”运算，可以透过反转算子顺序的方式，只用上述六种指令实作出来。举例来说：“如果大于时跳跃”可以用算子顺序相反的“如果小于或等于时跳跃”来实作。

这六种比较分支指令具有 12-bit 的有号位移，可以跳到 PC±4KB 的范围内。

RISC-V 要求 CPU 实作“预设分支预测”（default branch prediction）。如果是往回跳跃 (例如：中的 expr 判断式），CPU 要预测跳跃会发生，也就是预测 expr “会”成立。如果是向前跳跃（例如：} 中的 else 部分），CPU 预测这个跳跃会发生，也就是预测 expr “不会”成立。CPU 判断往回或向前的方法，是看指令中相对位址的最高位元，也就是有号数（signed bit）的部分：如果是 1，表示是负数，要往回跳跃；如果是 0，表示是正数，要向前跳跃。当然，复杂的 CPU 实作也可以加入更多的分支预测。

RISC-V 手册也建议软件（如：编译器）利用预设分支预测的特性，来避免分支造成 pipeline 被停滞。方法就是利用上一段提到的 signed bit 来“暗示” CPU 这个分支会不会发生。所以，就是算是简单又便宜的 CPU，也可以透过编译器来优化效能。如果有需要，编译器也可以透过统计等方式来优化效能。

所以，为了避免不必要的分支预测电路（以及不必要的 pipeline 停滞），无条件跳跃不要用“比较分支”来实作。

RISC-V 并不支援“条件执行”指令（conditional execution，注：当某个条件成立的时候，才执行该指令）。设计者宣称没有这种设计的 CPU 比较容易设计，而且编译器在进行优化的时候，也比较不容易假设错误。设计者宣称高速又不照顺序执行的 CPU 反正都会同时执行正反两种结果，之后再丢弃其中一个。他们也宣称，即使在简单的 CPU 当中，条件执行其实是比较没有价值的，不如跳跃预测来的有用。不使用条件执行的程式码会比较大，但是他们宣称压缩指令集在大部分的情况下，可以解决这样的问题。

许多的 RISC 设计都有“分支延迟槽”（branch delay slot），用来充份使用跳跃指令的下一个内存位址，这可以略略增加整体的 CPU 效能。RISC-V 并不支援这个功能，因为他会让多时序、超纯量，以及 long pipeline 变得很复杂。而动态分支预测其实已经做得很好，可以不需要这个功能了。

### 算术和逻辑集

RISC-V 把数学运算指令归类到一个很小的 I 子集当中，包括：加法、减法、位移、位元运算，及比较分支。这些可以使用软件的方式去模拟其他大部分的 RISC-V 指令（atomic 运算是值得一提的例外）。RISC-V 目前没有“数开头有几个零”以及一些用来加速软件浮点运算的位元运算。

整数乘法子集（M 子集）包括：有号数与无号数的乘法与除法。

浮点子集（F 子集）包括单精度运算，以及类似于整数的“比较分支”。它需要额外的 32 个浮点暂存器，这些暂存器是与整数暂存器分开的。双精度浮点子集（D 子集）一般假设浮点暂存器是 64 位元，而且会与 F 子集一起协作。RISC-V 亦有定义四精度 128-bit 浮点子集（Q 子集）。没有支援硬件浮点指令的 RISC-V CPU，依旧可以使用软件的浮点程式库。

RISC-V 在遇到运算错误的时候，并不会抛出异常，包括：overflow、underflow、subnormal 及 divide by zero。相反的，整数运算和浮点运算都会产生合理的预设数值，而且浮点运算指令还会设定状态位元。Divide-by-zero 可以透过在除法运算之后放置分支指令来发现。这些状态位元可以也可以被操作系统或是定期的中断检查到。

### 原子内存操作

RISC-V 支援计算机在多个 CPU 与线程之间共享内存。RISC-V 的标准内存同步模式是“释放一致”原则。也就是说，读取和写入顺序可以被重排，但是有些读取可以被设定成“获取”（acquire）运算，必须在其后的存取之前被执行；有些写入可以被当作“释放”（release）运算，必须在其之前的存取的后面执行。

基本指令集包含了以FENCE指令提供的最小支援，来保证内存存取顺序。尽管这已经足够了（FENCE R, RW 提供“获取”，FENCE RW, W 提供“释放”），使用组合操作指令可以更有效率。

原子操作子集（A 子集）支援两种类型的原子内存操作，以实现释放一致性。首先，它提供了通用的 load-reserved 及 store-conditional 指令。执行加载，并尝试为其执行绪保留该地址。仅当该保留未被来自另一个来源的干预性写入破坏时，才会执行对保留地址的 store-conditional。如果写入成功，则将零放入目标暂存器中；如果失败，则以非零值表示软件需要重试操作。在任何一种情况下，保留都会被释放。

第二组原子指令 AMO（Atomic Memory Operation）执行 Read-modify-write 操作：读取（可选为读取-获取）到目标暂存器，然后执行读出值和来源暂存器值之间的操作，然后写入（可选为写入-释放）结果。将内存屏障设计为可选的，允许了多个操作的组合。每个 AMO 的操作码中都有“获取”及“释放”位元，用于启用可选的内存屏障。

## RISC-V处理器

### 商业实现

#### 阿里巴巴玄铁910

<image>

阿里巴巴旗下半导体公司平头哥发布了它的首款 RISC-V 处理器“玄铁 910”（XuanTie910），名字取自金庸小说《神雕侠侣》。阿里巴巴称它是目前性能最强的 RISC-V 处理器，支持16核，主频 2.5GHz，单核性能达到 7.1 Coremark/MHz。阿里巴巴称其性能突破源自两大创新：一是它采用3发射8执行的复杂乱序执行架构，是业界首个实现每周期 2 条内存访问的 RISC-V 处理器；二是它基于 RISC-V 扩展了 50 余条指令，系统性增强了 RISC-V 的计算、存储和多核等方面能力。

2021年平头哥半导体释出玄铁C910处理器开源项目，同时还发布出C910的LLVM编译器源代码。

#### SiFive公司的RISC-V半导体IP核系列

RISC-V创始人所创办的SiFive公司提供一系列RISC-V半导体IP核，包含高性能、高效能、低功耗及嵌入式RISC-V处理器。

#### 晶心科技的RISC-V CPU IP系列

晶心提供可配置性高的32/64位元高效能CPU核心，包含DSP、FPU、Vector、超纯量 (Superscalar)、乱序执行 (Out-of-Order)及多核心系列。

### 开源实现

#### 中国科学院“香山”

中国科学院计算所在2020年释出“香山”高性能RISC-V处理器开源项目，香山以Chisel (硬件描述语言)硬件描述语言(Scala领域特定语言)开发。第一版“雁栖湖架构”使用台积电的28nm制程，工作频率为1.3GHz。

#### 西部数据“SweRV”

西部数据在2018年释出SweRV RISC-V处理器开源项目，SweRV 目标应用环境为储存装置控制器，从开源以来已有多家厂商采用。

## 参见

- 精简指令集 (RISC)
- OpenRISC，以GNU General Public License授权
- OVPsim，RISC-V处理器指令子集、内核和系统的指令精确模拟器。免费为非商业用途提供。
- ARM架构
- 开源运算硬件列表

## 拓展阅读

- The RISC-V Instruction Set Manual
- Instruction Sets Should Be Free: The Case For RISC-V Whitepaper by Krste Asanović and David A. Patterson
- The RISC-V Instruction Set HotChips 25 (2013)
- The RISC-V Software Ecosystem HPCA 2015, Tutorial
- Rocket Chip HPCA 2015, Tutorial
- The RISC-V Compressed Instruction Set Manual Version 1.9 (draft)

## 外部链接

- Pulpino: A developed, open-source system-on-chip based on RISC-V, 4 August 2016

## 基本资料

- 设计师：加州大学柏克莱分校
- 字长/暂存器资料宽度：32、64、128
- 始创时间：2010年
- 版本：非特权指令集：20191213、特权指令集：20211203
- 形式：RISC
- 类型：载入-储存架构
- 编码：不定长度
- 分支预测结构：比较和分支
- 字节序：小端序
- 扩展名：M、A、F、D、Q、C、P
- 启用：是
- 通用暂存器：16、32（包括一个始终为零的寄存器）
- 浮点寄存器：32（可选；宽度取决于选用的扩展指令集，可为32、64、128位元）