
开发者用Bluespec SystemVerilog从零构建乱序RISC-V处理器
来源标题:Building an Order RISC-V CPU from scratch
一名工程专业学生从零开始构建了一款乱序执行的RV32I RISC-V处理器Specula。该项目使用Bluespec SystemVerilog编写,起因是他对大三下学期的课程感到无聊,转而研究真实世界的乱序处理器设计。作者自述当时目标定得过高,项目命名为Specula,为双发射乱序架构。
以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
一切始于我工程专业的第四学期(2025年初),当时我对学校开设的课程实在感到无聊。没有一门课让我感兴趣,于是我做了任何一个好奇的孩子都会做的事:去找点真正能让自己兴奋起来的东西。我一直深耕于处理器设计和FPGA的世界。我对基本的顺序处理器如何工作有不错的理解,也一直在琢磨冒险(hazard)是如何处理的。在其中一次这样的钻研中,我记得自己搜索了顺序处理器的真实案例,想看看我笔记本电脑里的CPU和我过去几个月一直在构建的东西到底有多大差别。
我发现我的Ryzen 9 CPU是一种叫做“乱序”(Out of Order)处理器的东西。太好了,又多了一个不专注于实际大学课程内容的理由。它看起来正是我想要接下来挑战的东西,主要因为两点:它的复杂性,以及我的笔记本电脑里竟然有比我预想中 sophisticated 得多的东西。我很确定我当时给Specula的仓库描述写的是类似“Specula is a dual-issue Out of Order RV32I processor in Bluespec SystemVerilog”……是啊,年轻的我确实太野心勃勃了。
这个描述保持了一段时间没变,而那时我正艰难地理解现代处理器工作原理中复杂而精妙的理论。我的学习方式是:读一些东西,然后尝试复现它,看看过程中哪里会出问题,因为那种时刻教给我的东西远比任何理论课都多。虽然大多数项目都是这样,但Specula在这个意义上确实是个异类,因为它和我之前自学阅读和理解过的东西都不一样,而且它是我决定尝试的第二个Bluespec项目……同时我还在学Bluespec。
致那些直到偶然读到这篇博客才第一次听说“乱序处理器”这个词的可爱读者们,请允许我提供一个速成课。与传统的顺序处理器不同,乱序处理器可以在指令完成时执行它们,前提是没有依赖关系(后面段落会详细讲)。它使用一堆复杂的硬件单元和算法来实现这一点。Specula最终成为一个32位、单发射(意味着处理器每个时钟周期最多发射一条指令)、乱序且推测执行(处理器在知道或确认这些指令是否真的需要之前就执行它们)的RISC-V处理器,完全用Bluespec SystemVerilog编写。这个设计从最初那个荒诞的野心演变了相当多,现在实现的核心是1-wide,使用寄存器重命名来消除假依赖,并用重排序缓冲区来确保完成的指令最终按正确的程序顺序更新架构状态。
现在这已经是一堆时髦术语了,让我们像拆棉花糖一样把它拆开。
Specula的高层微架构。为清晰起见,部分内部队列和控制路径已省略。
在很长一段时间里,目标就是让一个乱序处理器在Bluespec上跑起来。事实上,大约有4个月(2025年9月到2026年2月之间),Specula只是在积灰。在这段空白期里,我对基本现代处理器如何工作有了更好的理解,也探索了其他乱序RISC-V设计,以了解我实际上能把Specula推进到什么程度。最著名的可能是Berkeley的SonicBOOM,而令我惊讶的是,我居然找到了一个用Bluespec做乱序机器的项目。这帮人2017年就开始这个项目了,那时我才只有4英尺5英寸高。
大约在2026年3月,我回到了Specula,仍然只是想实现正常的乱序执行。在这个过程中,我遇到了xv6,看到其他项目都能启动Linux,这让我问自己:“为什么不试试在我的Specula上跑一个教学操作系统呢?”这意味着我现在必须为我的处理器扩展特权模式、CSR、陷入处理和Sv32虚拟内存,同时还要构建必要的系统组件,如UART、PLIC和VirtIO块设备。
我还想看看这个设计如何转化为实际硬件,所以我让它走了一遍针对Artix-7 FPGA的Vivado综合流程。所以没错,我再一次成功地把50个其他领域牵扯进了我的项目,把它搞复杂了。
但是嘿,这不就是学习的方式吗 :D
现代处理器执行数十亿条指令,但并非每条指令完成所需的时间都相同。整数加法可能比除法或内存访问完成得快得多。现在想象一下,一个处理器执行一串指令,其中一条正在等待来自内存的数据,但它后面的几条指令完全独立。传统的顺序处理器即使有有用的工作等着做,也可能最终停顿下来。
这就是乱序执行试图解决的问题之一。处理器不是强制指令严格按照它们在程序中出现的顺序执行,而是允许独立指令在它们的操作数和执行资源就绪时随时推进。
当然,这并不像随便打乱指令那么简单。有些指令确实依赖于前面指令的结果,另一些可能访问相同的寄存器或内存位置。所以我们确实需要一些机制来跟踪这些依赖关系,找出真正准备好执行的指令,并确保以不同顺序执行它们不会改变程序的可观察行为。(而且在这个过程中,也许不会掉一两根头发。)
这就是寄存器重命名、保留站和重排序缓冲区等概念发挥作用的地方。这些是使乱序处理器成为可能的机制,也是我们在探索Specula时会遇到的构建模块。
(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。