硬件描述语言(Verilog,VHDL等)的最佳做法是什么?


71

实施HDL代码时应遵循哪些最佳实践?

与更常见的软件开发领域相比,有什么共同点和区别?

Answers:


50

关于该主题的最佳书籍是“重用方法论手册”。它涵盖了VHDL和Verilog。

特别是一些在软件中不完全匹配的问题:

  • 无闩锁
  • 小心重置
  • 检查您的内部和外部时间
  • 仅使用可综合代码
  • 注册所有模块的输出
  • 阻止与非阻止分配要小心
  • 注意组合逻辑的敏感列表(或在Verilog中使用@(*))

一些相同的包括

  • 使用CM
  • 有代码审查
  • 测试(模拟)您的代码
  • 适当时重用代码
  • 制定最新时间表
  • 有规格或用例或敏捷客户

63

有点旧的线程,但想放入我的$ 0.02。这并不是真正针对Verilog / VHDL的。更多关于一般硬件设计的信息……特别是针对定制ASIC的可综合设计。

这是我根据多年行业(相对于学术)在设计上的经验得出的意见。它们没有特定的顺序

我的总括声明是为执行验证而设计。在硬件设计中,验证至关重要。在实际的硅片中发现错误时,错误会贵很多。您不能只是重新编译。因此,前硅被给予了更多的关注。

  • 了解控制路径和数据路径之间的区别。这使您可以创建更加优雅和可维护的代码。还允许您保存门控并最小化X传播。例如,数据路径永远不需要可重置的触发器,控制路径应该始终需要它。

  • 在验证之前证明功能。通过正式方法或通过波形。我将解释2这样有很多优点。首先,它将节省您因洋葱剥皮而浪费的时间。与许多应用程序级设计(尤其是在学习中)和大多数课程工作不同,代码更改的周转时间非常长(从10分钟到几天不等,具体取决于复杂性)。每次更改代码时,都需要进行详细的说明,皮棉检查,编译,波形生成,最后是实际的仿真……这本身可能要花费数小时。其次,您很难遇到困难的情况。注意这是针对硅前验证的。这些肯定会在后硅片上遭受打击,使您损失很多资金。相信我,验证功能的前期成本极大地降低了风险,值得付出努力。有时很难说服最近的大学毕业生。

  • 有“鸡丁”。小鸡位是通过驱动程序设置为禁用硅功能的MMIO中的位。旨在还原置信度不高(置信度与验证工作成正比)的更改。在预硅中几乎不可能达到所有可能的状态。除非经过后硅验证,否则无法真正满足您对设计的信心。即使只有1种状态在发生错误的时间中被击中0.000005%的时间,它也会在后硅阶段(但不一定在前硅阶段)命中。

  • 不惜一切代价避免在控制路径中出现异常。您拥有的每个新异常都会使验证工作加倍。这个很难解释。可以说有一个DMA块,它将数据保存到另一个块将要使用的内存中。可以说保存下来的数据结构取决于完成的某些功能。如果您决定设计成不同功能之间保存的数据结构不同,那么只需将验证工作乘以DMA功能的数量即可。如果遵循此规则,则保存的数据结构将是可对内容位置进行硬编码的每个功能可用的所有数据的超集。一旦DMA保存逻辑针对1个功能进行了验证,就对所有功能进行了验证。

  • 最小化接口(读取最小化控制路径)。这与最小化异常有关。首先,每个新接口都需要验证。这包括测试台中的新检查器/跟踪器,断言,覆盖点和总线功能模型。其次,它可以成倍地增加您的验证工作!假设您有1个用于读取缓存中数据的接口。现在说(由于某种奇怪的原因),您决定要另一个接口来读取主存储器。您只需四倍的验证工作。现在,您需要在任何给定的时间n验证这些组合:

    • 不读取缓存,不读取内存
    • 不读取缓存,读取内存
    • 缓存读取,无内存读取
    • 缓存读取,内存读取
  • 了解并传达假设。缺少这是阻止通信问题的主要原因。您可能已经对一个完美的模块进行了完全验证。.但是,如果不理解所有假设,则您的模块在连接时会失败。

  • 最小化潜在状态。设计的状态(意想不到的或意想不到的)越少,验证所需的工作就越少。将类似的功能分组为1个顶级函数(如定序器和仲裁器)是一个好习惯。很难识别和定义此高级功能,使其包含尽可能多的较小功能,但是这样做会极大地消除状态,进而消除潜在的错误。

  • 始终发出强烈的信号离开您的障碍物。在大多数情况下,失败都是解决方案。您不知道端点块将如何处理它。您可能会遇到时间安排问题,这些问题可能直接影响您的完美实施。

  • 除非性能受到负面影响,否则应避免使用粉状FSM。单纯的FSM更有可能在摩尔之上产生时序问题

  • ..最后是我最不喜欢的一个:“如果没有破裂,就不要修复”。由于涉及的风险和错误的高昂代价,很多时候,黑客入侵是解决问题的更实用的解决方案。其他人则通过提及对现有组件的利用来避免这种情况。

