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

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

与更常见的软件开发领域相比,有哪些共同之处和差异?

关于这个主题的最好的书是重用方法手册 。 它涵盖了VHDL和Verilog。

尤其是一些软件中没有完全匹配的问题:

  • 没有闩锁
  • 小心重置
  • 检查你的内部和外部的时间
  • 只能使用可合成的代码
  • 注册所有模块的输出
  • 小心阻塞与非阻塞任务
  • 注意组合逻辑的敏感列表(或者在Verilog中使用@(*))

有些是相同的包括

  • 使用CM
  • 有代码评论
  • testing(模拟)你的代码
  • 适当时重用代码
  • 有一个最新的时间表
  • 有一个规范或用例或敏捷客户

sorting一个旧的线程,但要放在我的$ 0.02。 这并不是Verilog / VHDL所特有的。通常在硬件devise方面更多…专门针对定制ASIC的可综合devise。

这是我基于多年的行业(而不是学术)devise经验。 他们没有特定的顺序

我的伞声明是devisevalidation执行。 在硬件devise中,validation是最重要的。 在实际芯片中发现的缺陷要贵得多。 你不能只重新编译。 因此,硅前期工作得到了更多的关注。

  • 了解控制path和数据path的区别。 这使您可以创build更优雅和可维护的代码。 也可以让你保存大门和X传播最小化。 例如,数据path不应该需要可重置的触发器,控制path应该始终需要它。

  • 在validation之前certificatefunction。 无论是通过正式的方法还是通过波形。 这有很多好处,我会解释一下。首先,它会为您节省时间洋葱剥离的问题。 与许多应用程序级别的devise(尤其是学习)和大多数课程工作不同,代码更改的周转时间非常长(根据复杂性,从10分钟到几天)。 每次你改变代码,你都需要经过精心devise,检查,编译,波形提取,最后是实际的模拟。 其次,你不太可能遇到困难的情况。 注意这是关于硅前validation的。 这些将肯定会在后期硅上花费你很多$$$。 相信我,certificatefunction的前期成本大大降低了风险,非常值得努力。 有时很难说服最近的大学gradle生。

  • 有“鸡头”。 鸡位是通过驱动器设置的MMIO中的位来禁用硅中的特征。 它旨在恢复信心不高的变化(信心与validation工作成正比)。 几乎不可能在预硅片上达到所有可能的状态。 只有在硅之后certificate自己的devise才能真正得到满足。 即使只有一个状态达到0.000005%的时间暴露了这个bug,它也会在硅后发生,但不一定在硅前。

  • 不惜一切代价避免在控制path中出现exception。 每一个新的例外你有双倍的validation工作。 这个很难解释。 假设有一个DMA块将数据保存到另一块将使用的内存中。 可以说,保存的数据结构取决于某个正在完成的function。 如果您决定devise一个保存的数据结构在不同function之间不同的数据结构,那么您只需将您的validation工作量乘以DMA函数的数量即可。 如果遵循这个规则,保存的数据结构将是内容位置被硬编码的每个function的所有可用数据的超集。 一旦DMA保存逻辑被validation为1function,其validation所有function。

  • 最小化接口(读取最小化控制path)。 这与最小化exception有关。 首先,每个新界面都需要validation。 这包括testing台中的新的检查器/跟踪器,断言,覆盖点和总线function模型。 其次,它可以成倍增加您的validation工作! 比方说,你有1个接口读取caching中的数据。 现在让我们说(出于某种奇怪的原因)你决定你想要另一个接口来读取主内存。 你只是把你的validation工作翻了两番。 您现在需要在任何给定的时间validation这些组合n

    • 没有caching读取,没有内存读取
    • 没有caching读取,内存读取
    • caching读取,无内存读取
    • caching读取,内存读取
  • 理解和传达假设。 缺乏这是阻止沟通问题的主要原因。 你可以有一个完美的块完全validation..然而,不理解所有的假设,你的块将失败,当其连接。

  • 尽量减less潜在的状态。 devise越less(有意或无意),validation所需的努力就越less。 将函数组合成1个顶层函数(如顺序器和仲裁器)是很好的做法。 要识别和定义这个高级function是非常困难的,因为它包含了尽可能多的小function,但是这样做会大大消除状态,进而可能发生错误。

  • 始终提供一个强大的信号离开你的块。 大多数情况下,这是解决scheme。 您不知道端点块将使用它做什么。 您可能会遇到可能对您的完美实施产生直接影响的计时问题。

  • 除非性能受到负面影响,否则应避免使用粉碎型FSM。 Mealy FSM比摩尔更可能产生计时问题

  • 最后是我最不喜欢的那个:“如果没有破坏,就不要修复”由于涉及到的风险和高昂的bug成本,很多时候黑客攻击是解决问题的更实际的解决scheme。 其他人通过提及利用现有组件来避免这一点。

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

  • 离散事件驱动的编程是一个完全不同的范例。 人们看到Verilog的语法,并认为“哦,它就像C”…但是,这不能离真相更远。 虽然语法是相似的,但是必须有不同的思维。 例如,传统的debugging器在可综合的RTL上实际上是毫无意义的(Testbenchdevise是不同的)。 纸上的波形是最好的工具。 然而,这就是说,FSMdevise有时可以模仿程序编程。 有软件背景的人往往会对FSM发疯(我知道我起初是这么做的)。

  • 系统Verilog具有大量(大量)testing台特定function。 它完全是面向对象的。 就testing平台devise而言,它与传统的软件devise非常相似。 但是,它还有一个与它相关的维度,那就是时间。 必须考虑到种族条件和协议延迟

  • 至于validation,它也是不同的(和相同的)。 主要有三种方法;

    • 正式的传播validation(FPV):你通过逻辑certificate它会一直工作
    • 定向随机testing。 随机设置种子定义的延迟,input值和特征启用。 直接意味着种子把重点放在信心不足的path上。 这种方法使用覆盖点来表示健康
    • 重点testing。 这与传统的软件testing类似

