目录
写在前面
亚稳态
解决时间
MTBF 和可靠性
同步
采样计数器
同步:解决可靠性问题
悲观报告:正确处理错误
架构 1
创建空、满条件
第一个解决方案
执行
时序考虑
往期系列博客
在本系列的前一部分中,我们看到了如何使用以下方法设计同步 FIFO一个双端口、非寄存输出 RAM。 这部分检查了相同的概念如何可能扩展以产生具有独立、自由运行的读取和写入时钟的 FIFO。 有自由运行的时钟简化了一些问题,但这会导致针对特定情况的解决方案。最普遍的情况是对时钟没有任何假设——甚至没有他们是自由运行的。 将在本系列的最后部分介绍这一点。
如果参考上一篇文章,会观察到除了状态块之外,没有什么真正需要在两个时钟下工作。 内存没有寄存读取,所以它并没有真正使用读时钟; 即使它确实有寄存读取,这些可以毫无问题地在读取时钟上运行。 状态块从根本上执行两个指针上的操作,它们运行两个不同的时钟。 这就是原因真正的困难。 如果要使用写时钟对读指针进行采样(反之亦然),可能会遇到称为亚稳态的问题。 这会导致错误地计算了空标志和满标志,总之会影响设计。
因此,让我们系统地进行,并在出现问题时加以解决。第一个问题是了解亚稳态。亚稳态是物理现象的名称当一个事件尝试对另一个事件进行采样时发生。在数学上,这种情况是如下:假设信号在时间 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 伏)。在物理系统,就像在数学系统中一样,通过另一个事件采样一个事件会产生不可预知的结果。不可预测性还意味着另一种现象——这就是亚稳态带来的真正危险。
当一个事件采样一个静态值,(或一个已经稳定了一段时间的值)采样值将自身解析为该静态值的值。如果你用 D 触发器来说话,Q 自行解析为 D 的值。此解析所用的时间,定义为采样事件的时间称为分辨率时间。您对这个术语很熟悉,因为“时钟到 Q 时间”,或 t cq 。如果满足触发器的建立时间和保持时间,这就是单元设计者保证输出将被解决的时间。亚稳态影响物理系统的解析时间,以及解析值。想想这个“不稳定平衡”的术语,或山上的球。如果你在“小山”上有一个球(比方说,另一个球面)球被认为处于不稳定状态平衡。如果完全不受干扰,它可能会永远停在山上,但最小的扰动会导致球滚到山的一侧或另一侧。没有办法计算球会在山上停留多长时间,或者球会落在哪一侧。这是亚稳态的确切情况——更危险的是,你无法预测物理系统的值输出将在多长时间后解决。换句话说,有一个输出将永远保持亚稳态的有限非零概率。在实践中虽然这种情况很少发生,并且 20 倍时钟到 q 的数字被认为是合理的图为分辨率。理论上,解决时间遵循一条渐近曲线到无穷大采样时刻更接近被采样的事件。
如果您的设计中有异步元素,您将遇到亚稳态不管你想不想。绝对没有办法消除亚稳态完全,所以我们要做的是计算错误的“概率”并用以下形式表示时间。假设一个物理系统存在亚稳态故障的概率,并且这是千分之一。换句话说,对于每 1000 个样本,一个将导致失败因为亚稳态。这也意味着每千次输出一次在下一个时钟沿出现时不会自行解决。如果你的时钟频率是 1kHz,这意味着每秒一次的故障率,因此平均时间间隔失败计算为 1 秒。当然,这过于简单了。 MTBF 是一个统计失效概率的度量,并且需要一些更复杂的、经验性的和得出的实验数据。对于触发器,这种关系取决于物理电路本身的常数,以及时钟频率。重要的是要记住亚稳态本身与时钟频率无关——但 MTBF 与时钟频率有关。我们定义一个具有较高 MTBF 的电路自然是更可靠的电路。
由于亚稳态是绝对不可避免的,因此您必须设计电路,使其
第一个要求因设计而异,不在此范围内简单的介绍。对于第二个要求,一种称为“同步”的技术是用过的。该技术仅由两个触发器组成,如图 1 所示。Q2 将变为仅当 Q1 变化太接近时钟时才亚稳态。如果我们将 t cq 的 20 倍作为在亚稳态情况下解决的时间,那么时钟周期将由下式给出t clk = 20t cq + t 设置。这真正意味着输出仍然没有解决的概率在 20 次后,时钟到 q 的时间相当小。因此,Q2 的概率不在时钟沿出现时解决大约是 p^2 其中 p 是第一阶段输出在时钟沿到来时没有得到解决的概率沿着,相当于利用两级寄存器消除亚稳态的效率是一级寄存器的平方倍,这称为双级同步。当您将此概率与时钟频率来计算 MTBF,你会发现 MTBF 大大增加了。如果您可以通过使用三级同步器来进一步增加 MTBF,但是这在实践中很少需要,三级寄存器对亚稳态的进一步消除已经微乎其微。
可以通过冗余使电路更耐亚稳态同步器,如图 2 所示。最终输出计算为三重冗余的多数和双冗余的相等。在这种情况下,小路由和设备的差异意味着如果其中一个同步器出现亚稳态故障,则其他两个将,很可能已经自己解决了。 再次,这项技术是仅在最关键的要求中需要。
现在回到 FIFO 问题。 您需要使用时钟对计数器的值进行采样这与计数器时钟异步。 因此,可以在以下情况下设置计数器正在从 FFFF 变为 0000,并且每一位都变为亚稳态。 这意味着可能读取 0000 和 FFFF 之间的任何值(两者包括)。当然,这意味着 FIFO 将不起作用。 同步将保存计数器样本来自亚稳态,但仍然可能会得到采样值非常离谱。 换句话说,仅仅同步计数器是不够的。
我们必须做的重要事情是确保不是计数器的所有位都可以同时改变。 事实上,我们必须确保每时间计数器递增。 这意味着如果你赶上计数器转换,只有一位可能有误。 这是我们能做的最好的,因为我们至少需要一位转换如果计数器本身要工作。因此,我们需要一个以格雷码计数的计数器。 这是因为格雷码是单位距离码,也就是数据每增加1,格雷码的形式下二进制数只会变化一位。
现在让我们看看这对我们有何帮助。 首先,同步意味着我们很少会让计数器的采样值进入亚稳态,其次,我们所做的值样本最多会有一位错误。 这意味着如果计数器的实际值从 N - 1 更改为 N,将读取 N - 1 或 N,但没有其他值。 这是读取计数器的绝对正确行为,因为在更改时您需要做出值的确定。 只要您确定该值是旧值或更改后的值就可以了。 任何其他值都不行。 如果进一步考虑这一点,你会意识到,如果你在计数器改变的那一刻对它进行采样,要么结果(N - 1 或 N) 对计数器的值是正确的。
知道了这么多,现在让我们分析一下如何将其应用于读写我们的 FIFO 的指针。 假设我们想知道 FIFO 是否已满。 如果它已满,我们必须阻止进一步的写操作。 这很关键,因为我们必须停止写入当 FIFO 已满时,指针不会发生变化。 我们同步(格雷码)读取指向写时钟的指针。 这意味着我们可能有一个过时的读指针值,因为实际的读取指针可能在我们之前更改为不同的值同步它。 如果是这样,那么写入方认为读取次数较少执行(比实际执行),如果条件匹配,则 FIFO 已满。 事实上,FIFO 可能未满,因为可能发生了写入端未“看到”的读取。但是,我们只是阻止额外的写入,这没关系。 如果我们这样做是不正确的当 FIFO 实际已满时,不会阻止写入。
读取端类似——读取端看到“延迟”写入,并可能决定当 FIFO 实际上有一些数据时,它是空的。 这样做的效果是读取将阻塞直到写入“变得可见”到读取端。 同时,它不允许进一步阅读。
这被称为悲观报告。 简而言之,向写入端报告 FIFO 是不完整时已满,因此向读取端报告 FIFO 为空时它不是。 这就像 FIFO 已经动态收缩了一点,更加保守的使用FIFO,换句话说,这种保守的方式会影响 FIFO 的能,但是功能不受影响。
在字数统计的情况下,我们使用相同的技术,提供写入端字数统计和读取端字数。 写入端字数可能大于FIFO中的实际字数,这很好,因为它是允许的唯一效果拥有就是阻止进一步的写入。 类似地,读取端字数可能小于实际字数,这也可以。 只要确保你写入 FIFO 空间边缘的数据,反之亦然。
这种悲观报告机制负责处理同步值。 事实上,即使采样的读取指针值保持不变亚稳态一段时间,效果将是阻止写入,导致 FIFO “挂起”写入时间,但不会导致数据错误。 这同样适用于读取。
在上一篇文章中介绍过指针并不是唯一影响空和满标志。 empty 是当读取导致指针相等时, full 是写导致指针相等的时候。 换句话说,要生成正确 full 和 empty,我们需要自己对读写信号进行采样同步另一个时钟。 想象一下对 10 ns 写入信号进行采样(在 100 MHz 时)具有 1 kHz 读时钟。 如果没有脉冲展宽,你就无法做到这一点。
当然,我们不想假设时钟之间有任何关系。 这构成了一个围绕哪三种方式的问题,这导致了三种不同的我们将研究的架构。 这里描述了第一个架构,并且是最优的。 第二个是可行的,但不是很优,第三个是最庞大但就面积而言,价格昂贵。 选择哪种架构取决于你的要求。
因为不可能设计出一种电路来满足脉冲采样,而不管频率,我们通过在指针本身。 我们设计一个指针宽度为N + 1,FIFO 深度为2^N。 我们还将格雷指针转换为二进制,以便在比较时更容易。
当二进制版本的最高有效位时,FIFO 被视为已满指针(与相关时钟同步)不同,其余 N 位相等。当(二进制转换的)指针完全相等时,FIFO 被视为空。 这可能不是很明显,所以让我们用一个例子来分析它。
考虑这对于 深度为 16 的 FIFO 是如何工作的(我们使用二进制转换的指针)。最初,rd_ptr_bin 和 wr_ptr_bin 都是“00000”。 假设你写了 16 个数到 FIFO。 这意味着 wr_ptr_bin 是“10000”,而 rd_ptr_bin 是“00000”。 这当然是满的条件。 现在假设您执行16次读取,导致 rd_ptr_bin 为“10000”。这是空的条件。 另外 16 次写入将使 wr_ptr_bin 等于“00000”。 但是 rd_ptr_bin 仍然是“10000”,所以这是满的条件。如下图所示,。
应该很容易看出起点不必在“00000”。 如果它在,说 "01000" 且 FIFO 为空,然后16次写入将导致 wr_ptr_bin 为 "11000",和 rd_ptr_bin 保持在“01000”。 这又意味着满了。 也可以将此技术与同步 FIFO 一起使用。 这样可以避免算术运算并加速 FIFO。
我们需要一个格雷码计数器。 不是其值转换为的二进制计数器格雷码(这将破坏每次计数器转换改变一位的目的),但是真正的格雷码计数器。 如果尝试实现此功能,会发现它是不像看起来那么容易。 当然可以创建一个定制的机器工作,但让我提出一个问题的一般解决方案。 我们可以转换使用简单的方程从格雷码到二进制和二进制到格雷码:
二进制转格雷码,其转换格式为,格雷码数的最高位等于二进制数据的最高位,格雷码数的次高位等于二进制数的最高位与次高位异或,后面的位也是一样的方法。
逻辑表示为:
格雷码转二进制逻辑表示为:
在上面的等式中,下标是指 n+1 位二进制或格雷中的位数价值。
计数器只不过是一组触发器和一个增量器,我们执行以下操作——将格雷码值转换为二进制,递增,再转换回格雷码并存储它。 这是广义 n 位棘手问题的一般解决方案格雷码算术(它有一个复杂的解决方案)。 这个通用计数器是如图3所示。
当使用综合工具进行优化时,该工具将提供格雷计数器的相当快的电路。 当然,如果想要一个深度为32的 FIFO,可以用状态机的形式手动对计数器进行编码(用格雷码编码)。 然后状态本身就是计数值。
如果你观察图 4,你会注意到有四个格雷码到二进制转换器,这并不完全是浪费。 可以避免这些转换器通过保持指针的低 N 位格雷码,和最高有效位二进制。 这将是一个“混合”计数器。
控制 FIFO 操作的主要时序条件是最大时钟的频率。 在这样的 FIFO 的情况下,您将不得不遇到几个参数:时钟频率不能大于所需的内存(大于的话会使数据写入过满),并且必须满足亚稳态时序关系 t clk = 20t cq + t setup 。 当然,等式中的 20 因数是经验性的,你可以选择任何其他的,只要你已完成有关 MTBF 的功课。 除此之外,将不得不担心格雷计数器的运行速度有多快,因为上面的一个等式需要链式 XOR 大门。 因为我们在这里没有做任何花哨的事情(除了同步,那不是真的很花哨)时序不会造成太大问题。
此设计中的重要考虑因素是避免与亚稳态相关的故障使用格雷码计数器并同步它们。 一定要意识到,如果你失败了同步器,整个 FIFO 可能被破坏(两个位错误可能意味着与 DPRAM 完全不同的地址,因为地址也是格雷码的)——也就是说,它可能会吃掉或反刍数据。 因此,我不能对以下事实给予足够的强调: MTBF 计算应该尽可能悲观。
一文看懂异步 FIFO 架构(一) 单时钟的异步 FIFO