设计RISC-V CPU,第1部分

2021-02-19 04:58:12

我没有数字逻辑设计经验。也就是说,我直到最近才决定要尝试设计自己的CPU并在FPGA上运行它!如果您也是对硬件设计有模糊兴趣的软件工程师,我希望这一系列关于我所学到的知识将是有益和有趣的。在第一部分中,我希望回答以下问题:

在以后的文章中,我将详细介绍我的CPU设计和RISC-V架构,并希望回答以下问题:

在撰写本文时,您可以在此处查看我的CPU的代码,或在此处查看最新版本。

数字逻辑设计是设计以二进制值运行的逻辑电路,基本组件是逻辑门:例如,一个AND门具有两个输入和一个输出。当两个输入均为1时,输出为1。

通常,我们设计使用触发器存储状态的同步电路,从而将电路的操作同步到一个公共时钟。触发器由逻辑门组成。

模拟电路设计与构成逻辑门的电子组件有关,例如晶体管和二极管。对于直接处理从模拟传感器派生的信号的应用(例如无线电接收机),通常需要这种抽象级别。在设计CPU时,这种抽象水平是不可行的:现代CPU可能具有数十亿个晶体管!

相反,我们使用的工具可以将我们的数字逻辑设计转换为不同的有用格式:FPGA的配置(请参见下文);模拟硅布局。

上面我们指出,无论是创建将要制成芯片的定制ASIC还是配置FPGA,都可以使用相同的数字逻辑设计工具。现场可编程门阵列是包含可编程逻辑块阵列的集成电路。您可以想象它是可以通过各种方式连接在一起的大量逻辑门。

制作定制芯片通常需要花费数百万美元的费用,当然,一旦您的芯片被制造出来,就无法更改。因此,通常在以下情况下使用FPGA:

由于缺乏资金,您无力创建自定义ASIC(例如,如果您只是像我这样的黑客,而不是ARM或Intel的黑客)

您无法负担得起创建定制ASIC的费用,因为您的体积太小而无法承受一次高昂的一次性成本(例如,如果您使用定制数据采集硬件制造少量MRI机器)

不利之处? FPGA的单芯片成本要高得多,并且由于能够以非常灵活的方式将逻辑模块连接在一起,因此它们通常要慢得多。相反,定制设计可以减少到最少的晶体管数量,而无需考虑灵活性。

我认为将自定义ASIC设计过程与FPGA设计过程进行比较是很有帮助的:

逻辑设计:就像我们对FPGA所做的那样,ASIC的逻辑设计是用硬件描述语言完成的。

验证:FPGA设计可能已经过验证,但是您可能希望ASIC设计的过程更加严格-毕竟,一旦制造,就不能更改设计!验证通常涉及正式验证设计的两个部分。

综合:这将创建一个网表:逻辑块及其连接的列表。这些连接称为网络,而这些块称为单元。对于FPGA和ASIC,这些单元都是特定于供应商的。

布局和布线(P& R):对于FPGA,这涉及将网表中描述的逻辑块映射到FPGA中的实际块。生成的二进制文件通常称为比特流。对于ASIC,这涉及确定将单元放置在硅片上的位置以及如何将它们连接起来。这两个应用程序通常为此使用自动优化工具。

您可能听说过Verilog或VHDL:两种流行的硬件描述语言(HDL)。我使用的是“热门”这里的意思是广泛使用,而不是广受喜爱。

我不会假装对这些工具了解很多:我只知道拥有丰富逻辑设计经验的比我聪明的人会讨厌他们。由于Verilog和其他类似工具的问题,人们进行了各种各样的尝试。做出更有用,更友好的选择。 nMigen就是这样的一个项目,它可以在Python中创建特定领域的语言。用他们自己的话说:

尽管比原理图输入要快,但由于多种原因,使用Verilog和VHDL进行硬件设计仍然很繁琐且效率低下。事件驱动模型引入了对于同步电路而言不必要的问题和手动编码,它们代表了当今逻辑设计的主要部分。违反直觉的算术规则会导致学习曲线更加陡峭,并为设计中的细微错误提供了肥沃的土壤。最后,通过&generate;语句对过程逻辑生成(元编程)的支持非常有限,并且限制了使代码通用,重用和组织的方式。

为了解决这些问题,我们开发了nMigen FHDL,该库用组合和同步语句的概念替换了事件驱动的范例,并具有使整数始终像数学整数一样起作用的算术规则,最重要的是允许设计逻辑由Python程序构建。最后一点使硬件设计人员可以利用Python语言的丰富功能-面向对象的编程,函数参数,生成器,运算符重载,库等,来构建组织良好,可重用且优雅的设计。

如果像我一样,您从未使用过Verilog,那么对您而言,并非所有这些都具有抽象的意义。但这听起来确实很有希望,而且我可以证明,开始进行逻辑设计非常简单,而没有据说为Verilog所困扰的巨大障碍。我会推荐它,特别是如果您已经熟悉Python!

我能想到的唯一缺点是nMigen仍在开发中,尤其是文档还不完善。 chat.freenode.net上的#nmigen有一个有用的社区。

nMigen提供了仿真工具:我在测试中使用pytest编写它。我在这些测试期间记录信号,并在waveviewer中查看它们以帮助调试。

您不需要FPGA开发板即可创建自己的CPU。您可以在仿真中做所有事情!对我来说,与一块板一起工作的乐趣是能够使LED闪烁并看到我的设计在运行。

当然,如果您要创建比我的基本CPU更有用的功能,那么您可能希望一些硬件在其上运行,这将是较少的可选操作!

我不是立即尝试设计CPU,而是从在nMigen中制作一个算术逻辑单元(ALU)开始。 ALU是我所见过的任何CPU设计的关键部分:它执行算术运算。

为什么从这个开始?我知道我的CPU需要一个ALU。我知道我可以做一个简单的。我知道在开始一个新项目时做某件事的感觉是一个重要的动机!

1"""算术逻辑单元""" 2导入枚举3 4导入nmigen作为nm 5 6 7类ALUOp(枚举.IntEnum):8""" ALU的操作""" 9 ADD = 0 10 SUB = 1 11 12 13 ALU级(nm.Elaboratable):14""" 15算术逻辑单元16 17 * op(输入):操作码18 * a(输入):第一个操作数19 * b(输入):第二个操作数20 21 * o(输出):输出22"& #34;" 23 24 def __init__(self,width):25""" 26初始化程序27 28 Args:29 width(int):数据宽度30""" 31 self .op = nm .Signal()32 self .a = nm .Signal(width)33 self .b = nm .Signal(width)34 self .o = nm .Signal(width)35 36 def(详尽,self _):37 m = nm .Module()38 39 with m .Switch(self .op):40 with m .Case(ALUOp .ADD):41 m .d .comb + = self .o .eq(self。 a + self .b)42和m .Case(ALUOp .SUB):43 m .d .comb + = self .o .eq(self .a-self .b)44返回m