1 亚稳态
接下来我们将系统地开始探讨亚稳态,并解决由亚稳态产生的问题。首先我们来了解一下什么是亚稳态。亚稳态是一种物理现象的名称,它发生在一个事件试图取样[1](sample)另一事件的时候。亚稳态可以描述如下:假设一个信号在t = 0时刻瞬间从0变为1,那么信号在t = 0时刻的值究竟是多少?是0还是1,或者在两者之间?在亚稳态中,这个问题被定义的两个时刻回避了,分别是0-和0+。在t = 0-时刻,规定信号的取值为0,t = 0+ 时刻规定信号的取值为1。显然,0- = 0 - 0,0+ =0 + 0。注意,这仅仅是一个数学定义,如果你正在用实际的电路做同样的事,输出将有可能是逻辑0(0伏)或者逻辑1(5伏),或者是介于0 ~5伏中间的某个值。正如在数学中描述的一样,物理系统中一个事件取样另一个事件产生了不可预知的结果。不可预知性也就意味着另一个迹象——亚稳态很危险。
1.1 时间分辨率(Resolution Time 翻转时间?)
当一个事件取样一个稳定值时(或者一个能稳定一段时间的值),取样值就随这个稳定值而变化。假设在D触发器情况下,就是Q值随D值变化。这段能够稳定取样的时间用相关的取样事件来定义,称之为时间分辨率(翻转时间?)。也就是我们所熟悉的“clock-to Q time”,或tcq。如果遇到触发器的setup time[2] 和hold time[2],这将是cell设计者保证输入能够正确变为输出的时间。亚稳态影响物理系统的时间分辨率,同样也影响输出值。在“不稳定平衡”情况下考虑这些问题,就像“山上的球”(或者球面上的球体)你不知道它会向哪个方向滚,这个球就处于不稳定平衡状态。如果球完全不受干扰,它有可能一直呆在原地,但是微小的晃动会使球滚到山的一边或另一边。这将无法计算球从山上滚下的距离,或者无法计算球从山的哪一边滚下来。这就是亚稳态的一个准确的例子——你无法预知物理系统输出的值将会变成什么样,多久会变化,并且相当危险。换句话说,输出永远保持一个有限非零概率的亚稳态。在现实中,尽管很少有这种情况发生,但20倍的clock-to Q 时间是一个合理的时间分辨率数值。在理论上,当取样操作接近被取样事件的时候,时间分辨率是无限的渐进曲线。
1.2 MTBF(平均无故障时间)与可靠性
如果一个设计中包含同步组件,无论是否愿意它都会出现亚稳态。亚稳态无法彻底消除,因此我们所做的就是计算错误概率以及在时间上来描述它。让我们来看一下,假设这里有一个物理系统亚稳态错误发生的概率为1/1000。换句话说,每一千次采样就会因为亚稳态发生一次错误。这也意味着,每一千次,输出就会在下一个时钟沿到来时,无法变化。如果时钟频率为1KHz,那么每秒都会有一次错误出现,MTBF值就为1秒。当然,这个假设过于简单;MTBF是一种故障概率的统计度量,并且需要更为复杂、经验化、实验化的数据来计算。对于触发器来说,这种关系依赖于电路自身的物理常数和时钟频率,记住亚稳态本身与时钟没有任何关系,但是它和MTBF相关[3]。自然的,我们会说一个可靠性好的电路具有很高的MTBF值。
1.3 同步
由于亚稳态无法彻底避免,在设计电路时一定要——
首先要求,设计与设计之间要有很大的区别,它并不在本文介绍的范围。第二个要求,使用 “同步”技术。这种技术由两个触发器简单的组合在一起如图1所示。仅当Q1的出现非常接近时钟沿的时候,Q2才会进入亚稳态。如果在亚稳态情况下我们将20倍的tcq作为时间分辨率,那么时钟周期将为tclk = 20tcq+ tsetup。这说明经过20倍的clock-to Q时间,输出仍然随输入改变的概率大大减小。因此,在时钟沿到来时Q2没有被改变的概率接近P2,这里P是第一级输出没有在时钟沿到来时随输入而改变的概率。这称为两级同步。当使用这个时钟频率下概率来计算MTBF时, MTBF值会提高很多。如果愿意的话,可以通过三级同步进一步增加MTBF值。但这在实际中很少需要。
如图2所示,可以在电路中增加冗余的同步来很好的抵御亚稳态。在三冗余和等同于两冗余的状态下,最终的输出大部分(三分之二)可以计算出来。在这个实例中,小尺寸的布局布线与器件的差异说明了如果一个同步器产生亚稳态错误,其他的两级也会产生亚稳态错误,所有的概率将随之改变。这种技术仅在要求非常苛刻时候的用到。欲更多了解亚稳态与同步的知识,请参阅Grosse,Debora的“Keep metastabiliy from killing your digital design”
2 采样计数器
2.1 同步:解决可靠性问题
现在我们回到有关FIFO的问题上来。如果要用时钟取样计数器的值,这相对于计数器时钟来说是异步的。因此,到最后不得不考虑计数器到底在哪个范围变化,假定从 FFFF到0000。每个单独的位(bit)都处于亚稳态。这种变化意味着有可能读数为0000到ffff之间(包含两者)的任何可能的值。当然这也说明该情况下FIFO将无法工作。同步可以保存处于亚稳态时的计数器取样,尽管看似很离谱但仍然可以得到取样值。换句话说,仅靠计数器同步是不够的。
重要的是我们必须确保不是所有的计数器位(bits)同时改变。实际上,不得不保证每一次计数器的增加正好改变一位。这说明计数器变化时出现错误的只可能有一位。如果计数器准备开始工作,那么至少需要一位的变化,这就是我们所能做的最好的办法。我们所需要的是用格雷码来表示的计数器。这是因为格雷码是最小距离码[4],相邻码元之间的只有1位不同。
让我们来分析一下格雷码(GRAY)对于FIFO的指针设计有什么作用。首先,同步意味着计数器的取样值很少处于亚稳态,其次,我们取样的值最多只会有一位发生错误。这就是说计数器的真实值从N-1变到N,那么无论是否发生错误读取的数不是N-1就是N,而不会是其它的值。由于在变化的那一时刻,必须确定输出的值是多少,这对于读出计数器值来说是完全正确的举动。只要能够确定读出的值是旧还是新就可以了。出现其它值则是不对的。如果进一步考虑,将会发现如果在改变值的瞬间取样计数器的值,两个答案(N-1,N)对于计数器的值都是正确的。
2.2 保守的[5]报告——很好的处理错误
了解了这么多,接下来分析一下怎样将这些知识用于FIFO的读写指针操作。人们通常希望知道FIFO是否为满。如果它满了,必须阻止写操作再次发生。这很关键,因为当FIFO已满时,必须停止写指针加1。将(格雷码的)读指针与写时钟同步。因为每当同步读指针的时候,实际的读指针可能会变为不同的值。这意味着读指针可能会是一个失效的值。如果是这样,从写操作的角度考虑会发生少读现象(相比实际情况),如果条件吻合,FIFO为满。实际上,FIFO可能未满,因为有可能读操作发生,而从写操作的角度是“看不到”的。然而,我们只要阻止额外的写操作就OK了。如果当FIFO真的满了时我们不去阻止写操作将会出现错误。
同样的从读操作的角度看——实际上当FIFO 中还有一些数据时,读操作一方看到“被延迟的”写操作,可能会认为FIFO为空。这种情况读操作被阻止直到写操作“变得可被读操作一方所看见”,它将不允许进一步的读操作。
上述被称为保守的报告。简而言之,当FIFO未满时,对于写操作一方报告称FIFO已满,当FIFO未空时,报告对读操作一方称FIFO已空。这种现象好比FIFO动态的缩小了一点,这毫无坏处。在字节计算的情况下,我们用同样的技术,提供写操作一方的字数计算和读操作一方的字数计算。写操作一方计算的字数可能大于FIFO中的真实字数。这已令人相当满意了,因为影响它的仅仅是允许其阻止下一步的写操作。同理,读操作一方字数计算会少于实际字数,那也没关系,只要确认不要将写操作一方计算的字数用于读操作一方即可,反之亦然。
这种保守的报告机构在被同步的值中能很好的处理错误。事实上,即使取样的读指针值将处于亚稳态一段时间,其影响只是阻止写操作,使FIFO暂停写操作,而不会引起数据错误。同理适于读操作。
3 结构
3.1 产生空/满标志的条件
记得上篇文章中,我们提到了指针不是影响空/满标志唯一的条件。空标志的条件是由读操作引起的读写指针相等,满标志的条件是写操作引起的读写指针相等。换句话说,要正确地产生空/满标志信号,需要用写时钟对读信号进行取样,同时用读时钟对写信号进行取样。这不同于球的游戏,因为我们不希望对时钟的频率做出假设。设想一个10ns的写信号(100MHz)被一个1KHz的读时钟取样,若无脉冲宽度延展的话就不能这样做,而且这也意味着已知(或假设已知)两个时钟之间具有某种关联。
当然,我们也不希望假设时钟之间有任何的关系。这就引起了分别围绕三种方法的问题,并且,它将引出我们即将讨论的三种不同的结构。第一种结构相当不错,将在下面描述。第二种结构也还行,但不是很好,第三种结构性能超强,但在在面积占用方面没有优势。选择哪种结构要根据自己的需求。
3.2 第一个方案
由于不可能设计出一个不考虑频率的满足脉冲采样的电路,通过对读/写指针的编码我们绕过了这个问题。构造一个指针宽度为N+1,深度为2N字节的FIFO。为便方比较还可以将格雷码指针转换为二进制指针。
当(正被讨论的已被时钟同步的)指针的二进制码中最高位不一致而其它N位都相等时,FIFO为满。当(已经过二进制转换的)指针完全相等时,FIFO为空。这也许不容易看出,因此让我们举个例子来分析一下。
思考一下一个深度为8字节的FIFO怎样工作(使用已转换为二进制的指针)
(译者注:FIFO_WIDTH=8,FIFO_DEPTH= 2N = 8,N = 3,指针宽度为N+1=4 )。起初rd_ptr_bin和wr_ptr_bin均为“0000”。此时FIFO中写入8个字节的数据。wr_ptr_bin =“1000”,rd_ptr_bin=“0000”。当然,这就是满条件。现在,假设执行了8次的读操作,使得rd_ptr_bin =“1000”,这就是空条件。另外的8次写操作将使wr_ptr_bin 等于“0000”,但rd_ptr_bin 仍然等于“1000”,因此FIFO为满条件。
显然起始指针无需为“0000”。假设它为“0100”,并且FIFO为空,那么8个字节会使wr_ptr_bin =“1100”,, rd_ptr_bin 仍然为“0100”。这又说明FIFO为满。
这个例子的意义就在它生动地说明了读/写指针怎样产生空/满标志的。我曾说过第一个方案是最好的?你到不如将其这种技术与同步FIFO一起使用。它可以避免算数运算,提高FIFO的速度。
3.3 实现
我们知道在FIFO中要用到格雷码计数器。而不是用由格雷码换算的二进制码计数器(它不能实现每个计数器换后只有1位发生变化),必须使用真正的格雷码计数器。如果想实现格雷码计数,你会发现它并不像看起来那么容易。当然,你可以创建一个定制的机构来完成这项工作,但还是让我来提供一个更为普遍的解决问题的方法。大家知道格雷码于二进制码之间能够相互转换用到一个简单的公式:
二进制码转格雷码
gn=bn
Gi=bi⊕bi+1 ? i≠n
格雷码转二进制码
bn=gn
bi=gi⊕bi+1 ? i≠n
在上面的公式中,下标表示n+1位二进制码或格雷码的位数。
我们还知道计数器不过是一个触发器组和一个累加器而已,我们可以按照下面的方法来做——将格雷码码元转换为二进制码元,然后加1,再它转换回格雷码并存储。这是解决产生n-bit格雷码算法棘手问题一个普遍的方法。由它生成的计数器如图3所示。
当用综合工具优化时,相信综合工具能够为格雷码计数器提供一个相当快速的电路。当然,如果希望拥有一个深度为32字节的FIFO时,可在格雷码编码的状态机中手工编写计数器代码。
最终的FIFO设计如图4所示。这次我不再提供代码,因为我相信无论用VHDL或Verilog HDL编写,那都是一件非常容易的事。
在这里我要补充一点:如果你观察图4,会注意到有4个格雷码~二进制码转换器,这并不浪费。但通过保留格雷码指针的低n-bit和二进制最高位将有可能避免使用这些转换器。这是一种“混合”计数器,我将它作为练习留给读者。
3.4 时间考量
管理FIFO工作的首要时间条件是时钟的最高频率。在上述的FIFO条件下,不得不面对几个参量——时钟频率不能大于存储器所需频率,必须满足亚稳态时间关系tclk=20tcq+tsetup。当然,在公式中20这个因数完全凭借经验,倘若已经完成系统MTBF的计算,也可以选择其它值。另外,还应考虑格雷码计数器能够运行多快,因为上述公式要求受制于XOR(异或)门的速度。由于本文没有做任何设想(除了同步,而这并非真正意义上的设想),时间不会引起很多同样的问题。 在这个设计中最应考虑的是用格雷码计数器和同步时避免与亚稳态相关的错误。要认识到发生同步错误,整个FIFO将无法工作(2bit错误就将意味着在DPRAM中一个完全不同的地址,因为地址也用格雷码表示)——也就是FIFO即可以吃入数据也可以吐出数据。所以,我无法列出更多的要点,而这些要点都基于用户设计中MTBF值,要做好你所能承担的最坏的打算。
译者注释:
[1] sample在这里翻译为“取样”,而不是“采样”、“抽样”,是想有别于奈奎斯特定理中抽样的概念。汉语中在触发器构成的电路里很少听到“取样”这种说法,但文中用到了sample一词,姑且译作“取样”,其实它表示了时序电路中两个信号相遇时的状态、稳定程度及先后关系。
[2] 关于setup time 和hold time 借用北大的一个PPT来解释其意义。
[3]实际中,MTBF与时钟频率也有关,若一个时钟为1MHz的系统其MTBF为10年,当时钟变为10MHz时,其MTBF有可能变为1秒钟。
[4]最小距离码:码的距离定义为相邻两个码元之间互异元素的个数比如101010与110011,从左到右,互异的元素有,第2个,第3个,第6个,所以码距为3 。这种定义又称为码的汉明距离。格雷码相邻码只有一位不同,因此格雷码的距离为1。
[5]原文为Pessimistic Reporting,字面翻译为悲观的报告,但综合上下文的意思来看,作者想表述的意思是宁少不多,宁慢不快。应该是一种出于保险的,保守的考虑,宁可少读一次FIFO ,也不让FIFO出错,顾翻译为“保守的报告”
文章评论(0条评论)
登录后参与讨论