目录
使用 1‑deep/2‑register FIFO 同步器传递多位 CDC 信号
在时钟域之间传递多个信号
在时钟域之间传递多个信号时,简单的同步器并不能保证数据的安全传送。工程师在进行多时钟设计时经常犯的一个错误是将同一事务中所需的多个 CDC 位从一个时钟域传递到另一个时钟域,而忽略了CDC 位同步采样的重要性。
问题是同步到一个时钟的多个信号会遇到小的数据变化偏差,这些偏差偶尔会在第二个时钟域中的不同时钟上升沿采样。即使我们可以完美地控制和匹配多个信号的走线长度,上升和下降时间的差异以及芯片上的工艺变化也可能会引入足够的偏差,从而导致在其他精心匹配的走线上出现采样失败。因此必须采用多位 CDC 策略来避免多位数据的倾斜采样。
多位 CDC 策略
为了避免多位 CDC 倾斜采样情况,将多位 CDC 策略分为三大类:
- 多位信号合并。在可能的情况下,将多个 CDC 位合并为 1 位 CDC 信号;
- 多循环路径公式。使用同步负载信号安全地通过多个 CDC 位;
- 使用格雷码传递多个 CDC 位。
多比特信号合并
在可能的情况下,将多个 CDC 信号合并为一个 1 位 CDC 信号。问自己一个问题,我真的需要多个位来控制跨 CDC 边界的逻辑吗?
仅在所有 CDC 位上使用同步器并不总是足够好,如下面的示例所示。
如果控制信号的顺序或对齐很重要,则必须注意正确地将信号传递到新的时钟域。本节中显示的所有示例都过于简单化,但它们与实际设计中经常出现的情况非常相似。
问题 ‑ 两个同时需要的控制信号
在如图所示的简单示例中,接收时钟域中的寄存器需要加载信号和使能信号才能将数据值加载到寄存器中。如果负载和使能信号都在同一发送时钟沿驱动,则控制信号之间的小偏差可能会导致两个信号同步到接收时钟域内的不同时钟周期。在这些条件下,数据不会加载到寄存器中。
解决方案 ‑ 合并
问题的解决方案很简单,合并控制信号。如图所示,仅从一个负载使能信号驱动接收时钟域中的负载和使能寄存器输入信号。合并将消除两个控制信号在时间上发生偏移的可能性。
问题 ‑ 两个相移排序控制信号
图中展示了两个使能信号aen1和aen2,它们被顺序地从发送时钟域驱动到接收时钟域,以控制流水线数据寄存器的使能输入。问题是在第一个时钟域中, aen1控制信号可能在aen2控制信号产生之前稍微终止,并且接收时钟的上升沿可能出现在aen1和aen2控制信号脉冲之间的微小间隙中,导致在接收时钟域的使能控制信号链中形成一个周期间隙。这将导致第二个寄存器丢失a2数据值。
解决方案 ‑ 合并和额外的触发器
如图所示,该问题的解决方案是仅将一个控制信号发送到接收时钟域,并在接收时钟域内生成第二个相移流水线使能信号。
问题 ‑ 多个 CDC 信号
如图所示,在时钟域之间传递的两个编码控制信号。如果两个编码信号在采样时有轻微偏差,则可能会在接收时钟域中的一个时钟周期内生成错误的解码输出。
传递多个 CDC 信号的解决方案
多循环路径 (MCP) 公式和 FIFO 技术可用于解决与传递多个 CDC 信号相关的问题。 MCP 公式的描述和定义在后面的内容给出。
有两种多循环路径 (MCP) 公式可用于解决此问题:
(1) 闭环 ‑ 带反馈的 MCP 公式
(2) 闭环 ‑ 带有确认反馈的 MCP 公式
MCP 制定实施技术将在下一节开始介绍。
还有两种 FIFO 策略可以作为这个问题的闭环解决方案:
(1) 异步 FIFO 实现
(2) 2‑deep FIFO 实现
之后会讲到这部分的内容。
多循环路径(MCP)公式(握手法)
使用 MCP 公式是安全传递多个 CDC 信号的常用技术。MCP 公式是指将非同步数据发送到与同步控制信号配对的接收时钟域。数据和控制信号同时发送,允许数据在目标寄存器的输入上设置,同时控制信号在到达目标寄存器的输入之前同步两个接收时钟周期。
优点:
(1) 发送时钟域不需要计算在时钟域之间发送合适的脉冲宽度。
(2) 发送时钟域只需要将一个使能切换到接收时钟 domain 表示数据已通过并准备好加载,只有使能信号来临,才能对信号进行采样。使能信号不需要返回其初始逻辑电平。
该策略在不同步的情况下传递多个 CDC 信号,同时将同步的使能信号传递到接收时钟域。在同步使能通过同步到达接收寄存器之前,不允许接收时钟域对多位CDC信号进行采样。
这种策略被称为多周期路径公式,因为未同步的数据直接传递到接收时钟域并保持多个接收时钟周期,从而有充分的时间允许使能信号同步,并识别到接收允许未同步的数据更改之前的时钟域。
因为未同步的数据在被采样之前经过多个时钟周期并保持稳定,所以不会有采样值变为亚稳态的危险。
使用同步使能脉冲的 MCP 公式
或许在时钟域之间传递同步使能信号的最常用方法是采用切换使能信号,该信号被传递到同步脉冲发生器,以指示可以在下一个接收时钟沿捕获未同步的多周期数据,如下图所示。
这种同步使能脉冲生成的一个关键特性是输入信号的极性无关紧要。在图中,d 输入在周期 1 中切换为高电平,到周期 4 时,高电平信号已通过三个同步触发器传播。在周期 3 中,q2 和 q3 触发器的输出具有不同的极性,在周期 3 可以对 q2 和 q3 进行异或操作形成脉冲。类似地,d 输入在周期 7 中切换为低电平,到周期 10 时,高信号已通过三个同步触发器传播。同样在第 9 周期,q2 和 q3 触发器的输出具有不同的极性,在周期 9 可以对 q2 和 q3 进行异或操作形成脉冲。
由于前面描述的所有 MCP 公式都使用同步使能脉冲生成电路,因此认为创建和使用较小的等效符号来表示同步使能脉冲生成电路是有用的。等效符号如下图所示。
除了生成任何 d 输入极性的脉冲外,同步使能脉冲生成电路还具有一个 q 输出,该 q 输出跟随 d 输入,延迟三个时钟周期。 q 输出经常用作反馈信号,并作为确认信号通过发送时钟域中的另一个同步使能脉冲生成电路。
下图展示了典型的发送‑接收触发脉冲生成设计。
大致的实现过程:Data In 作为发送方的数据输入,Next Data Pulse 用作输入的打三拍后的异或形成脉冲信号,并同打三拍的信号一同输出,脉冲信号用作输出信号的判据,当接收时钟域检测到脉冲,则将发送方的数据采样输出。
注意:使用这种技术,需要接收时钟域具有适当的逻辑来在检测到脉冲时捕获数据,因为脉冲将仅在每个多周期数据字的一个接收时钟周期内有效。
闭环 ‑ 带反馈的 MCP 公式
使用 MCP 公式时的一项重要技术是将启用信号作为确认信号传回发送时钟域,如下图所示。
对于上图中的示例,确认反馈信号(b_ack)生成一个确认脉冲 (aack) ,该脉冲用作一个小的READY‑BUSY、 1 状态 FSM 块的输入,该块生成一个就绪信号 (aready) 以指示现在可以安全地再次更改数据输入 (adatain) 值。一旦aready信号变高,发送者就可以自由发送新数据(adatain)和伴随的 asend 控制信号。
我的理解:接收方有个 ready 信号,只有当 readt 信号拉高时,发送方才可以发新的数据给接收方。
这是一个自动反馈路径,它假定接收时钟域将始终准备好通过 MCP 公式同步的下一个数据。
闭环 ‑ 带有确认反馈的 MCP 公式
之前描述的技术的完全响应变体使用 MCP 公式,即仅在接收时钟域确认接收到带有bload脉冲的数据后,才将启用信号作为确认信号传递回发送时钟域,如下图所示。
对于上图中的示例,接收时钟域有一个小的 WAIT‑READY、 1 状态 FSM,当数据寄存器的输入上的数据有效时,它会向接收逻辑发送一个有效信号(bvalid) 。直到接收逻辑通过置位 bload 信号确认应该加载数据后,才实际加载数据。在加载数据之前,没有反馈到发送时钟域,然后将b_ack信号发送回,与具有自动反馈的 MCP 公式相同。
我的理解:接收方有 ready 信号和 bload 信号,发送方有 valid 信号,当 ready 信号和 valid 信号同时为高时,将 bload 信号拉高,表示可以将数据加载到接收方,接收方加载完数据后,回传 b_clk 信号给发送端。
这是一条反馈路径,要求接收时钟域在捕获数据和发送反馈之前采取行动。
同步计数器
如前所述,在时钟域之间传递多个信号时,要问的一个重要问题是,我是否需要对从一个时钟域传递到另一个时钟域的信号的每个值进行采样?对于计数器,答案通常是,不!
《Simulation and Synthesis Techniques for Asynchronous FIFO Design》这篇文献详细介绍了 FIFO 设计技术,其中格雷码计数器在时钟域之间进行采样,而中间格雷计数值经常被遗漏。对于这种 FIFO 设计,更多的考虑是确保计数器不会超出其边界,这可能会导致错过满标志和空标志检测。尽管时钟域之间的采样格雷码计数值经常被遗漏,但该设计是稳健且保守的,并且所有重要的格雷码计数值都被适当地采样。
由于可能允许有效设计跳过一些计数值样本,因此是否可以使用任何计数器跨 CDC 边界传递计数值?答案是:不可以。
二进制计数器
二进制计数器的一个特点是所有顺序二进制递增操作的一半需要两个或更多计数器位必须改变。尝试跨CDC 边界同步二进制计数器与尝试将多个 CDC 信号同步到新的时钟域相同。如果一个简单的 4 位二进制计数器从地址 7(二进制 0111)更改为地址 8(二进制 1000),则所有四个计数器位将同时更改。如果同步时钟边沿出现在该转换的中间,则任何 4 位二进制模式都可能被采样并同步到新的时钟域中,如下图所示。
在 FIFO 设计中,新的同步二进制值可能会触发错误的满或空标志,或者更糟糕的是,它可能不会触发真正的满或空标志,从而导致数据由于 FIFO 溢出而丢失,或者由于FIFO 真的是空的,尝试读取数据而导致从 FIFO 中读取无效数据。
格雷码
格雷码以 Frank Gray 和可用于多时钟的最安全计数器命名设计是格雷码计数器。格雷码只允许每个时钟改变一位过渡,消除了与尝试同步多个变化的 CDC 相关的问题跨时钟域的位。
标准格雷码具有非常好的翻译属性,可以将格雷码转换为二进制并返回再次。使用这些转换,设计高效的格雷码计数器很简单。
格雷码到二进制的转换
使用 n 位格雷码值将格雷码值转换为等效的二进制码值,例如,二进制位 0 等于格雷码位 0 的异或与所有从 1 到 n 的其他格雷码位。二进制位 1 等于格雷码位 1 与所有位异或其他格雷码位从 2 到 n 等。最高有效二进制位正好等于最重要的格雷码位。计算方法如下图所示。
也可以这么计算:二进制的最高位等于格雷码的最高位,二进制的次高位等于格雷码的次高位与二进制的最高位异或得到,以此类推,如下图所示。
编写格雷码到二进制转换器的最简单方法是编写 for 循环并执行异或,减少具有可变索引范围的格雷码向量,其中每次通过循环索引范围的 LSB 会增加,直到我们得到一个简单的 bin[MSB] = ^gray[MSB:MSB](只是格雷码向量的 1 位 MSB),如示例 1 所示。
不幸的是,Verilog 和 SystemVerilog 不允许使用可变索引范围进行部分选择,所以示例 1 中的代码虽然在概念上是正确的,但无法编译。
为了解决这个问题,请记住异或门实际上是一个可编程的反相器。如果一个输入连接高电平,另一个输入反相并传递到输出。同样,如果一个输入被拉低,另一个输入被传递到输出而不反相(从输入到没有变化输出)。
利用任何数与 0 进行异或操作结果不变的原理,格雷码到二进制转换的方法是异或具有填充 0 的有效格雷码位,如下图所示。
此简化算法的相应参数化 SystemVerilog 模型显示在下面的示例中,利用 for 语句对格雷码依次右移计算,这个示例在语法上是正确的,可以编译并且可以工作。
输入绑定为 0 的所有额外异或操作会发生什么?综合工具认识到在一个输入上具有常数 0 的异或门可以优化掉以推断出设计的非常有效的实施。
二进制到格雷码的转换
要将二进制值转换为等效的格雷码值,使用 n 位二进制值作为例如,格雷码位 0 等于二进制位 0 和 1 的异或结果。格雷码位 1 是等于二进制位 1 和 2 的异或结果。最高有效的格雷码位是等于最高有效二进制位。如下图所示。
编写二进制到格雷码转换器的最简单方法是编写一个简单的连续赋值,将二进制右移一位与原来的二进制数执行按位异或运算,如下示例所示。这个例子在语法上是正确的,可以编译并且可以工作。
格雷码计数器样式#1
我们可以使用前面中展示的转换来构建格雷码计数器。对于任何格雷码计数器,重要的是要记住必须寄存格雷码输出以消除设计中的任何组合稳定。
格雷码计数器样式 #1 的 SystemVerilog 代码包含一个格雷码到二进制转换器、一个二进制到格雷码转换器,并在转换之间递增二进制值,如下图所示。
下面的示例显展示了格雷码计数器样式 #1 的相应参数化 SystemVerilog 模型。
先对格雷码转换成二进制,再对二进制+1,然后再将二进制转换成格雷码,便可以得出下一个格雷码的值。
格雷码计数器样式#2
我们可以只使用二进制到格雷码的转换来构建第二种格雷码计数器,如前面所述。这个格雷码计数器实际上是一个二进制计数寄存器和格雷码计数寄存器。
格雷码计数器样式#2 的 SystemVerilog 代码包含一个二进制计数器以消除需要进行格雷码到二进制的转换,并使用下一个二进制计数值进行二进制到格雷码的转换,然后将其寄存到格雷码寄存器中。这种风格使用了两倍的触发器,但生成下一个格雷码值的组合逻辑路径更短,这使得该实现比格雷码计数器样式#1更快。格雷码计数器样式#2 的框图如上图所示。
以下示例展示了格雷码计数器样式 #2 的相应参数化 SystemVerilog 模型。
其他多位 CDC 技术
除了前面章节中描述的 MCP 制定技术之外,我还发现许多工程师使用标准 FIFO 在时钟域之间传递数据和控制信号。
有两种 FIFO 实现策略可用于解决多位 CDC 信号完整性问题:
(1) 异步 FIFO 实现。
(2) 2‑deepFIFO 实现。
使用异步 FIFOS 传递多位 CDC 信号
传递多个位,无论是数据位还是控制位,都可以通过异步 FIFO 完成。异步 FIFO 是共享内存或寄存器缓冲区,其中数据从写时钟域写入,数据从读时钟域中读出。由于发送器和接收器都在各自的时钟域内运行,因此使用双端口缓冲器(例如 FIFO)是在时钟域之间传递多位值的安全方法。
标准异步 FIFO 设备允许在 FIFO 未满时插入多个数据或控制字,只要 FIFO 不为空,接收器便可以在方便时提取多个数据或控制字。
FIFO 设计中的大部分艰苦工作是通过格雷码计数器的同步完成的,并且在此前提到的文献中描述了一种经过验证的 FIFO 设计技术。
使用 1‑deep/2‑register FIFO 同步器传递多位 CDC 信号
跨 CDC 边界传递多个控制和数据位的另一个有趣变化涉及使用深度为 1 的两个寄存器 FIFO,如下图所示。
这个深度为 1 的两个寄存器 FIFO 有许多有趣的特性。由于 FIFO 仅使用两个寄存器或深度为 2 的双端口 RAM 构建,用于检测满和空的格雷码计数器是简单的触发器,实际上只不过是 1 位二进制计数器(请记住,标准格雷码的 MSB 与二进制码的 MSB 相同)。
复位时,两个指针都被清除,FIFO 为空,因此 FIFO 未满。我们使用反转的未满条件来指示 FIFO 已准备好接收数据或控制字( wrdy 为高电平)。在将数据或控制字放入 FIFO(使用 wput )后, wptr 切换并且 FIFO 变满,或者换句话说, wrdy 信号变为低电平,这也禁用了切换 wptr 的能力,因此也禁用了能够将另一个字放入 2 寄存器 FIFO,直到接收时钟域逻辑从 FIFO 中读出第一个字。
这个设计特别有趣的是 wptr 现在指向 2 寄存器 FIFO 中的第二个位置,所以当 FIFO 再次准备好时(当 wrdy 为高时), wptr 已经指向下一个位置写。
在 FIFO 的接收端复制相同的概念。当数据或控制字写入 FIFO 时,FIFO 变为非空。我们使用反相非空条件来指示 FIFO 有准备好接收的数据或控制字( rrdy 为高电平)。
通过使用两个寄存器来存储多位 CDC 值,我们能够从发送 MCP 公式中删除一个时钟周期,并从确认反馈路径中删除另一个周期。
说明
本文是对《Clock Domain Crossing (CDC) Design & Verification Techniques Using SystemVerilog》的文章的翻译及部分说明解释
往期系列博客
【CDC 系列】跨时钟域处理(二)快时钟域信号同步到慢时钟域