个人导航网站:yun916831.github.io
第1章 在时钟域之间传递多bit信号
在时钟域之间传递多bit信号时,简单的同步器并不能保证数据的安全传输。
工程师在进行多时钟设计时经常犯的一个错误是将同一事务中所需的多个 CDC 位从一个时钟域传递到另一个时钟域,而忽视了 CDC 位同步采样的重要性。
问题是同步到一个时钟的多bit信号会经历小的数据变化偏斜(skews),偶尔会在第二个时钟域的不同时钟上升沿上采样。即使我们可以完美地控制和匹配多个信号的走线长度,上升和下降时间的差异以及芯片上的工艺变化可能会引入足够的偏斜,从而导致对原本精心匹配的走线的采样失败。
所以必须采用多位CDC策略来避免多bit的偏斜采样。
多bit信号的CDC问题主要来自信号之间的skew(简单地理解为到达目的时钟域的时间无法控制一致),可能的后果就是某些bit可能还没到达,但是某些bit已经被采样了。
1.1 多bit CDC策略
为了避免多bit CDC偏斜采样情况,我将多位bit CDC策略分为三大类:
(1) 多bit信号合并。在可能的情况下,将多个 CDC 位合并为 1 位 CDC 信号。
(2) 多循环路径公式。使用同步负载信号安全地传递多个CDC位。
(3) 使用格雷码传递多个 CDC 位。
1.2 多bit 信号合并
在可能的情况下,将多个 CDC 信号合并为一个 1 位 CDC 信号。问问自己这个问题,我真的需要多个位来控制跨 CDC 边界的逻辑吗?
如以下示例所示,简单地在所有 CDC 位上使用同步器并不总是足够好。 如果控制信号的顺序或对齐很重要,则必须注意将信号正确传递到新的时钟域。
1.3 问题—同时需要两个控制信号
在图 12 所示的简单示例中,接收时钟域中的寄存器需要加载信号和使能信号,以便将数据值加载到寄存器中。如果负载和使能信号在同一发送时钟边沿上驱动,则控制信号之间的小偏差可能会导致两个信号在接收时钟域内同步到不同的时钟周期。在这些条件下,数据不会被加载到寄存器中。
在这个示例中,需要2bit信号来做逻辑控制。跨时钟域传输这2bit信号的过程中,由于信号到达目的时钟域的时间不一致(存在skew),导致2个信号无法在同一个时钟周期进行采样造成了数据漏采,从而使得预期功能无法实现。
Figure 12 - Problem - Passing multiple control signals between clock domains
1.3.1 解决方案—整合
如图 13 所示,仅从一个加载启用信号驱动接收时钟域中的加载和启用寄存器输入信号。合并将消除两个及时转移到达的控制信号的可能性。 把控制信号合并不失为一个好办法。
Figure 13 - Solution - Consolidating control signals before passing between clock domains
1.4 问题—两个相位偏差的控制信号
图 14 中的图表显示了两个使能信号 aen1 和 aen2,它们依次从发送时钟域驱动到接收时钟域,以控制流水线数据寄存器的使能输入。问题是在第一时钟域,aen1控制信号可能在aen2控制信号产生前稍稍终止,在aen1和aen2控制信号脉冲之间的微小间隙中可能出现接收时钟的上升沿,导致在接收时钟域的使能控制信号链中形成一个周期间隙。这将导致第二个寄存器丢失 a2 数据值。
Figure 14 - Problem - Passing sequential control signals between clock domains
1.4.1 解决方案—合并和额外的触发器
上图需求是延迟的控制信号分别控制目标时钟域的2个寄存器,那么可以修改为在原时钟域进行控制信号融合,然后在目标时钟域打两拍,输出信号控制1个寄存器,再打一拍输出延迟信号控制另一个寄存器,如下图所示:
Figure 15 - Solution - Logic to generate proper sequencing signals in the new clock domains
1.5 问题—多bit CDC 信号
图16显示了在时钟域之间传递的两个编码控制信号。如果两个编码信号在采样时略微偏斜,则可能会在接收时钟域中的一个时钟周期内生成错误的解码输出。
Figure 16 - Problem - Encoded control signals passed between clock domains
1.5.1 传递多个CDC信号的解决方案
多循环路径 (MCP) 公式和 FIFO 技术可用于解决与传递多个 CDC 信号相关的问题。
Figure 17 - Logic to pass a synchronized enable pulse between clock domains
1.6 多循环路径 (MCP) 公式
1.7 同步计数器
如前所述,在时钟域之间传递多个信号时,要问的一个重要问题是,我是否需要对从一个时钟域传递到另一个时钟域的信号的每个值进行采样?对于这种情况,答案经常是,不!
格雷码计数器在时钟域之间采样,而中间格雷码计数值经常被遗漏。对于这种 FIFO 设计,更多的考虑是确保计数器不会超出其边界,这可能导致错过满和空标志检测。即使时钟域之间的采样格雷码计数值经常被遗漏,该设计也是稳健的,并且所有重要的格雷码计数值都被适当地采样。
1.7.1 二进制计数器
二进制计数器的一个特点是,所有连续二进制递增操作中有一半要求必须更改两个或更多计数器位。尝试跨 CDC 边界同步二进制计数器与尝试将多个 CDC 信号同步到新的时钟域中是一样的。如果一个简单的 4 位二进制计数器从地址 7(二进制 0111)更改为地址 8(二进制 1000),则所有四个计数器位将同时更改。如果同步时钟边沿出现在此转换的中间,则任何 4 位二进制模式都可能被采样并同步到新的时钟域中,如图 23 所示。
Figure 23 - Binary count values sampled in mid-transition
在 FIFO 设计中,新的同步二进制值可能会触发错误的满或空标志,甚至更糟的是,它可能不会触发真正的满或空标志,从而导致数据因 FIFO 而丢失 。当 FIFO 真的为空时,由于尝试读取数据而导致溢出或导致从 FIFO 读取无效数据。
1.7.2 格雷码到二进制转换
将格雷码值转换为等效的二进制码值,以n位格雷码值为例,二进制位0等于格雷码位0的异或与所有其他格雷码的异或位从 1 到 n。二进制位 1 等于格雷码位 1 与从 2 到 n 等所有其他格雷码位的异或运算。最高有效的二进制位刚好等于最高有效的格雷码位。
bin[0] = gray[3] ^ gray[2] ^ gray[1] ^ gray[0];
bin[1] = gray[3] ^ gray[2] ^ gray[1];
bin[2] = gray[3] ^ gray[2];
bin[3] = gray[3];
编写格雷码到二进制转换器的最简单方法是编写一个 for 循环并对具有可变索引范围的灰度代码向量进行异或约简,其中每次通过循环,索引范围的 LSB 都会增加,直到我们只剩下 bin[MSB] = 的简单赋值 ^gray[MSB:MSB](只是格雷码向量的 1 位 MSB),如示例 1 所示。
module gray2bin_bad
#(parameter SIZE = 4)
(
output logic [SIZE-1:0] bin,
input logic [SIZE-1:0] gray
);
// Syntax Error - variable index range always_comb
for (int i=0; i<SIZE; i++)
bin[i] = ^(gray[SIZE-1:i]);
endmodule
不幸的是,Verilog 和 SystemVerilog 不允许使用可变索引范围进行部件选择,因此示例 1 中的代码虽然在概念上是正确的,但不会编译。
为了解决这个问题,请记住异或门实际上是一个可编程反相器。如果一个输入被拉高,另一个输入被反相并传递到输出。类似地,如果一个输入被拉低,另一个输入被传递到输出而不反转(从输入到输出没有变化)。
利用任何涉及 0 输入的添加异或运算不会改变运算结果的事实,格雷码到二进制转换的方法是异或有效的格雷码位带有填充的 0,如图 25 所示。
bin[0] = gray[3] ^ gray[2] ^ gray[1] ^ gray[0] ; // gray>>0
bin[1] = 1'b0 ^ gray[3] ^ gray[2] ^ gray[1] ; // gray>>1
bin[2] = 1'b0 ^ 1'b0 ^ gray[3] ^ gray[2] ; // gray>>2
bin[3] = 1'b0 ^ 1'b0 ^ 1'b0 ^ gray[3] ; // gray>>3
此简化算法的相应参数化 SystemVerilog 模型如示例 2 所示。此示例在语法上是正确的,可以编译并且可以正常工作。
module gray2bin #
(parameter SIZE = 4)
(
output logic [SIZE-1:0] bin,
input logic [SIZE-1:0] gray
);
always_comb
for (int i=0; i<SIZE; i++)
bin[i] = ^(gray>>i);
endmodule
输入绑定到 0 的所有额外的异或运算会发生什么?综合工具认识到,可以优化一个输入上具有常数 0 的异或门,以推断设计的非常有效的实现。
1.7.3 二进制到格雷码的转换
将二进制值转换为等效的格雷码值,以n位二进制值为例,格雷码位0等于二进制位0和1的异或。格雷码位1等于到二进制位 1 和 2 的异或等。最高有效的格雷码位刚好等于最高有效的二进制位。
示例 4 位二进制到格雷码转换的方程式如图 26 所示。
gray[0] = bin[0] ^ bin[1];
gray[1] = bin[1] ^ bin[2];
gray[2] = bin[2] ^ bin[3];
gray[3] = bin[3] ^ 1'b0 ; // same as gray[3] = bin[3];
编写二进制到格雷码转换器的最简单方法是编写一个简单的连续赋值,该赋值在二进制向量和相同二进制向量的右移版本之间执行按位异或运算,如图所示 示例 3。这个示例在语法上是正确的,可以编译并且可以工作。
module bin2gray #(parameter SIZE = 4)
(
output logic [SIZE-1:0] gray,
input logic [SIZE-1:0] bin
);
assign gray = (bin>>1) ^ bin;
endmodule
1.7.4 格雷码计数器样式 #1
格雷码计数器样式 #1 的 SystemVerilog 代码包含一个格雷码到二进制转换器、一个二进制到格雷码转换器并在转换之间递增二进制值,如图 27 所示。
Figure 27 - Gray code counter style #1 - only one gray code register
module graycntr #(parameter SIZE = 5)
(output logic [SIZE-1:0] gray,
input logic clk,
inc,
rst_n);
logic [SIZE-1:0] gnext, bnext, bin;
always_ff @(posedge clk or negedge rst_n)
if (!rst_n) gray <= '0;
else gray <= gnext;
always_comb begin
for (int i = 0; i<SIZE; i++)
bin[i] = ^(gray>>i);
bnext = bin + inc;
gnext = (bnext>>1) ^ bnext;
end
endmodule
1.7.5 格雷码计数器样式 #2
我们可以仅使用第 5.7.4 节中显示的二进制到格雷码转换来构建第二种样式的格雷码计数器。这个格雷码计数器实际上既是一个二进制计数寄存器又是一个格雷码计数寄存器。
Figure 28 - Gray code counter style #2 - binary register and gray code register
用于格雷码计数器样式 #2 的 SystemVerilog 代码包含一个二进制计数器以消除格雷码到二进制转换的需要,并使用下一个二进制计数值进行二进制到格雷码转换,然后将其寄存到格雷码中。这种风格使用两倍数量的触发器,但生成下一个格雷码值的组合逻辑路径更短,这使得这种实现比格雷码计数器样式 #1 更快。
module graycntr #(parameter SIZE = 5)
(output logic [SIZE-1:0] gray,
input logic clk,
full,
inc,
rst_n);
logic [SIZE-1:0] gnext, bnext, bin;
always_ff @(posedge clk or negedge rst_n)
if (!wrst_n) {bin, gray} <= '0;
else {bin, gray} <= {bnext, gnext};
assign bnext = !full ? bin + inc : bin;
assign gnext = (bnext>>1) ^ bnext;
endmodule
1.8 其他多bit CDC 技术
1.8.1 使用异步 FIFO 的多位 CDC 信号传递
传递多个位,无论是数据位还是控制位,都可以通过异步 FIFO 来完成。异步 FIFO 是共享存储器或寄存器缓冲区,其中数据从写时钟域插入,数据从读时钟域移除。由于发送方和接收方都在各自的时钟域内运行,因此使用双端口缓冲器(例如 FIFO)是在时钟域之间传递多位值的安全方式。
只要FIFO未满,标准异步FIFO设备就允许插入多个数据或控制字,只要FIFO不为空,接收器然后在方便时提取多个数据或控制字。
1.8.2 使用 1-deep/2-register FIFO 同步器的多位 CDC 信号传递
跨 CDC 边界传递多个控制位和数据位的另一个有趣变化涉及使用1 深度双寄存器FIFO,如图 29 所示。
Figure 29 - 1-deep / 2-register FIFO synchronizer block diagram
由于 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 公式中删除一个时钟周期,并从确认反馈路径中删除另一个周期。
第2章 总结
CDC问题是芯片失败的最常见的问题之一,弄清楚CDC方法也是芯片设计的最重要的事情。常见的CDC方法总结如下:
推荐的1-bt CDC技术:
慢时钟到快时钟:同步器;
快时钟到慢时钟:MCP方法
推荐的multi-bit CDC 技术:
多个信号合成一个信号。
MCP方法(其实用的很少,但是设计思想很好)
AFIFO
2-Depth AFIFO
参考:Clock Domain Crossing (CDC) Design & Verification Techniques Using SystemVerilog
https://zhuanlan.zhihu.com/p/359327167
https://wuzhikai.blog.csdn.net/article/details/122874278
https://www.cnblogs.com/lyc-seu/p/12441366.html
标签:bin,gray,格雷,CDC,FIFO,传递,bit,时钟 From: https://www.cnblogs.com/superego-zhang/p/17499504.html