FPGA设计的十条“军规”

本文转载自: FPGA技术联盟

概述

本文参考了Peter Chambers的《The Ten Commandments of Excellent Design》。
同步数字系统在当今的设计中无处不在。工程师们为每一个可能的应用创造同步电路,频率从直流到千兆赫。每个同步系统都有一定的共性,且容易出现共性错误。这些错误会导致不稳定和不可靠,在典型的设计过程中可能无法发现。
最终的结果是一个不符合设计标准的劣质产品,工程师必须经历设计修改和修改的痛苦。这既费时又费钱。但是,通过使用一些简单的技巧,您可以避免设计中的同步设计错误,并获得一致的首次通过成功。在本文中,您将了解最常见问题的来源及其解决方案,以及如何将这些思想应用到您的设计中。

1、数字系统

开头我们先来说说一个典型的同步电路。可能有很多其他形式,但一个简单的例子足以说明。图1展示了同步电路的形式和时序。

一个值得提及的问题是:到底为什么要使用同步电路?异步逻辑(组合逻辑)不是更快速吗?这个问题的答案有很多,这里只提重要的几点:

同步电路消除了不同路径之间由于速度差异导致的问题。通过一个确定的时间间隔采样来实现的同步电路,使得快路径和慢路径可以以一种相同的形式完成采样;

  1. 同步电路不太受电压、温度和压力等外部因素的影响,这使得大规模的工业生产称为可能;

  2. 许多的设计被要求具备良好的移植性--也就是说,要非常容易地适应新的技术或者某种改进的技术(比如,从90nn到65nn)。同步电路的确定性行为使其更容易实现技术移植;

  3. 同步电路可以简化不同时钟域之间的接口。异步接口通常需要复杂的握手协议来保证数据的完整性;而同步电路自身就已经携带了时序信息,这使得数据可以被方便且正确地互相传递。

  4. 同步电路是由组合逻辑和一些时钟元素组成的,比如触发器和寄存器。时钟元素共享同一个时钟,所有的数据传递都发生在时钟的上升沿(或者下降沿,上升沿还是主流)。当上升沿到来时,寄存器把逻辑值从输入D端传递到输出Q端。

1.JPG

 在图1中,定义了两个重要的时钟参数:
  • Setup Time(建立时间)—Tsu:建立时间是指数据输入在时钟上升沿到来之前必须保持稳定的时间。
  • Hold Time(保持时间)—Th :保持时间是指数据输入在时钟上升沿到来之后必须保持稳定的时间。

        如何违反了建立时间和保持时间的要求,就会导致可怕的亚稳态问题。

2、时钟

时钟在同步系统种是最重要的因素。下面是两个对时钟所提出的要求。

Clock Skew 时钟偏差
时钟偏差,Clock Skew,是指同一个时钟域内的时钟信号到达数字电路各寄存器所用时间的差异。时钟偏差必须尽可能的小,以满足建立时间和保持时间的要求。减小时钟偏差的办法有路径等长、PLL和附加逻辑扩展保持时间等。
Clock Fidelity 时钟精确度
理想的时钟信号是完美的方波,但是实际的方波是存在一些时钟抖动的。那么什么是时钟抖动呢?时钟抖动, Clock Jitter,是相对于理想时钟沿,实际时钟存在不随时间积累的、时而超前、时而滞后的偏移称为时钟抖动(时钟脉冲宽度发生暂时变化,也就是 T cycle【时钟周期】或大或小)。同步系统中应尽可能地保证时钟的准确度。

3、好的状态机设计

同步设计中一个非常强大的武器是状态机(万物皆可状态机)。结合组合逻辑和许多寄存器,状态机能够根据其输入和当前状态做出决策。

状态机的行为是完全同步的,所有决策都是在时钟转换时做出的。状态机有两种传统形式:Mealy状态机和Moore状态机。这些状态机的特性如图2所示。

2.JPG

Moore状态机是两种状态机中较简单的一种。输出只是当前输入的函数。Mealy状态机的输出是当前状态加上输入的函数。

这个额外的路径提供了更多的灵活性,但可能会使对机器的理解复杂化。 

Moore状态机/Mealy状态机有什么问题?

 图2显示了状态机的Mealy和Moore形式的输出都是当前状态的组合解码,在Mealy形式中是输入的组合解码。虽然这在原则上是好的,但这里有陷阱等着粗心的人。

状态机的输出可能包括以下类型的功能:

  • 锁存使能(低或高脉冲打开或关闭锁存)

  • 三态使能(在片内或片外总线上打开和关闭驱动程序的信号)

  • 寄存器启用(启用同步时钟寄存器)

  • 其他一般控制信号,如计数器启用、标志等。

大多数这些信号都有一个共同的特点——毛刺在任何时候都是绝对不可接受的。当状态寄存器和Mealy或Moore状态机的输入转换时,组合逻辑可能由于门传播延迟的变化而产生毛刺。这些短暂的毛刺很可能包含足够的能量来打开锁存器、时钟寄存器,以造成非常严重的影响。

