在实施HDL代码时应该遵循哪些最佳实践?
与更常见的软件开发领域相比,有哪些共性和差异?
一个旧线程的排序,但想要投入我的0.02美元.这并非真正特定于Verilog/VHDL ..更多关于硬件设计的信息......特别是针对定制ASIC的可综合设计.
这是我基于多年的行业(而不是学术)设计经验的观点.它们没有特别的顺序
我的总结声明是设计验证执行.在硬件设计中,验证是至关重要的.当在实际的硅中发现时,错误要贵得多.你不能只是重新编译.因此,预先给予硅更多的关注.
了解控制路径和数据路径之间的区别.这使您可以创建更优雅和可维护的代码.还允许您保存门并最小化X传播.例如,数据路径永远不需要可复位的触发器,控制路径应始终需要它.
验证前证明功能.通过正式方法或通过波形.这有很多优点,我将解释2.首先,它将节省你浪费时间洋葱剥皮问题.与许多应用程序级别设计(尤其是学习时)和大多数课程工作不同,代码更改的周转时间非常长(根据复杂程度,从10分钟到数天不等).每次更改代码时,都需要经过详细说明,lint检查,编译,波形启动,最后进行实际模拟......这本身可能需要数小时.其次,你不太可能遇到难以打击的案件.请注意,这与硅前验证有关.这些肯定会在后硅片上花费你很多$$$.相信我,证明功能的前期成本大大降低了风险,非常值得付出努力.这有时难以说服最近的大学毕业生.
有"鸡块".鸡位是通过驱动程序设置的MMIO中的位,以禁用硅中的功能.它旨在恢复信心不高的变化(置信度与验证工作成正比).在硅之前几乎不可能达到每种可能的状态.只有在后硅片中证明了对您的设计的信心才能真正得到满足.即使只有1个状态在暴露bug的时候达到0.000005%,它也会在后硅片中发生,但不一定在硅片之前.
不惜一切代价避免控制路径中的异常.您的每个新例外都会使您的验证工作加倍.这个很难解释.假设有一个DMA块可以将数据保存到另一个块将使用的内存中.可以说保存的数据结构取决于正在完成的某些功能.如果您决定设计保存的数据结构在不同函数之间是不同的,那么您只需将验证工作乘以DMA函数的数量.如果遵循此规则,则保存的数据结构将是内容位置被硬编码的每个功能可用的所有数据的超集.一旦DMA保存逻辑被验证为1个功能,它就验证了所有功能.
最小化接口(读取最小化控制路径).这与最小化异常有关.首先,每个新界面都需要验证.这包括测试平台中的新检查器/跟踪器,断言,覆盖点和总线功能模型.其次,它可以以指数方式增加您的验证工作量!假设您有一个用于读取缓存中数据的界面.现在让我们说(出于一些奇怪的原因)你决定要另一个接口来读取主内存.您只是将验证工作增加了四倍.您现在需要在任何给定时间验证这些组合n:
没有缓存读取,没有内存读取
没有缓存读取,内存读取
缓存读取,无内存读取
缓存读取,内存读取
理解并传达假设.缺乏这是阻止通信问题的主要原因.您可以完全验证完美的块.但是,如果不了解所有假设,您的块将在连接时失败.
尽量减少潜在的状态.设计越少(有意或无意),验证所需的工作量就越少.将类似函数分组为1个顶级函数(如序列发生器和仲裁器)是一种很好的做法.识别和定义这个高级函数非常困难,因此它包含尽可能多的较小函数,但是这样做可以大大消除状态,从而可能导致错误.
始终提供一个强大的信号离开你的街区.大部分时间都是解决方案.您不知道端点块将使用它做什么.您可能遇到可能对您的完美实施产生直接影响的计时问题.
除非性能受到负面影响,否则请避免使用类型FSM.Mealy FSM更有可能产生超过摩尔的时间问题
...最后是我最不喜欢的那个:"如果没有破坏,就不要修复它"由于涉及的风险和错误的高成本,很多时候黑客攻击是解决问题的更实际的解决方案.其他人则通过提及现有组件的使用而忽略了这一点.
至于与更传统的软件设计进行比较:
离散事件驱动编程是一种完全不同的范例.人们看到verilog语法,并认为"哦,它就像C"......但是,这不能说实话.虽然语法类似,但必须以不同的方式思考.例如,传统的调试器在可综合的RTL上几乎毫无意义(Testbench设计不同).纸上的波形是最好的工具.然而,话虽如此,FSM设计有时可能模仿程序编程.拥有软件背景的人往往会对FSM感到疯狂(我知道我最初做过).
System Verilog拥有大量(和大量)测试平台特定功能.它完全面向对象.就测试平台设计而言,它与传统的软件设计非常相似.但是,它确实还有1个与之相关的维度.必须考虑竞争条件和协议延迟
至于验证,它也是不同的(也是相同的).有三种主要方法;
正式传播验证(FPV):您通过逻辑证明它将始终有效
定向随机测试.随机设置种子定义的延迟,输入值和功能启用. 定向意味着种子将重量放在信心不足的路径上.该方法使用覆盖点来指示健康
重点测试.这类似于传统的软件测试
...为了完整起见,我还需要讨论最好的测试平台设计实践......但那是另一天
抱歉长度..我在"The Zone":)
关于这个主题的最好的书是重用方法手册.它涵盖了VHDL和Verilog.
特别是一些在软件中没有完全匹配的问题:
没有锁扣
小心重置
检查内部和外部时间
仅使用可合成代码
注册所有模块的输出
小心阻塞与非阻塞分配
小心组合逻辑的敏感列表(或在Verilog中使用@(*))
一些相同的内容包括
使用CM
有代码审查
测试(模拟)您的代码
适当时重用代码
有一个最新的时间表
有规范或用例或敏捷客户
像Verilog和VHDL这样的HDL似乎真的鼓励意大利面条代码.大多数模块由几个"始终"(Verilog)或"进程"(VHDL)块组成,可以按任何顺序排列.模块的整体算法或功能通常是完全模糊的.弄清楚代码是如何工作的(如果你没有编写代码)是一个痛苦的过程.
几年前,我遇到了这篇文章,概述了一种更加结构化的VHDL设计方法.基本思想是每个模块只有2个过程块.一个用于组合代码,另一个用于同步(寄存器).它非常适合生成可读和可维护的代码.
在HDL中,代码的某些部分可以同时工作,例如两行代码"可以同时工作",这是一个优点,明智地使用.这是习惯于逐行语言的程序员最初可能很难掌握的东西:
可以创建长而且特定的需求管道.
您可以让您的大模块同时工作.
而不是一个单元对不同的数据进行重复操作,您可以创建多个单元,并行地完成工作.
应特别注意启动过程 - 一旦你的芯片正常运行,你就已经做了很大的工作.
在硬件上进行调试通常比调试软件困难得多:
简单的代码是首选,有时还有其他方法可以在代码运行后加速代码,例如使用更高速的芯片等.
避免组件之间的"智能"协议.
HDL中的工作代码比其他软件更加珍贵,因为硬件很难调试,因此重用,并且还考虑使用模块的"库",其中一些模块是免费的,而另一些则是出售的.
设计不仅要考虑HDL代码中的错误,还要考虑编程芯片上的故障,以及与芯片接口的其他硬件设备,因此应该考虑一个易于检查的设计.
一些调试技巧:
如果设计包含多个构建块,则可能需要从这些块之间的接口创建线到芯片外部的测试点.
您需要在设计中保存足够的线条,以转移有趣的数据,以便使用外部设备进行检查.你也可以使用这一行和你的代码来告诉你当前的执行状态 - 例如,如果你在某个时刻收到数据,你就会给行写一些值,在执行的后期你写另一个值等等'
如果你的芯片是可重新配置的,这将变得更加方便,因为你可以定制特定的测试,并在你去的时候重新编程每个测试的输出(这与leds :)非常相似.)
编辑:
通过智能协议,我的意思是,如果您的两个物理单元连接,它们应该与最简单的通信协议进行通信.也就是说,不要在它们之间使用任何复杂的自制协议.
原因是这样的 - 在你有模拟器的情况下,在FPGA/ASIC内部"填补"错误相当容易.因此,如果您确定数据是按照您的需要进行的,并在程序发送时熄灭,那么您已达到硬件乌托邦 - 能够在软件级别工作:)(使用模拟器).但是如果你的数据没有找到你想要它的方式,你必须找出原因......你必须连接到线路,这并不容易.
找到线路上的错误是很困难的,因为你必须连接到具有特殊设备的线路,记录线路的状态,在不同的时间,你必须确保你的线路按照协议行事.
如果你需要连接两个物理单元,使"协议"尽可能简单,直到它不会被称为协议:)例如,如果单元共享一个时钟,在它们之间添加x数据线例如,使一个单元写入那些单元并且另一个单元读取,从而传递一个"字",其在每个时钟下降之间具有x位.如果您有FPGA,如果原始时钟速率对于并行数据来说太快 - 您可以根据实验控制速度,例如使数据保持在至少't'时钟周期等线上.我假设并行数据传输更简单,因为您可以以更低的时钟速率工作并获得相同的性能,而无需在一个单元上拆分您的单词,并在另一个单元上重新组装.(希望每个单位收到的'时钟'之间没有延迟).即使这可能太复杂了:)
关于SPI,I2C等'我还没有实现它们中的任何一个,我可以说我已经连接了两个从同一个时钟运行的FPGA的脚,(不记得中间电阻的确切形成),很多更高的速率,所以我真的想不出使用它们的一个很好的理由,作为在你自己的FPGA之间传递数据的主要方式,除非FPGA位于彼此很远的地方,这是使用串口的一个原因而不是并行总线.
JTAG被一些FPGA公司用来测试/编程他们的产品,但不确定它是否被用作高速传输数据的方式,它是一种协议......(仍然可以在芯片上内置一些)支持).
如果您必须实施任何已知协议,请考虑使用预先制作的HDL代码 - 可以找到或购买.
使用修订版/版本控制,就像在软件中一样.SVN和Hg是免费的.
要求代码在签入前通过语法检查.LINT工具更好.
使用全强度硬件验证语言进行设计验证.System-Verilog几乎是一个安全的选择.
跟踪错误.Bugzilla和GNATS是免费工具.FogBugz需要一点钱.
使用断言来捕获错误使用的问题.
Coverage Triad实现了稳定的设计:在模拟和正式工具中测量代码覆盖率,功能覆盖率和断言覆盖率.
Power is King:使用CPF或UPF来捕获,执行和验证您的Power-Intent.
真正的设计通常是混合信号,使用混合信号语言来验证模拟与数字.Verilog-AMS就是这样一种解决方案.但不要过火.Realnumber建模可以完成混合信号行为的大多数功能方面.
使用硬件加速来验证必须使用芯片的软件!
语法Aware HDL/HVL的文本编辑器是开发人员IDE的最低要求.