至于与更传统的软件设计进行比较:

  • 离散事件驱动的编程是完全不同的范例。人们看到了Verilog语法,并认为“哦,就像C一样……”……但是,这离事实还远。尽管语法相似,但必须有所不同。例如,传统的调试器在可综合的RTL上几乎毫无意义(Testbench设计不同)。纸上的波形是可用的最佳工具。但是,可以这么说,FSM设计有时可以模仿过程编程。具有软件背景的人倾向于对FSM疯狂(我知道我一开始就是这么做的)。

  • 系统Verilog具有很多(很多)测试台特定的功能。它完全是面向对象的。就测试平台设计而言,它与传统软件设计非常相似。但是,它确实具有与时间相关的1个维度。必须考虑比赛条件和协议延迟

  • 至于验证,它也不同(相同)。主要有3种方法:

    • 正式传播验证(FPV):您可以通过逻辑证明它将始终有效
    • 定向随机测试。根据种子定义随机设置的延迟,输入值和功能启用。 有向是指种子在没有信心的路径上加重。此方法使用覆盖点指示健康
    • 重点测试。这类似于传统的软件测试

...为了完整性,我还需要讨论最佳的测试平台设计实践...但这是另一天

抱歉,长度不够。我在“区域”中:)


1
有趣的是,许多建议归结为充分考虑了硬件设计中涉及的验证工作。我不会不同意您的任何观点,但不禁会想知道,业界将通过充分改进验证实践来“解除阻碍” RTL设计流程而从中受益。想象一下,如果验证工作不是限制因素,那将是可能的!
Chiggs 2014年

1
我一直发现Mealy样式的FSM易于设计,并且可以选择节省时钟周期。如果它们成为关键路径的一部分,则始终可以注册其输出以模仿更多时序。
AxelOmega

26

HDL像Verilog和VHDL似乎确实鼓励使用意大利面条式代码。大多数模块由多个“总是”(Verilog)或“过程”(VHDL)块组成,这些块可以任意顺序排列。模块的整体算法或功能通常被完全遮盖。弄清楚代码的工作方式(如果您未编写代码)是一个痛苦的过程。

几年前,我遇到了这篇论文,概述了用于VHDL设计的更结构化的方法。基本思想是每个模块只有2个处理块。一种用于组合代码,另一种用于同步(寄存器)。这对于生成可读且可维护的代码非常有用。


绝对是这样做的方法。
erikkallen 2010年

1
这些专用指南可能会干扰旨在识别某些编码样式的综合工具。最好让设计规范来指定编码安排。

4
如果综合工具“旨在识别某些编码样式”而不是“旨在识别特定语言”,那么我想说该工具是有缺陷的,而不是编码。我认为我已经遇到了Adam12提到的一些问题。例如,在Synplicity中,它将所有VHDL记录重新制作为巨型阵列。SignalX.NamedElementY被转换为RegisterX [RandomNumber]。这可能到现在已经解决,但几年前就是这种情况。令人遗憾的是,在处理HDL设计时,胡扯的工具似乎已成为现实。
bengineerd 2011年

4
有趣的是,我还想指出“两个过程”文件。这是我从未发现的有关VHDL风格的唯一有意义的文章。当然,其他答案中的所有建议也都很好,但是:“两个过程”文件显示了一种实际获取代码的方法,该方法要好得多(更灵活,更不易出错,等等),您应该看看。顺便说一句:这是演示文稿,而不是纯文章:(gaisler.com/doc/structdes.pdf
Ingo Blackman

6
  • 在HDL中,代码的某些部分可以同时工作,例如两行代码“可以同时工作”,这是一个明智地使用的优点。这是习惯于逐行使用语言的程序员起初可能很难理解的东西:

    • 可以创建满足您需求的冗长和特定的管道。
    • 您可以使大模块同时工作。
    • 您可以创建多个单元并并行执行工作,而不是用一个单元对不同数据重复执行操作。
  • 应特别注意引导过程-芯片正常工作后,您将获得巨大成功。

在硬件上进行调试通常比调试软件要困难得多,因此:

  • 首选简单代码,在代码运行后,有时还有其他方法可以加快代码速度,例如使用更高速度的芯片等。

  • 避免组件之间的“智能”协议。

  • HDL中的工作代码比其他软件更宝贵,因为硬件是如此难以调试,如此重用,并且还考虑使用模块的“库”,其中一些是免费的,而另一些则出售。

  • 设计不仅应考虑HDL代码中的错误,还应考虑正在编程的芯片上以及与该芯片接口的其他硬件设备上的故障,因此,人们应该真正考虑一种易于检查的设计。

一些调试技巧:

  • 如果一个设计包含多个构建块,则可能要创建从这些块之间的接口到芯片外部测试点的线。

  • 您将需要在设计中保存足够的行,以转移有趣的数据以供外部设备检查。您也可以使用这行代码,并将代码作为告诉您当前执行状态的一种方式-例如,如果您在某点接收数据,则向这些行写入一些值,在执行的稍后阶段,您写入另一个值,等等”

    如果您的芯片是可重配置的,这将变得更加方便,因为您可以定制特定的测试,并在进行时对每个测试的输出进行重新编程(这对于leds来说非常好)。)

