Clock Domain Crossing (CDC) Design & VerificationTechniques Using SystemVerilog(Part Ⅱ)

105 篇文章 13 订阅
本文详细讨论了在数字设计中处理时钟域交叉(CDC)的重要性和方法,包括采用命名约定来标识时钟源,设计分区以简化时序验证,以及使用同步器来避免建立和保持时间违规。文中还提到了门级仿真中遇到的X传播问题及其解决方案,如使用多个SDF文件和特定的Synopsys命令。此外,文章强调了验证工具和良好的编码实践在确保无错误的多时钟设计中的关键作用。
摘要由CSDN通过智能技术生成

6.0 Naming conventions & design partitioning(命名约定和设计分区)
        命名约定有助于确保良好的团队沟通,也有助于使用脚本语言来收集和分组设计中与特定时钟相关的所有信号。良好的设计分区可以显著减少综合和验证多时钟设计的时序的工作量。
        本节将讨论推荐的命名约定和设计分区。有两种方法可以解决CDC的潜在问题:
(1) 验证设计符合合格的CDC规则,
(2) 避免这个问题。这两种方法都很有价值,应该用于确保无错误的设计。
        第一种方法是验证CDC的设计规则,通常需要使用特殊工具来检查设计是否可能违反CDC的规定。
        有许多公司提供此类工具(有关CDC验证的公司和工具列表,请参见[11])。第二种方法,避免这个问题,可以通过使用下面概述的一些好的编码准则来实现。
6.1 Clock & signal naming conventions(时钟和信号命名约定)
        各种设计团队已经使用了许多有用的时钟和信号命名约定。
        指南:使用时钟命名约定来识别设计中每个信号的时钟源。
        原因:命名约定有助于所有团队成员识别设计中每个信号的时钟域,还可以使用综合脚本中的正则表达式“wild-carding”更容易地对信号进行分组以进行时序分析。一个经过验证的命名约定要求使用前导前缀字符来识别各种异步时钟域。
        示例包括:用于微处理器时钟的uClk,vClk用于视频时钟,dClk用于显示时钟。
然后将每个信号同步到设计中的一个时钟域,并且用前缀字符标记每个信号名称以标识用于生成该信号的时钟域。例如由uClk生成的任何信号在信号名称中被标记有u前缀,例如uaddr、udata、uwrite等。由vClk生成的任何信号在信号名称中类似地标记有v前缀,例如vdata、vhsync、vframe等。
        相同的信号命名约定用于由设计中的任何其他时钟生成的所有信号。
        使用这项技术,设计团队中的任何工程师都可以很容易地识别设计中任何信号的时钟域源,并直接使用信号或通过适当的同步传递信号,以便在新的时钟区域内使用信号。确切的命名约定并不重要,但至关重要的是,项目中的每一位工程师都同意遵守团队选择的命名约定。命名约定将大大提高设计团队的生产力。
6.1.1 Multi-clock / multi-source modules with no naming convention(无命名约定的多时钟/多源模块)
        如果您的团队不使用任何特定的面向时钟的信号命名约定,并且允许模块具有多个时钟输入,那么CDC分析工具总是有可能无法正确设置,并且很容易错过糟糕的CDC设计实践。
        即使您的团队可以使用良好的CDC分析工具,我强烈建议您采取一些简单的步骤,使潜在CDC设计问题的分析和识别更容易识别和调试。
6.2 Timing verification for each clock domain(每个时钟域的定时验证)
        要验证任何设计的时序,必须验证设计中每个时钟域都满足该时序。尽管在过去的十年里,工具已经得到了改进,有助于自动化单独时钟域中信号的分析和验证,但使用良好的分区和命名约定来进行多块设计仍然是一种很好的做法。通过将设计划分为每个模块只允许一个时钟,静态时序分析对于设计中的每个领域来说都变得非常容易。
6.3 Clock oriented design partitioning(面向时钟的设计分区)
        一些最简单和最好的设计分区方法是使用时钟边界的设计分区来实现的。