格雷码不能解决问题吗?

格雷码是一个非常好的设计,因为其每次转化都只有一个bit的变化,这很好地避免了毛刺对状态机转换带来的影响,看起来格雷码似乎与状态机是绝配。但是不要忘了,格雷码每次只有1bit变化的特性是有条件限制的--即转化只能发生在相邻两位。

比如从6跳转到7,或者反之,这样的转化格雷码会只有1bit的变化,但是从6到8则格雷码的变化就不止1bit了。现在的设计越来越复杂,状态机的状态通常都是几十上百,且不同状态之间的跳转及其复杂,这使得不相邻数字状态之间的跳转已成为常态!这无疑让格雷码作用大打折扣!

一个更好的状态机设计

 图3展示了一个状态机的更好设计。通过增加一个寄存器到输出端,来保证状态机的输出不会有毛刺,在此建议所有的状态机都使用寄存器作为输出端。

3.JPG

4、同步输入和状态机的复位

        复位信号通常是异步的,直接链接到到状态机寄存器的复位端。当复位时,所有寄存器(状态位和输出位)立即被清除。一切都很好,但是当复位被取消时会发生什么呢?

        试想一个状态机,它将在取消复位后直接从复位状态转换到其他状态。如果复位在时钟边缘附近解除,那么一些状态位将假定它们的新状态,而另一些可能不会。

状态机最终处于未定义的错误状态。解决方案?同步该死的复位!这样,复位将在时钟边缘之前被删除,所有寄存器元素将正确地过渡到它们的新状态。
事实上,对状态机的每个输入都必须是同步的。至少,您必须绝对确定没有任何输入会状态机内部寄存器的建立时间和保持时间。 

5、非法状态--状态机的灾难

        对状态机状态的编码有时候并不会用到所有的状态,比如一个有20个状态的状态机,通常会用5个bit来编码,而5bits最大可以有2^5=32个状态,那么其中剩下的32-20=12个状态就是不会用到的非法状态(dead states)。

        假设在某个状态机中,我们将值0-19用来设定为正确的状态机状态值,剩余的20-31是不会使用的多余值。如果状态机进入到状态值20-31,那么就会发生这样的错误:状态机永远会呆在这个非法状态而无法跳转到正常状态。
    为了避免这一情况,我们都需要设定一个良好的复位机制。当然,最好的办法是确保你的状态机永远都不会进入非法状态。

6、跨时钟域设计

        将数据从一个时钟域送入到另一个时钟域是困难的,建立时间和保持时间违规,亚稳态问题,不可靠的数据和其他危险等都有可能发生。实际上,整个同步问题都值得专门写一篇文章来讨论。

不过,在这里将介绍一些小提示,它们可能有助于解决跨时钟域同步问题。
 首先,让我们定义问题,请参见图4。

4.JPG

  现在有A、B两个不同的时钟域。我们不对时钟A/B做任何假设,只设定其为分别独立的两个不同时钟。 

        我们需要从时钟域A到时钟域B发送一个选通信号(Strobe A-B)和数据(Data A-B),作为回应,接收一个从时钟域B到时钟域A的选通信号(Strobe B-A)和数据(Data B-A)。彼此之间的信息传输必须绝对可靠。为了实现这一点,我们将研究跨时钟域问题的几个方面。

同步

        跨时钟域之间的问题与异步输入的问题有些类似。因为不同时钟域之间并无整数倍的关系可循,所以实际上应将其视为一对异步信号,这样就可以用处理异步输入的办法来解决跨时钟域问题,典型方法如图5(即打两拍):

5.JPG

 使用了两个寄存器,两个寄存器通常就足够了。只有最罕见的应用可能需要3个。这种方法使用广泛,但无法实现高频率信号同步到低频率的时钟域,即无法慢采快。

单点信息

        假设A块需要向b块发送2bits信息,我们可以简单地复制图5中的电路,每个bit对应一个同步电路。但有一个很严重的问题需要明确:有时会出现一个bit通过了两级同步电路,而另一个bit没有通过的情况。解决方案如图4所示,使用从a块到B块的单bit选通信号,并分别发送其他信息。从A到B的单点选通通知目标块数据A-B有效,初始块确保有足够的建立时间。 

切换交换

        一个不用担心电平和脉冲宽度的双向握手的好方法是使用切换交换协议。如图6所示。

6.JPG

    在这种情况下,通过选通信号Toggle A-B来指定此时传递的数据Data A-B有效,Data B-A的传递同理。如图7所示。

7.JPG

可以看到,每次传输只需要两个事件就可以完成:两个toggle选通信号中的每一个的切换。

当然,每个切换必须在接收端小心地同步,这种方法保证了跨任意频率的时钟域的宽数据总线的成功传输和接收。从千兆赫到千兆赫,切换方法是可预测和可靠的。 

7、锁存器

        在创建一组时钟元素时,通常有一个令人信服的理由使用基于锁存器的设计。用锁存器实现的单位寄存器可能只使用传统D型触发器所需的60%的逻辑门。