编辑:

通过智能协议,我的意思是,如果您的两个物理单元连接,则它们应该与可用的最简单的通信协议进行通信。也就是说,在它们之间不要使用任何复杂的自制协议。

原因是这样的-由于拥有模拟器,在FPGA / ASIC内部“查找”错误非常容易。因此,如果您确定数据随心所欲,并且在程序发送时就消失了,那么您已经达到了硬件乌托邦-能够在软件级别工作:)(使用模拟器)。但是,如果您的数据没有得到您想要的方式,那么您就必须弄清楚原因……您必须连接线路,这并不是那么容易。

在线路上查找错误非常困难,因为您必须使用专用设备连接线路,并记录线路在不同时间的状态,并且必须确保线路按照协议进行操作。

如果您需要连接两个物理单元,则使“协议”尽可能简单,直到不被称为协议为止:)例如,如果这些单元共享一个时钟,则在它们之间添加x条数据线,例如,使一个单元写入它们,而另一个单元读取,因此,例如,在每个时钟下降时,传递一个在它们之间具有x位的“字”。如果您有FPGA,则原始时钟速率对于并行数据而言是否太快-您可以根据实验控制其速度,例如,使数据停留在至少“ t”个时钟周期等行上。我认为并行数据传输比较简单,因为您可以以较低的时钟速率工作并获得相同的性能,而无需在一个单元上拆分字眼,而在另一个单元上重新组装。(希望每个单元在“时钟”之间没有延迟)。甚至这可能太复杂了:)

关于SPI,I2C等,我还没有实现,我可以说我已经连接了两个运行在同一时钟下的FPGA的支路(不记得中间电阻的确切形成)。更高的速率,所以我真的想不出使用这些速率作为在您自己的FPGA之间传递数据的主要方式的好理由,除非FPGA之间的距离很远,这是使用串行而不是串行的原因比并行总线

一些FPGA公司使用JTAG对其产品进行测试/编程,但不确定是否将其用作高速传输数据的方式,并且它是一种协议...(仍然是一个内置于芯片上的协议)支持)。

如果您必须实现任何已知协议,请考虑为此使用预制的HDL代码-可以找到或购买。


@Liran Orevi,精彩文章,您能详细介绍一下智能协议吗?SPI,I2C还有其他功能吗?
JeffV

@Jeff V,添加了有关“编辑”的一些信息,如果不是您想要的,或者有其他问题,请联系我。
Liran Orevi 09年

5

这个问题需要JBDAVID的10条关于硬件设计的诫命。

  1. 就像在软件中一样,使用修订/版本控制。SVN和Hg是免费的。
  2. 要求代码在登机前通过语法检查。LINT工具更好。
  3. 使用功能全面的硬件验证语言进行设计验证。System-Verilog几乎是一个安全的选择。
  4. 跟踪错误。Bugzilla和GNATS是免费工具。FogBugz需要一点钱。
  5. 使用断言来发现使用不正确的问题。
  6. Coverage Triad可以实现稳定的设计:在仿真工具和正式工具中都可以测量代码覆盖率,功能覆盖率和断言覆盖率。
  7. 力量为王:使用CPF或UPF捕获,执行和验证您的Power-Intent。
  8. 真正的设计通常是混合信号,请使用混合信号语言来验证模拟与数字。Verilog-AMS就是这样一种解决方案。但是不要太过分。实数建模可以完成混合信号行为的大多数功能方面。
  9. 使用硬件加速来验证必须与芯片一起使用的软件!
  10. HDL / HVL的语法感知文本编辑器是开发人员IDE的最低要求。

4

对于FPGA,Xilinx拥有此页面。几乎所有这些都将适用于其他FPGA供应商,或者具有等效的规则。大量设计适用于ASIC设计。

英特尔在此页下有推荐的HDL编码样式和设计建议(PDF)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.