指南:每个模块只允许使用一个时钟[9]。
原因:静态时序分析和创建综合脚本更容易在单个时钟模块或单个时钟模块组上完成。
例外:将来自所有不同时钟域的信号连接在一起的顶级模块自然会将所有时钟作为该模块的输入。最大限度地减少您的多时钟验证工作,只允许顶部模块有多个时钟输入。
指导方针:将设计块划分为一个时钟模块。
原因:使用STA(静态时序分析)工具可以很容易地验证完全同步子块的时序验证,并将设计块划分为多个单时钟域子块,将大型复杂的时序分析任务转变为多个完全同步的单时钟设计。
指南:创建同步器模块,将信号从一个时钟域传递到另一个时钟域,并且每个同步器模块只允许一个时钟。
原因:假设任何信号从一个时钟域传递到另一个时钟域,最终都会遇到setup和hold时间问题。
隔离CDC边界逻辑可以显著减少多时钟设计的设计和验证工作量。
        在大多数情况下,同步器模块将是设计中唯一会经历setup和hold时间冲突的块。当在异步时钟域之间传递信号时,会出现定时冲突,这就是必须在设计中添加同步器的全部原因。


                                                图30-按时钟边界划分的设计
        考虑一个具有三个时钟域的示例设计,标记为aClk、bClk和cClk,如图30所示。在该设计中,所有aClk设计块都被分组为一个aClk逻辑块。所有的bClk设计块都被分组到一个bClk逻辑块中,类似地,我们创建了一个cClk逻辑模块。任何源自异步时钟域的信号在被允许驱动另一逻辑块的输入之前都要经过同步器模块。
6.3.1 Timing analysis of clock-partitioned modules(时钟分区模块的时序分析)
        使用面向时钟的设计分区策略,每个设计块的所有输入和输出都与一个时钟完全同步。这是使用静态时序分析(STA)工具验证的最简单的设计类型,因为设计中没有错误路径。将在每个时钟域内计时的所有设计模块分组在一起。在设计中,应为每个时钟域形成一个组。将对这些组进行时间验证,就好像每个组都是单独的、完全同步的设计一样。
        对于每个时钟域,我们有一个单独的设计块,我们可以轻松地执行最坏情况(最大时间/setup时间检查)的时序分析,以及最佳情况(最小时间/hold时间检查)时序分析。同样使用这种面向时钟的分区策略,每个CDC边界都使用同步器模块进行了隔离。每个同步器模块仅包括ASIC或FPGA供应商(优选)提供的同步器单元,或者使用成对连接的触发器来构建以形成同步器等效单元。
        如果同步器单元可从ASIC或FPGA供应商处获得,并实例化到设计中,则无需验证这些模块上的setup和hold时间,因为供应商应该已经创建了不违反触发器级之间的setup或hold时间的单元布局。
        如果同步器是从RTL码综合的,则最重要的是执行最佳情况时序分析,以确保触发器不会以第一级的输出可能变化太快而无法满足第二级的输入的hold时间要求的方式放置得太近。
        同样也应该进行最坏情况下的时序分析,以防布局工具碰巧将两个同步器触发器放在ASIC或FPGA芯片上相距很远
由于独立同步器的分区,门级仿真可以更容易地配置为忽略每个同步器第一级的setup和hold时间违规
        RTL同步器的静态时序分析需要简单的set_false_path命令来从STA移除输入。我们知道同步器的输入端存在定时问题,这就是使用同步器的原因。通过划分设计和同步器块,每个模块只允许一个时钟,静态时序分析变得非常容易执行。用于解决多个时钟域问题的综合脚本命令现在变成了分组、识别错误路径和执行最小-最大时序分析的问题。
