行业报告 AI展会 数据标注 标注供求
数据标注数据集
主页 > 机器学习 正文

RISC-V有何特别之处?

20 世纪 90 年代末,RISC 和 CISC 爆发了一场大战,自那以后,大家却说 RISC 和 CISC 的区别没那么重要了了。许多人表示,指令集也就那么回事,对 CPU 没什么太大的影响。但其实不然,指令集决定了我们可以轻松为微处理器做哪些优化。本文将介绍 RISC-V 处理器是如何设计指令集的,这样的设计具有什么好处。
 

 

20 世纪 90 年代末,RISC 和 CISC 爆发了一场大战,自那以后,大家却说 RISC 和 CISC 的区别没那么重要了了。许多人表示,指令集也就那么回事,对 CPU 没什么太大的影响。
 
但其实不然,指令集决定了我们可以轻松为微处理器做哪些优化。
 
我最近一直在了解有关 RISC-V 指令集架构 (ISA) 的更多信息,说起来,关于 RISC-V ISA 有几件事给我留下了非常深刻的印象:
它是一种 RISC 指令集,体积小,易于学习。不管是任何人,只要有兴趣学习微处理器,选它准没错。
请参考:RISC-V 备忘单(https://www.cl.cam.ac.uk/teaching/1617/ECAD+Arch/files/docs/RISCVGreenCardv8-20151013.pdf)。
 
它在大学数字化设计教学中占据重要地位:为什么大学要学 RISC-V(https://www.eejournal.com/article/why-universities-want-risc-v/)
 
经过巧妙地设计,它允许 CPU 设计生产者使用 RISC-V ISA 打造高性能微处理器。
 
无需授权费,且被设计成允许简单的硬件实现,按道理,专业爱好者可以在合理的时间内完成他自己的 RISC-V CPU 设计。
 
易于修改和使用的开源设计:The Berkely Out-of-Order (BOOM) RISC-V 处理器(https://boom-core.org/)
 
欲了解更多详情请点击:什么是 RISC-V 的创新之处?(https://medium.com/swlh/what-is-innovative-about-risc-v-a821036a1568)
 
RISC 的复仇
当我开始更深入地理解 RISC-V 时,意识到 RISC-V 是一种根本性的转变,它回到了许多人认为已经过时的计算时代。在设计方面,RISC- V 就像乘着时光机穿越回了上世纪八九十年代的经典 RISC 时代。
 
近年来,许多人指出 RISC 和 CISC 的区别不再重要,因为像 ARM 这样的 RISC CPU 已经添加了太多的指令,很多指令相当复杂,以至于它现在更像是一个混合的 RISC CPU,而不是纯粹的 RISC CPU。而那些 RISC CPU 也是如此,比如 PowerPC。
 
相比之下,RISC- V 是 RISC CPU 真正的硬核。事实上,如果你在网上看过大家就 RISC- V 的讨论,会发现有人声称 RISC-V 出自一些老学究式的 RISC 激进分子之手,他们拒绝与时俱进。
 
前 ARM 工程师 Erin Shepherd 几年前就 RISC-V 写过一篇评论,内容很有意思:
RISC-V ISA 过分追求极简主义。它非常强调最小化指令数、规范化编码这些事。这种对极简主义的追求导致了错误的正交性 (例如针对分支、调用和返回重用同一条指令) 和对冗余指令的需求,这在指令大小和数量这两个方面影响了代码密度。
 
我向大家简单介绍一下背景。让代码更小对性能有好处,因为这样就可以更容易将正在运行的代码保存在高速 CPU 缓存中。
 
本文在此批评的是,RISC-V 设计者太过于追求拥有小的指令集。尽管,这是 RISC 最初的目标之一。然而,这样做的弊端是,实际上程序在完成工作时将需要更多的指令,从而消耗更多的内存空间。多年来,人们普遍认为 RISC 处理器应该增加更多的指令,变得更像 CISC。其理论依据是,更专门化的指令可以替代对多个通用指令的使用。
 
压缩指令和宏融合
然而,在 CPU 设计中有两项特别的创新,这些创新从许多方面使添加更多复杂指令的策略变得多余:
·压缩指令——在内存中压缩指令,并在 CPU 的第一阶段进行解压。
·宏融合——将两个或两个以上由 CPU 读取的简单指令融合成一个复杂指令。
实际上 ARM 已经采用了这两种策略,而 x86 CPU 则采用了后者,所以这不能算是 RISC-V 的新招术。
 
然而,关键是 RISC-V 从这些策略中获得了更大的优势,这里面有两个重要原因:
它从一开始就添加了压缩指令。在 ARM 上使用的是 Thumb2 压缩指令格式,这就必须将其作为一个单独的 ISA 来添加以完成改造,这需要一个内部模式切换和单独的解码器来进行处理。RISC-V 压缩指令可以添加到具有 400 个额外逻辑门 (AND、OR、NOR、NAND 门) 的 CPU 上。
 
2.RISC 执着地控制独特指令的数量得到了回报,如此就有了更多的空间来容纳压缩指令。
 
指令编码
这一部分需要进行一些解释。指令在 RISC 体系结构上通常是 32 位(即比特)宽的。这些比特需要用来编码不同的信息。例如,下面这样一条指令:
ADD x1, x4, x8    # x1 ← x4 + x8
 
这条指令将累加寄存器 x4 和 x8 的内容,然后将结果存储在 x1 中。我们需要多少比特来编码,这取决于我们有多少寄存器。RISC-V 和 ARM64 有 32 个寄存器。可以用 5 比特表示数字 32:
2⁵ = 32
 
因为我们需要指定 3 个不同的寄存器,所以我们需要总共 15 比特 (3×5) 来编码操作数 (累加操作的输入)。
 
因此,我们想要在指令集中支持的东西越多,那么就会消耗掉那 32 比特中更多的比特。当然,我们可以使用 64 位指令,但是这会消耗太多的内存,从而降低性能。
 
通过刻意压低指令的数量,RISC-V 节省下更多的空间来添加表示我们正在使用的压缩指令的比特。如果 CPU 看到指令中的某些位被设置为 1,它就知道这条指令应该作为一条压缩指令来进行解释。
 
压缩指令——二到一
这表示,我们可以将两条 16 位宽的指令装入一个 32 位字,而不是一个 32 位字只装入一条指令。当然,并不是所有的 RISC-V 指令都可以用 16 位格式表示。因此,32 位指令的子集是根据它们的效用和使用频率来挑选的。未压缩指令可以接受 3 个操作数 (输入),而压缩指令只能接受 2 个操作数。因此,压缩后的 ADD 指令应该如下所示:(# 号后为注释)
C.ADD x4, x8     # x4 ← x4 + x8
 
RISC-V 汇编程序使用前缀 c. 来指示一条指令应该被汇编程序转换成一个压缩指令。但实际上你不需要去写它。RISC-V 汇编程序将能够在适当的时候选择是压缩指令还是非压缩指令。
 
基本上,压缩指令减少了操作数的数量。三个寄存器操作数将消耗 15 比特,而留给我们指定操作的就只剩下 1 比特了!因此,将操作数减少到两个,我们就能剩下 6 比特来指定操作码 (要执行的操作)。
 
这实际上接近于 x86 汇编的工作方式,在 x86 汇编中没有足够的比特来保留 3 个寄存器操作数。取而代之的是,x86 使用一些比特来允许像 ADD 这样的指令从内存和寄存器中读取输入。
 
宏融合——一到二
但是,当我们将指令压缩与宏融合结合起来看时,才能发现真正的收益。你看,如果 CPU 得到一个包含有两个 16 比特的压缩指令的 32 比特的字,它可以把这些合并成一条单一的复杂指令。
 
这听起来很荒谬,我们不是又回到原点了吗? 我们是不是又回到 CISC 风格的 CPU,这不正是我们试图要避免的吗?
 
不是的,因为我们避免用大量复杂的指令、x86 和 ARM 策略填充 ISA 规范。相反,我们基本上是通过各种简单指令的组合来间接地表达一整套复杂指令。
 
在正常情况下,宏融合存在一个问题:虽然两条指令可以被一条指令替换,但它们仍然会消耗两倍的内存空间。但是使用指令压缩,我们不会消耗更多的空间。我们做到了两全其美。
 
让我们来看看艾琳·谢泼德的一个例子。在她批评 RISC-V ISA 时,展示了一个简单的 C 函数。为了解释起来更清楚一些,我把它重新写了下来,内容如下:
int get_index(int *array, int i) { 
     return array[i];
 }
 
在 x86 上编译成:
mov eax, [rdi+rsi*4]
ret
 
当你在编程语言中调用函数时,参数通常会根据既定的约定传递给寄存器中的函数,这将取决于你所使用的指令集。在 x86 上,第一个参数放在寄存器 rdi 中,第二个放在 rsi 中。按照惯例,返回值必须放在寄存器 eax 中。
 
第一条指令将 rsi 的内容乘以 4。它包含了变量 i。为什么乘?因为数组是由整数元素组成的,所以它们之间的间距为 4 个字节。因此,数组中的第三个元素的字节偏移量实际上是 3×4 = 12。
 
然后,我们把它添加到 rdi,它包含数组的基址。于是,我们得到了数组第 i 个元素的最终地址。我们读取该地址的存储单元的内容,并将其存储在 eax 中:大功告成。
 
在 ARM 上与之很相似:
LDR r0, [r0, r1, lsl #2]
BX  lr ; return
 
这里我们不是乘以 4,而是将寄存器 r1 向左平移 2 位,这就相当于乘以 4。这也可能是更本真地表示了 x86 代码中所发生的情况。在 x86 上,你只能乘以 2、4、8,所有这些其实都可以通过左移 1、2、3 位来实现。
 
我想,x86 描述中的剩余内容你肯定都能猜得到了。现在让我们进入 RISC-V,真正有趣的内容开始喽!(# 号后为注释)
SLLI a1, a1, 2     # a1 ← a1 << 2
ADD  a0, a0, a1    # a0 ← a0 + a1
LW   a0, a0, 0     # a0 ← [a0 + 0]
 
RET
RISC-V 上的寄存器 a0 和 a1 只是 x10 和 x11 的别名。它们是放置函数调用的第一个和第二个参数的地方。RET 是一条伪指令 (简写):
JALR x0, 0(ra)     # sp ← 0 + ra
                   # x0 ← sp + 4  ignoring result
 
JALR 跳转到 ra 引用返回地址的地址。ra 是 x1 的别名。
不管怎样看,这似乎都很糟糕,对吧?对于像在表中执行基于索引的查找并返回结果这样简单而常见的操作,需要两倍的指令。
 
看上去确实很糟糕。这就是为什么艾琳·谢泼德强烈批评了 RISC-V 的设计选择。她写道:
RISC-V 的简化使解码器 (即 CPU 前端) 更简单,但代价是执行更多的指令。然而,真正棘手的问题是扩展流水线的宽度,而稍稍不规则甚至很不规则的指令其解码都不会有太大的问题,主要难点是确定指令的长度,尤其是 x86,因为它有很多前缀。
 
然而,多亏了有指令压缩和宏融合,我们可以扳回这一程。
C.SLLI a1, 2      # a1 ← a1 << 2
C.ADD  a0, a1     # a0 ← a0 + a1
C.LW   a0, a0, 0  # a0 ← [a0 + 0]
C.JR   ra
 
现在,这和 ARM 的例子中所占用的内存空间是完全相同的。
 
好吧,接下来让我们做一些 宏融合!
 
在 RISC-V 中允许将多个操作融合为一个的规则之一是,目标寄存器得是相同的。ADD 和 LW(加载字) 指令就属于这种情况。因此,中央处理器将把这些转换成一条指令。
 
如果 SLLI 也是这样的话,我们就可以把这三条指令融合成一条了。因此,CPU 会看到一些类似于更复杂的 ARM 指令的东西:
LDR r0, [r0, r1, lsl #2]
 
为什么不能在代码中直接编写此宏操作?
因为我们的 ISA 不包含对它的支持!记住,可用的比特数是有限的。为什么不把说明写长一点呢?不行,那样会消耗太多的内存,并且会更快填满宝贵的 CPU 缓存。
 
然而,如果我们在 CPU 内部制造这些半复杂的长指令,也没有什么可担心的。CPU 在任何时候所面对的指令最多也不过几百条。所以在每条指令上浪费个 128 比特不是什么大问题。每个人都有足够的硅。
 
因此,当解码器得到一条正常指令时,它通常会把它转换成一个或多个“微”操作。这些“微”操作是 CPU 实际要处理的指令。它们可以非常地“宽广”,包含很多额外的有用信息。称之为“微”似乎有些讽刺,因为它们其实很“广”。然而事实上“微”指的是它们做的任务数量有限。
 
指令的复杂性
宏融合将解码器的工作做了一点改变:不再是将一条指令转换成多个微操作,而是将多个操作转换成一个微操作。
 
因此,在现代 CPU 中发生的事情看起来相当奇怪:
首先,它通过压缩将两条指令合并为一条指令。
然后借助解压把它分成两部分。
通过宏融合将它们合并到一个操作中。
 
其他指令反而可能最终会被分割成多个微操作,而不是融合在一起。为什么有些会融合,有些会分割?这种混乱是成体系的吗?
 
关键是微操作最终的复杂程度要适当:
不能太复杂,否则无法在为每条指令分配的数量固定的时钟周期内完成。
 
不能太简单,因为那纯粹就是浪费 CPU 资源。执行两个微操作的时间是执行一个微操作的时间的两倍。
 
这一切都始于 CISC 处理器。英特尔开始把复杂的 CISC 指令分解成微操作,这样它们就能像 RISC 指令一样更容易适应流水线。然而,在后来的设计中,他们意识到许多 CISC 指令是如此简单,它们可以很容易就融合成一条中等复杂的指令。你执行的指令越少,完成得自然也就越快。
 
好处
好了,以上解释了很多细节,也许你很难一下子弄清楚重点是什么。为什么要进行压缩和融合?听起来有很多额外的工作要做。
 
首先,指令压缩和 zip 压缩完全不同。“压缩”这个词其实有点用词不当,因为立即解压一条已压缩的指令非常简单。做这件事并不浪费时间。记住,对于 RISC-V 来说这很简单。只需 400 个逻辑门,就可以完成解压。
 
宏融合也是如此。虽然这看起来很复杂,但这些方法已经在现代微处理器中得到了应用。因此,这种复杂性的学费早就已经交过了。
 
然而,与 ARM、MIPS 和 x86 设计者不同的是,RISC-V 设计者在开始设计 ISA 时就了解指令压缩和宏融合。或者更准确地说,当他们最初的 ISA 被设计出来的时候,那些竞争对手们并不知道这一点。当设计 64 位版本的 x86 和 ARM 指令集时,他们可能已经考虑到了这一点。那么 ,为什么他们没有这样做呢,我们只能揣测。可能是这些公司制作新的 ISA 时,不喜欢过多地偏离早期版本吧。通常它更着重于消除以往明显的错误,而不是颠覆之前的理论基础。
 
通过对第一个最小指令集展开各种测试(https://arxiv.org/pdf/1607.02318.pdf),RISC-V 的设计者有了两个重要的发现:
通常 RISC-V 程序占用的内存空间接近或少于任何其他 CPU 体系结构,包括 x86,鉴于 x86 是 CISC ISA,所以被公认是最节省空间的。
 
它需要执行的微操作数比其他 ISA 更少。
 
本质上,他们由于在设计基础指令集时就考虑了融合,所以能够融合足够多的指令,使得针对任何给定程序,CPU 所必须执行的微操作比竞争对手更少。
 
这使得 RISC-V 团队加倍重视宏融合,将其作为 RISC-V 的核心战略。你可以在 RISC-V 手册中看到很多关于什么操作可以被融合的说明。你将看到对哪些指令进行了修订,以便更容易地融合那些常见模式中的指令。
 
使 ISA 保持较小意味着学生更容易学习。也就是说,对于一个学习 CPU 架构的学生来说,实际构建一个运行 RISC-V 指令的 CPU 会更容易。
 
RISC-V 有一个每个人都必须实现的小核心指令集。而所有其他指令都作为扩展部分存在。压缩指令只是一个可选的扩展。因此,如果是简单的设计,可以省略它。
 
宏融合只是一种优化。它不会改变整体行为,因此在特定的 RISC-V 处理器中不需要实现它。
 
相比之下,对于 ARM 和 x86 来说,很多复杂性都不是可选的。必须实现整个指令集和所有复杂的指令,即使你只是想要创建一个最小的最简单的 CPU 内核。
 
RISC-V 设计策略
RISC-V 利用了我们当今对现代 CPU 的了解,并用这些知识指导了他们在设计时的选择。例如,我们知道:
如今,CPU 内核会提前做分支预测。它们的预测正确率超过 90%。
CPU 内核是超标量体系结构的,这意味着它们在并行执行多条指令。
使用无序执行做到超标量体系结构。
它们是流水线式的。
 
这意味着不再需要像 ARM 所支持的条件执行等之类的事情。在 ARM 上支持它会消耗掉指令格式中的一些字节。RISC-V 可以节省这些比特。
 
条件执行的最初目的是避免分支,因为它们不利于流水线。CPU 要想快速运行,通常会预取下一条指令,这样在前一条指令完成第一阶段后,它就可以快速地选取下一条指令。
 
但是使用条件转移,当你开始填充流水线时,你不知道下一条指令将在哪里。然而,超标量 CPU 可以简单地并行执行两个分支。
 
这也是 RISV-C 没有状态寄存器的原因。因为这会导致指令之间的依赖性。每条指令越独立,就越容易与另一条指令并行运行。
 
RISC-V 策略基本上是,我们如何使 ISA 尽可能简单,使 RISC-V CPU 的最小实现尽可能简单,而无需做出影响 CPU 性能的设计决策。
 
欲了解更多内容请阅读:Avoiding ISA Bloat with Macro-Op Fusion for RISC-V
 
业界有什么说法?
好吧,从理论上这听起来可能很好,但在现实世界中也果真如此吗?科技公司对此有什么看法?他们是否认为 RISC-V ISA 比商业 ISA(如 ARM) 提供了实实在在的好处?
 
《电子工程杂志》是一本很不错的刊物,很多人都喜欢在它上面阅读这方面的内容。该刊物采访了戴夫·迪策尔,一名微处理器的高级专家。他的公司评估了制造专用硬件以加速的不同选择。吉姆·特尔写道(https://www.eejournal.com/article/another-risc-v-religious-conversion/):
 
RISC-V 甚至不在备选的采购清单上,但是随着 Esperanto 的工程师们对它越来越多的研究,他们渐渐意识到它不仅仅是一个玩具或者是一个教学工具。“我们认为 RISC-V(相对于 Arm 或 MIPS 或 SPARC) 可能会损失 30% 到 40% 的编译效率,因为它太简单了。”Ditzel 说。“但我们的编译器专业人员对它进行了基准测试,难以置信的是只有 1% 左右。”
 
Esperanto Technologies 现在只是一家小公司。像英伟达这样拥有大量经验丰富的芯片设计师和资源的大公司呢?英伟达在他们的板卡上使用了一种叫做“猎鹰”的通用处理器。在评估备选方案时,RISC-V 名列前茅(https://riscv.org/wp-content/uploads/2017/05/Tue1345pm-NVIDIA-Sijstermans.pdf)。
 
英文原文:
https://erik-engheim.medium.com/the-genius-of-risc-v-microprocessors-b19d735abaa6
 
译者简介:冬雨,小小技术宅一枚,从事研发过程改进及质量改进方面的工作,关注编程、软件工程、敏捷、DevOps、云计算等领域,非常乐意将国外新鲜的 IT 资讯和深度技术文章翻译分享给大家,已翻译出版《深入敏捷测试》、《持续交付实战》。
 
声明:文章收集于网络,版权归原作者所有,为传播信息而发,如有侵权,请联系小编删除,谢谢!
 
 

微信公众号

声明:本站部分作品是由网友自主投稿和发布、编辑整理上传,对此类作品本站仅提供交流平台,转载的目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,不为其版权负责。如果您发现网站上有侵犯您的知识产权的作品,请与我们取得联系,我们会及时修改或删除。

网友评论:

发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
SEM推广服务

Copyright©2005-2028 Sykv.com 可思数据 版权所有    京ICP备14056871号

关于我们   免责声明   广告合作   版权声明   联系我们   原创投稿   网站地图  

可思数据 数据标注

扫码入群
扫码关注

微信公众号

返回顶部