…为了完整起见,我还需要讨论最好的testing台devise方法…但是那是另一天

对不起长度..我在“区”:)

像Verilog和VHDL这样的HDL似乎确实鼓励了意大利面代码。 大多数模块由几个“总是”(Verilog)或“进程”(VHDL)块组成,可以按任意顺序进行。 模块的整体algorithm或function通常是完全模糊的。 弄清楚代码是如何工作的(如果你没有写的话)是一个痛苦的过程。

几年前我遇到这篇文章 ,概述了一个更加结构化的VHDLdevise方法。 基本思想是每个模块只有2个进程块。 一个用于组合代码,另一个用于同步(寄存器)。 生成可读和可维护的代码非常棒。

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

    • 长和具体为您的需要可以创buildpipe道。
    • 你可以让你的大模块同时工作。
    • 而不是一个单位对不同的数据做重复的动作,可以创build多个单位,并行地完成工作。
  • 应该特别注意引导过程 – 一旦你的芯片正常工作,你已经取得了巨大的成功。

在硬件上进行debugging通常比debugging软件要困难得多:

  • 简单的代码是首选,有时还有其他的方法来加快你的代码,例如使用更高速度的芯片等。

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

  • HDL中的工作代码比其他软件更加珍贵,因为硬件难以debugging,所以重复使用,并考虑使用某些免费和其他模块的“库”。

  • devise时不仅要考虑HDL代码中的错误,还要考虑到你正在编程的芯片上的故障,以及与芯片接口的其他硬件设备上的故障,所以应该考虑一个容易检查的devise。

一些debugging技巧:

  • 如果一个devise包含多个构build块,则可能需要创build从这些块之间的接口到该芯片之外的testing点的线路。

  • 您将需要在devise中存储足够的线路,以将有趣的数据转移到外部设备上进行检查。 你也可以使用这行代码和你的代码来告诉你当前的执行状态 – 例如,如果你在某些时候接收到数据,你会为这些行写入一些值,在后面的执行阶段你会写另一个值等等'

    如果你的芯片是可重新configuration的,这将变得更加方便,因为你可以定制特定的testing,并为每个testing的输出重新编程,你去(这看起来很好用LED)。 )

编辑:

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

原因就在于 – 在模拟器中,“在FPGA / ASIC内部”寻找错误相当容易。 所以,如果你确定数据是按照你的要求来的,并且在你的程序发送出去的时候,你已经达到了硬件乌托邦 – 能够在软件层面上工作:)(用模拟器)。 但是,如果你的数据不能得到你想要的结果,你必须弄清楚为什么…你必须连接线路,这并不容易。

发现线路上的错误是很难的,因为你必须用特殊的设备连接线路,logging线路的状态,在不同的时间,你必须确保你的线路按照协议行事。

如果你需要连接两个物理单元,使协议尽可能简单,直到它不会被称为协议:)例如,如果单元共享一个时钟,在它们之间增加x条数据线,并且使得一个单元将这些单元和另一个单元读取,从而例如在每个时钟周期中传递它们之间具有x位的一个“字”。 如果你有FPGA的话,如果原始的时钟频率对于并行数据来说太快了 – 你可以根据你的实验来控制这个速度,例如使数据保持在至less“t”个时钟周期的线上。 我假设并行数据传输更简单,因为您可以以较低的时钟速率工作并获得相同的性能,而无需在一个单元上分割您的单词,然后重新组合。 (希望在每个单元收到的'时钟'之间没有延迟)。 即使这可能太复杂:)

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

一些FPGA公司使用JTAG来testing/编程他们的产品,但是不知道它是否被用作高速传输数据的方式,而这是一种协议…(仍然可能有一些内置片上支持)。

如果您必须实现任何已知的协议,请考虑使用预先制作的HDL代码 – 可以find或购买。

这是需要JBDAVID的10个硬件devise指令的问题。

  1. 使用版本控制,就像在软件中一样。 SVN和Hg是免费的。
  2. 要求代码在检入前通过语法检查。 LINT工具更好。
  3. 使用全function硬件validation语言进行devisevalidation。 System-Verilog几乎是一个安全的select。
  4. 跟踪错误。 Bugzilla和GNATS是免费的工具。 FogBugz需要一点点$。
  5. 使用断言来捕捉错误使用的问题。
  6. Coverage Triad提供了一个稳定的devise:在模拟和正式工具中测量代码覆盖率,function覆盖率和声明覆盖率。
  7. 权力是国王:使用CPF或UPF捕捉,执行和validation您的权力意图。
  8. 真正的devise往往是混合信号,使用混合信号语言来validation模拟与数字。 Verilog-AMS就是这样一个解决scheme。 但不要太过分了 实数build模可以完成混合信号行为的大部分function。
  9. 使用硬件加速来validation必须使用硅片的软件!
  10. 语法针对您的HDL / HVL的Aware文本编辑器是开发人员IDE的最低要求。

对于FPGA,赛灵思拥有这个伟大的页面 (丢失,新的位置TBD)。 几乎所有的应用程序将适用于其他FPGA供应商,或将有相同的规则。 ASICdevise很适用。

Altera 推荐使用Altera器件和Quartus II Design Assistant的 HDL编码风格(PDF)和devisebuild议 。 Altera有这个薪酬课程 。 但是更多的是生产力。 我没有其他的信息有多好。