6.4 Partitioning with MCP formulations( MCP方案的分配)
        将时钟边界处的设计划分为单独的设计块和同步器块在大多数情况下都能很好地工作,但如果需要使用MCP方案在时钟域之间传递多个信号,那么传递到设计块的一些信号可能来自不同的时钟域,如图31所示。

                                                图31-MCP方案的分区设计
        如果在设计中对信号使用了基于时钟的命名约定,那么具有异步输入的设计块仍然可以很容易地计时。在对有问题的设计块执行STA之前,只需从分析中排除异步输入即可。通常,只有同步器和MCP方案数据路径的输入需要“set_false_path”命令。如果使用时钟前缀命名方案,则可以使用通配符来轻松识别所有异步输入。在图31中,要将adata总线从bClk逻辑块内的STA中排除,请首先执行以下命令:

set_false_path -from { a* }

 该命令应足以消除bClk STA的所有异步输入。

7.0 Multi-clock gate-level simulation issues(多时钟门级仿真问题)
        当同步器识别到CDC信号上的建立和保持时间违规时,数字仿真模型通常会生成X。这经常会导致门级仿真失败。有什么技术可以解决这个问题?如第6.3.1节所述,通过同步器跨越时钟边界的信号将经历建立和保持违规。这就是为什么在设计中添加了同步器,以滤除在接收时钟域时钟信号的上升沿附近变化的信号的亚稳态效应。
7.1 Synchronizer gate-level CDC simulation issue(同步器门级CDC仿真问题)
        当在多时钟设计上进行门级仿真时,触发器的ASIC库模型用建立和保持时间表达式来建模,以匹配实际触发器的时序规范。ASIC库通常对触发器进行建模,以在发生时序违规时驱动触发器输出上的X(未知)。当仿真门级同步器时,建立和保持时间冲突可能会导致ASIC库发出建立和保持时错误消息,并且冲突信号经常被驱动到X值。如图31所示,当试图验证整个门级设计的功能时,这些X值会传播到设计的其余部分,从而导致问题

                                        图32-同步器门级CDC仿真波形
7.2 Strategies to remove X-propagation from gate-level simulations(从门级仿真中消除X传播的策略)
   
  有许多策略,以解决每次信号违反同步器第一级的设置或保持时间时X的不必要传播相关的问题。
        由于当违反setup或hold时间时会发生X传播,因此几乎所有解决此问题的方法都涉及将setup和hold时间更改为0,这样就不会违反setup或保留时间,因此也不会发生X传播。有些方法不好,有些方法好。以下是为解决X传播问题而考虑的一些策略。
7.2.1 Simulator command to turn off timing checks(关闭时序检查的仿真器命令)
       
 大多数SystemVerilog模拟器都有一个忽略所有定时检查的命令选项,但这也会忽略设计其余部分所需的定时检查。
7.2.2 Change flip-flop setup and hold times to 0(将触发器setup和hold时间更改为0)
        
可以将同步器中使用的任何ASIC库触发器的设置和保持时间设置更改为零,但这将导致同一类型触发器的所有实例的所有setup和hold时长检查都设置为零,包括您可能想用来测试其余设计的触发器。
7.2.3 Copy and modify new flip-flop models(复制和修改新的触发器模型)
        您可以从ASIC库中复制触发器,并将其存储到具有不同名称的新SystemVerilog库中,将所有设置和保持时间设置为零,然后修改设计门级网表,用修改后的库触发器替换所有第一级同步器ASIC库触发器,而无需定时检查, 但这可能是一个容易出错且乏味的过程,每次生成新的网表时都必须重复,或者每次生成新网表时可能需要创建makefile和脚本来自动进行修改。
7.2.4 Synopsys set_annotated_check command( Synopsys set_annoted_check命令)
        Bhatnagar[5]提出的解决这个问题的一种有用方法是使用Synopsys命令来修改设计中仅第一级触发器单元上的setup和hold时间的SDF反向注释。Bhatnagar指出,SDF文件是基于实例的,因此更容易实现针对违规单元的setup和hold时间。
        Bhatnagar指出:与其手动从SDF文件中删除setup和hold时间结构,更好的方法是将SDF文件中的setup和hold时间清零,只针对违反的触发器,即用零替换现有的setup和hold时间
Bhatnagar进一步指出,setup和hold时间为零意味着不可能有时间冲突,因此不会有未知因素传播到设计的其余部分。Bhatnagar给出的以下dc_shell-t命令用于使setup和hold时间为零:

set_annotated_check 0 -setup -hold -from REG1/CLK -to REG1/D

        对同步器的第一级触发器的输出使用创造性的命名约定可以使通配符表达式能够容易地对所有第一级触发器SDF设置进行后注释,并使用很少的dc_shell-t命令将时间值保持为零。如果使用Synopsys DesignCompiler工具进行设计,则此技术有效,但非Synopsys流如何?
7.3 Additional strategies to remove X-propagation(消除X传播的其他策略)
        在最初的演示之后,许多工程师站出来分享了从门级模拟中消除X传播的额外技术。至少有三家公司的工程师对这项技术的描述与第###节中的描述非常相似(向参加圣何塞SNUG-2001的工程师致敬)。
        从那时起,许多公司的其他工程师分享了额外的技术。这些技术将在本节中进行描述,我非常感谢所有的工程师,他们每年都会继续与我分享有趣的技术。为你们所有人喝彩!
7.3.1 Use multiple SDF files(使用多个SDF文件)
         消除不需要的X传播的关键是强制同步器输入的setup和hold时间为0,从而消除同步器输入上所有可能的setup和hold时间违规。许多工程师告诉我,他们实际上生成了两个SDF文件。
        第一个SDF文件具有整个设计的所有实际延迟,包括准确的setup和hold时间。然后,工程师生成第二个SDF文件,该文件中只包含第一级触发器。在此文件中,setup和hold时间设置为0。一些工程师手工构建这个文件,另一些则使用脚本生成这个文件。
        然后,工程师使用$SDF_annotate命令读入第一个SDF文件。然后,他们读取第二个SDF文件,该文件覆盖第一级同步器数据输入的setup和hold时间读入两个SDF文件时,每个实例的最后一个SDF文件获胜。对所有时序进行了精确注释,然后修改了第一级同步器的时序检查。这是一种聪明的技术,可以与生成SDF文件的任何工具流一起使用。
7.3.2 Vendor synchronizer cell with supporting SDF generation tools(带有支持SDF生成工具的供应商同步单元)
        其他工程师已经介绍了解决X传播问题的好方法,但该方法需要(a)控制单元库,或(b)与ASIC供应商建立良好的工作关系。
        该技术要求在两个触发器级之间创建具有适当放置关系的单独同步器单元。要使这种方法发挥作用,供应商必须提供:
(1) 实际的同步器单元-这些将被纳入设计中。
(2) 用于仿真的同步器单元的SystemVerilog模型。
(3) SDF文件生成工具,用于为同步器单元生成具有0-setup和0-hold的SDF文件。
        如果供应商可以提供此单元和这些功能,则只需要生成一个SDF文件,并对同步器单元进行适当的时序检查。任何提供这种功能的FPGA供应商的ASIC都为他们的客户群带来了巨大的好处。
我听说一些ASIC供应商提供了这种功能。我不知道有哪家FPGA供应商提供这种功能。认识到大多数现代设计是多时钟设计,我强烈敦促所有ASIC甚至所有FPGA供应商为同步器单元提供适当的仿真和SDF文件工具支持。

7.4 Multiple SDF files for gate-level CDC simulations(门级CDC仿真的多个SDF文件)
        在门级模拟中解决X传播问题的技术:该技术包括写出完整的SDF时序文件,然后手动或使用脚本,仅为所有同步器模块的第一级触发器生成第二个SDF文件。第二个SDF文件将所有setup和hold时间设置为0,然后使用$SDF_annotation命令将两个SDF文件应用于设计。第一个SDF文件注释整个设计的所有实际时序,然后读取第二个SDF文件以覆盖第一级同步器。这种技术的优点是,它可以用于使用所有工具的所有设计,而不仅仅是Synopsys ASIC设计。这是一种强烈推荐的技术。