如果您的设计使用大量的配置寄存器、FIFO,或者有详细的数据路径,那么使用锁存时的节省可是相当可观的。
既然锁存器可能与时钟使能的D触发器的时钟使能信号相同,那么在FPGA设计中通常不使用锁存器呢?请看图8,其中显示了锁存器是如何工作的。

8.JPG

锁存器关闭时,锁存器的Q输出是稳定的。当锁存器打开时,输入被连续地复制到输出。锁存器在两个潜在的陷阱:

  • 输入端毛刺:锁存器D输入上的任何毛刺都会直接传播到输出。当然,通过确保输入上没有任何毛刺,这是可行的。然而,在同步系统中,总线往往在时钟边缘切换状态,锁存器使能通常跨越时钟传输从而容易产生毛刺。

  • 使能端毛刺:也许比锁存器输入端的毛刺更糟糕的是使能线上的毛刺。如果一个锁存器使能毛刺是异步解码的结果,那你的设计可真是太棒了!本文的第一部分讨论了如何消除毛刺。

基于寄存器的设计没有上面列出的任何缺点。竞争条件很少甚至不存在,控制或D信号上的毛刺不太可能造成伤害,信号可以在一个时钟周期内可靠地锁存住。

基于寄存器的设计可能比基于锁存的设计更大,但它更健壮。如果你一定要用锁存器,那就要小心了!

8、竞争 

        图9的电路有什么问题?        

9.JPG

这是竞争条件的一个经典例子:第一个触发器的输出发生变化时的过渡很可能违反第二个触发器的保持时间。

如果两个触发器的时钟之间存在偏差,则这种情况可能会恶化;如果触发器B的时钟滞后于A的时钟,那么B的输出实际上可能会复制A的输出,而不是增加所需的额外时钟延迟。图10显示了如何修复该问题:

10.JPG

 通过在传输路径上增益一个延迟元件确保触发器B在A的转换结果到达B之前有足够的时间完成它的转换。

9、可测试性

如果一切顺利,那么你的芯片将进入量产阶段,全世界(或至少股东们)将为此感到高兴。要做到这一点,你的设计必须要经历严格的测试。可测试性是许多设计中被忽视的一个方面。这里有一些建议可以帮助测试工程师在晚上睡得更好。

把大位宽计数器分成多个小位宽计数器

计数器需要大量的测试向量,以确保所有的位都正确切换,并且携带位按其应有的方式生成。为了帮助将测试向量的数量保持在一个合理的数量上,可以将一个计数器划分为多个更小的计数器(例如,每个计数器有四个比特)。然后提供每个阶段最重要的位的可见性。这样,测试序列可以通过观察最有效位的低到高和高到低的转换来验证每个计数器阶段的工作,并合理地得出计数器将作为一个单元工作的结论。

异步反馈路径是犯罪

       即使不考虑它对测试工程师的性格的影响,使用异步反馈的逻辑通常也是不好的,原因有很多。它很难模拟,它很可能依赖于电压、温度和过程,它可能非常容易受到瞬变的影响。

同样糟糕的是,它可能不能够在固定频率的测试仪器上进行测试。如果在你的设计中存在未锁定的反馈路径,确保它们能够从测试人员那里被打破和分析。当然最好是不好使用异步反馈路径。

10、别过分依赖仿真器

我们很容易说“我只要快速设计,然后在仿真中找到BUG。”这是一个坏主意,从一开始就注定要失败。模拟器因隐藏设计的古怪细节而臭名昭著。例子包括:

时钟同步

同步触发器不断与亚稳态和故障输入作斗争。它们的行为甚至不能接近你的一般模拟器;你只看到时钟边缘有一个清晰的过渡。从最初阶段开始,跨时钟域的设计必须始终正确。

异步逻辑

类似的方式,异步逻辑通常模拟得很差。当然,快速路径和竞争条件可能是隐藏的。一些环境将确定(和可选地纠正)保持时间违反,但这不是正确异步逻辑的万能药。

健壮设计的唯一解决方案是从一开始就正确地进行。你的逻辑必须是:

正确的设计

每一个门,每一行VHDL或Verilog,必须完全理解。不要指望某组模拟会发现你的bug;你可能会忽略测试你设计的一部分,如果它设计得很草率,它就会失败。

正确的检验

有纪律的布局也会使你的设计更加健壮、可理解和可维护。不应该需要通过大量难看的代码或杂乱的逻辑门来理解函数的操作。有组织的门、注释代码和完整的附带文档将为可靠的设计提供基础。

总结

  1. 所有的状态机输出都应该是时序逻辑输出(registered)

  2. 使用寄存器,别使用锁存器

  3. 状态机的输入包括复位都应该被同步

  4. 小心数据传递路径上的竞争

  5. 提供最好的时钟

  6. 一定要小心地进行信号的跨时钟域传递--记得同步

  7. 状态机中不要有非法状态

  8. 不要使用异步逻辑的反馈路径

  9. 小心创建解码逻辑--避免异步逻辑

  10. 别过分相信仿真器

最新文章

最新文章