7.5 Force synchronizer notifier inputs to a fixed value(强制同步器通知器输入固定值)
        Verilog和SystemVerilog的setup和hold时间检查($setup、$hold和$setuphold)的内置定时检查具有可选的通知器输出。每当检测到时序违规时,该通知器输出从0-1-XZ切换。
        大多数ASIC和FPGA触发器模型都是由Verilog用户定义原语(UDP)构建的,并且通知信号通常被列为UDP表的输入之一。
        无论何时通知器输入切换(由时序违规引起),触发器输出都是未知的,而该未知是在门级触发器模型的输出上可见的。这些第一级触发器模型上的通知器可以被强制到逻辑电平,以防止它们在仿真期间切换并导致触发器输出变为未知。
        至少有一家公司使用的一种聪明的技术迫使第一级同步器触发器的时序违规通知器被强制到一个逻辑电平,这样它们就永远不会在触发器模型中切换和触发X。
7.6 ASIC & FPGA library cell synchronizers( ASIC和FPGA库单元同步器)
        如果ASIC和FPGA提供商提供可以实例化到设计中的完全表征的同步器单元,那么它们可以使CDC设计变得更容易。高级ASIC供应商提供:
(1) 特征化的同步器单元。
(2) Verilog模型来模拟同步器单元。
(3) SDF生成器生成SDF文件,该SDF文件将同步器单元上的setup和hold时间注释为0以避免当信号在跨越CDC边界时违反setup或hold时间时的X生成
7.7 Simulation model with random delay insertion(具有随机延迟插入的仿真模型)
        多位同事提出了一个有趣的模型,该模型综合了正确的同步器进行设计,但使用随机循环延迟进行模拟。该模型的框图如图33所示,支持该模型的SystemVerilog代码如示例6所示。

                                图33-用于综合和仿真的ASIC和FPGA同步器单元示例
        从方框图中可以看出,该模型被设计为产生综合同步器模型或用作具有可选择延迟的仿真模型。IEEE Std 1364.1-2002 Verilog RTL Synthesis Standard[6]要求兼容的综合工具在读取任何Verilog模型之前设置Synthesis宏。
        尽管大多数综合工具在很大程度上忽略了IEEE Verilog综合标准的许多要求,但大多数工具都实现了这个不错的综合宏要求。在读取此sync2 SystemVerilog代码之前设置SYNTHESIS宏的工具将选择代码来推断双触发器同步器。
        不设置SYNTHESIS宏的仿真器将读取sync2模型,忽略用于可综合模型的代码,并在代码的“其他部分”中仿真模型。
        该模型被参数化,因此对于简单的1位CDC信号,相同的模型可以与宽度为1位的默认参数SIZE一起使用,或者该模型可以与设置为多位宽度的SIZE参数一起实例化,使得同步器可以用于捕获和同步诸如格雷码计数器的多位总线。​​​​​​​

module sync2 #(parameter SIZE=1)
(output logic [SIZE-1:0] q2,
input logic [SIZE-1:0] d,
input logic clk, rst_n);

`ifdef SYNTHESIS
logic [SIZE-1:0] q1;
always_ff @(posedge clk or negedge rst_n)
if (!rst_n) {q2,q1} <= '0;
else {q2,q1} <= {q1,d};

`else
logic [SIZE-1:0] y1, q1a, q1b;
logic [SIZE-1:0] DLY = '0;
assign y1 = (~DLY & q1a) | (DLY & q1b);
always_ff @(posedge clk or negedge rst_n)
if (!rst_n) {q2,q1b,q1a} <= '0;
else {q2,q1b,q1a} <= {y1,q1a,d};

`endif
endmodule

                               示例6-ASIC和FPGA同步单元的SystemVerilog模型​​​​​​​
        模型的仿真部分包括一个名为DLY的SIZE-ed变量的默认声明。默认情况下,DLY变量初始化为0,这导致整个sync2模型以两个触发器延迟的默认值进行仿真,但DLY变量可以从测试台分层设置为可重复的1和0的随机值,以使总线中的一些位通过三个触发器级,而其他位仅通过两个触发器级。这可以对一组同步器的行为进行建模,其中一些比特在比其他比特更早的时钟边沿上被捕获,并允许仿真观察设计在多比特数据路径中具有小偏差的情况下表现得如何。​​​​​​​
8.0 Summary & conclusions(总结与结论)
        时钟域交叉(CDC)错误可能会导致严重的设计故障。这些昂贵的故障可以通过遵循一些关键准则和使用成熟的验证技术来避免。
8.1 Recommended 1-bit CDC techniques(推荐的1位CDC技术)
在时钟域之间传递一位时:
•在发送时钟域中寄存信号,以消除组合故障。
•将信号同步到接收时钟域。多循环路径(MCP)方案可能是必要的。
8.2 Recommended multi-bit CDC techniques(推荐的多位CDC技术)
在时钟域之间传递多个控制或数据信号时,请使用以下策略之一:
•合并-在将信号同步到接收域之前,首先尝试在发送时钟域中将多个信号合并为1位表示。
•使用多循环路径(MCP)方案跨时钟域传递多个信号
•使用FIFO通过多位总线,无论是数据总线还是控制总线。
•使用格雷码计数器。
8.3 Recommended naming conventions and design partitioning(推荐的命名约定和设计分区)
        使用基于时钟的命名约定。尽可能将设计子块划分为完全同步的1—时钟设计。
8.4 Recommended solutions to multi-clock gate-level CDC simulations(多时钟门级CDC仿真的推荐解决方案)
        在门级仿真期间,有多种有用的解决方案来解决CDC X传播仿真问题:
•使用Synopsys开关为同步器上的第一级触发器生成0-setup和0-hold时间。仅适用于Synopsys工具。
•使用多个SDF文件——这是本节后面介绍的一种很好的技术。
•供应商提供同步单元和适当的SDF工具-如果您的ASIC或FPGA供应商提供模型和工具,这是一个很好的解决方案(很少有供应商提供-请您的ASIC和FPGA供应商支持此功能)
•使用创造性的SystemVerilog模型对同步问题进行建模。本文中描述的技术旨在促进多时钟设计的稳健开发和验证。

9 Appendix(附录)
        本附录包括具有确认反馈的MCP方案和1-deep,2级寄存器FIFO同步器的源代码。
9.1 Common sync2 model - used by MCP formulation and FIFO synchronizer(通用sync2模型-MCP方案和FIFO同步器使用)
        sync2模型对于具有就绪确认设计的MCP方案(第12.2节中的源代码)和多位1-deep/2寄存器FIFO同步器(第12.3节中的原代码)都是通用的。

// sync signal to different clock domain
module sync2 (
output logic q,
input logic d, clk, rst_n);
logic q1; // 1st stage ff output
always_ff @(posedge clk or negedge rst_n)
if (!rst_n) {q,q1} <= '0;
else {q,q1} <= {q1,d};
endmodule

                                                        Example 7 - sync2.sv code​​​​​​​
9.2 MCP formulation with ready-acknowledge source code(MCP方案,带有就绪确认源代码​​​​​​​)
该模型需要第12.1节所示的sync2模型。

// Pulse Generator
module plsgen (
output logic pulse, q,
input logic d,
input logic clk, rst_n);
always_ff @(posedge clk or negedge rst_n)
if (!rst_n) q <= '0;
else q <= d;
assign pulse = q ^ d;
endmodule

                                                             Example 8 - plsgen.sv code​​​​​​​

module asend_fsm (
output logic aready, // ready to send next data
input logic asend, // send adata
input logic aack, // acknowledge receipt of adata
input logic aclk, arst_n);
enum logic {READY = '1,
BUSY = '0} state, next;
always_ff @(posedge aclk or negedge arst_n)
if (!arst_n) state <= READY;
else state <= next;
always_comb begin
case (state)
READY: if (asend) next = BUSY;
else next = READY;
BUSY : if (aack) next = READY;
else next = BUSY;
endcase
end
assign aready = state;
endmodule

                                                        Example 9 - asend_fsm.sv code​​​​​​​

module back_fsm (
output logic bvalid, // data valid / ready to load
input logic bload, // load data / send acknowledge
input logic b_en, // enable receipt of adata
input logic bclk, brst_n);
enum logic {READY = '1,
WAIT = '0} state, next;
always_ff @(posedge bclk or negedge brst_n)
if (!brst_n) state <= WAIT;
else state <= next;
always_comb begin
case (state)
READY: if (bload) next = WAIT;
else next = READY;
WAIT : if (b_en) next = READY;
else next = WAIT;
endcase
end
assign bvalid = state;
endmodule

                                                Example 10 - back_fsm.sv code​​​​​​​

module bmcp_recv (
output logic [7:0] bdata,
output logic bvalid, // bdata valid
output logic b_ack, // acknowledge signal
input logic [7:0] adata, // unsynchronized adata
input logic bload, // load data and acknowledge receipt
input logic bq2_en, // synchornized enable input
input logic bclk, brst_n);
logic b_en; // enable pulse from pulse generator
// Pulse Generator
plsgen pg1 (.pulse(b_en), .q(), .d(bq2_en),
.clk(bclk), .rst_n(brst_n), .*);
// data ready/acknowledge FSM
back_fsm fsm (.*);
// load next data word
assign bload_data = bvalid & bload;
// toggle-flop controlled by bload_data
always_ff @(posedge bclk or negedge brst_n)
if ( !brst_n) b_ack <= '0;
else if (bload_data) b_ack <= ~b_ack;
always_ff @(posedge bclk or negedge brst_n)
if ( !brst_n) bdata <= '0;
else if (bload_data) bdata <= adata;
endmodule

                                        Example 11 - bmcp_recv.sv code​​​​​​​

module mcp_blk #(parameter type dat_t = logic [7:0]) (
output logic aready, // ready to receive next data
input logic [7:0] adatain,
input logic asend,
input logic aclk, arst_n,
output logic [7:0] bdata,
output logic bvalid, // bdata valid (ready)
input logic bload,
input logic bclk, brst_n);
logic [7:0] adata; // internal data bus
logic b_ack; // acknowledge enable signal
logic a_en; // control enable signal
logic bq2_en; // control - sync output
logic aq2_ack; // feedback - sync output
sync2 async (.q(aq2_ack), .d(b_ack), .clk(aclk), .rst_n(arst_n));
sync2 bsync (.q(bq2_en), .d(a_en), .clk(bclk), .rst_n(brst_n));
amcp_send alogic (.*);
bmcp_recv blogic (.*);
endmodule

                                                Example 12 - mcp_blk.sv code​​​​​​​

module amcp_send (
output logic [7:0] adata,
output logic a_en, aready,
input logic [7:0] adatain,
input logic asend,
input logic aq2_ack,
input logic aclk, arst_n);
logic aack; // acknowledge pulse from pulse generator
// Pulse Generator
plsgen pg1 (.pulse(aack), .q(), .d(aq2_ack),
.clk(aclk), .rst_n(arst_n));
// data ready/acknowledge FSM
asend_fsm fsm (.*);
// send next data word
assign anxt_data = aready & asend;
// toggle-flop controlled by anxt_data
always_ff @(posedge aclk or negedge arst_n)
if ( !arst_n) a_en <= '0;
else if (anxt_data) a_en <= ~a_en;
always_ff @(posedge aclk or negedge arst_n)
if ( !arst_n) adata <= '0;
else if (anxt_data) adata <= adatain;
endmodule

                                                Example 13 - acmp_send.sv code​​​​​​​
12.3 Multi-bit 1-deep / 2-register FIFO synchronizer source code(多位1-deep/2级寄存器FIFO同步器源代码)
该模型需要第12.1节所示的sync2模型。

module wctl (
output logic wrdy, wptr, we,
input logic wput, wq2_rptr,
input logic wclk, wrst_n);
assign we = wrdy & wput;
assign wrdy = ~(wq2_rptr ^ wptr);
always_ff @(posedge wclk or negedge wrst_n)
if (!wrst_n) wptr <= '0;
else wptr <= wptr ^ we;
endmodule

                                                Example 14 - wctl.sv code​​​​​​​

`timescale 1ns/1ns
module cdc_syncfifo #(parameter type dat_t = logic [7:0]) (
// Write clk interface
input dat_t wdata,
output logic wrdy,
input logic wput,
input logic wclk, wrst_n,
// Read clk interface
output dat_t rdata,
output logic rrdy,
input logic rget,
input logic rclk, rrst_n);
logic wptr, we, wq2_rptr;
logic rptr, rq2_wptr;
wctl wctl (.*);
rctl rctl (.*);
sync2 w2r_sync (.q(rq2_wptr), .d(wptr), .clk(rclk), .rst_n(rrst_n));
sync2 r2w_sync (.q(wq2_rptr), .d(rptr), .clk(wclk), .rst_n(wrst_n));
// dual-port 2-deep ram
dp_ram2 #(dat_t) dpram (.q(rdata), .d(wdata),
.waddr(wptr), .raddr(rptr),
.we(we), .clk(wclk), .*);
endmodule

                                                Example 15 - cdc_syncfifo.sv code​​​​​​​

// dual-port 2-deep ram
module dp_ram2 #(parameter type dat_t = logic [7:0])
(output dat_t q,
input dat_t d,
input logic waddr, raddr, we, clk);
dat_t mem [0:1];
always_ff @(posedge clk)
if (we) mem[waddr] <= d;
assign q = mem[raddr];
endmodule

                                Example 16 - Dual Port Ram code - dp_ram2.sv​​​​​​​

module rctl (
output logic rrdy, rptr,
input logic rget,rq2_wptr,
input logic rclk, rrst_n);
typedef enum {xxx, VALID} status_e;
status_e status;
assign status = status_e'(rrdy);
assign rinc = rrdy & rget;
assign rrdy = (rq2_wptr ^ rptr);
always_ff @(posedge rclk or negedge rrst_n)
if (!rrst_n) rptr <= '0;
else rptr <= rptr ^ rinc;
endmodule

                                        Example 17 - rctl.sv code​​​​​​​
10.0 References

[1] Clifford E. Cummings, “Simulation and Synthesis Techniques for Asynchronous FIFO Design,”
SNUG 2002 - www.sunburst-design.com/papers/CummingsSNUG2002SJ_FIFO1.pdf
[2] Clifford E. Cummings, “Synthesis and Scripting Techniques for Designing Multi-Asynchronous
Clock Designs,” SNUG 2001 -
www.sunburst-design.com/papers/CummingsSNUG2001SJ_AsyncClk.pdf
[3] Don Mills & Clifford E. Cummings, “RTL Coding Styles That Yield Simulation and Synthesis
Mismatches” SNUG 1999 - www.sunburst-design.com/papers/CummingsSNUG1999SJ_SynthMismatch.pdf
[4] Frank Gray, "Pulse Code Communication." United States Patent Number 2,632,058. March 17, 1953.
[5] Himanshu Bhatnagar, Advanced ASIC Chip Synthesis, Second Edition, Kluwer Academic
Publishers, 2002.
[6] "IEEE Std. 1364.1 - 2002 IEEE Standard for Verilog Register Transfer Level Synthesis," IEEE
Computer Society, IEEE, New York, NY, IEEE Std 1364.1-2002
[7] Mark Litterick, “Pragmatic Simulation-Based Verification of Clock Domain Crossing Signals and Jitter Using SystemVerilog Assertions,” DVCon 2006
www.verilab.com/files/sva_cdc_paper_dvcon2006.pdf
[8] Real Intent, Inc. (white paper), “Clock Domain Crossing Demystified: The Second Generation
Solution for CDC Verification,” February 2008 - www.realintent.com
[9] Steve Golson, personal communication
[10] William J. Dally and John W. Poulton, Digital Systems Engineering, Cambridge University Press,1998
[11] Wikipedia: http://en.wikipedia.org/wiki/Clock_Domain_Crossing_Verification

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值