01signal.com

Timing constraints 和 clock domain crossing

此页面属于关于 timing的一系列页面。前几页解释了 timing 计算背后的理论,展示了如何编写几个 timing constraints 并讨论了 timing closure的原理。本页说明如何定义与 clock domains相关的 timing constraints 。

介绍

了解了如何找到特定的 logic elements 以及如何定义 paths,我们现在将开始研究利用这些知识的 timing constraints 。

我们首先要看的是 timing constraints 和 clock domains之间的关系。这两个话题密切相关,讨论其中一个话题不可能不涉及另一个话题。因此,如果您不熟悉这个主题,我建议您通读有关 clock domains的这一系列页面。其中,这对于理解我将在下面使用的术语是必要的。

logic 定义了 clocks之间的关系

让我们看一下 Verilog 代码的这个示例:

module top(
    input clk,
    input foo,
    output reg bar_reg,
    output reg baz
);
    reg foo_reg;
    reg bar;
    reg baz_metaguard;
    wire pll_clk_8, pll_clk_6;

   clk_wiz_1 pll_i
   (.clk_in1(clk),
    .clk_out1(pll_clk_8),
    .clk_out2(pll_clk_6));

always @(posedge pll_clk_8)
  foo_reg <= foo;

always @(posedge pll_clk_6)
  begin
    bar <= !foo_reg;
    bar_reg <= bar;
  end

always @(posedge clk)
  begin
    baz_metaguard <= bar;
    baz <= baz_metaguard;
  end

这与我们之前看到的 PLL示例几乎相同。不同的是有新的 clock domain crossing: @bar 的值通过 metastability guard复制到 @baz 。

所以本例中有两种类型的 clock domain crossings :

我只看了一个标准来确定 clock domain crossing的类型: metastability guard的存在或不存在。如果 logic 期望 unrelated clocks,它会使用必要的安全机制。因此,其他都不重要: 即使在这些 clocks之间可以保证 paths 对 timing 的要求,也没有理由这么做。

反之亦然: 如果 logic 期望 related clocks,则没有针对 timing violations的保护。因此 timing 要求必须在这些 clocks之间的所有 paths 上得到满足。

所以总而言之, logic 总是假设哪些 clocks 是 related clocks ,哪些不是。这些假设反映在保护机制的存在与否上。但确保这些假设成为现实的是 FPGA 工具。特别是,这些工具确保在 related clocks之间的 paths 上满足 timing 要求。

因此,我们需要确保工具了解 logic对 clocks的假设。

请注意,在上面的示例中,工具无法了解 logic对 @pll_clk_6 和 @clk的期望: logic 可能假设这些是 related clocks ,也可能假设相反。事实上,我之前使用了一个类似的示例(参见“想法 #9”)来演示 related clocks之间的 path 。在上面的例子中,这两个 clocks 被当作 unrelated clocks处理。

也许这些工具可以从 @baz_metaguard的名称中做出智能猜测。也许 metastability guard 的典型结构可以提供一些提示。但这还不足以就如此重要的问题做出决定。

讲述 clocks的工具

在到目前为止的示例中,只有一个 timing constraint:

create_clock -period 4.000 -name clk [get_ports clk]

想到的第一个问题是默认情况下,工具如何将 clock domain crossing 从 @pll_clk_6 处理为 @clk 。如果这是唯一的 timing constraint,这些工具是否会在 @bar 和 @baz_metaguard之间的 path 上执行任何操作?

答案是这取决于使用哪种 FPGA 工具。尽管几乎所有 FPGA 工具都会将 @pll_clk_6 和 @pll_clk_8 视为 related clocks,但其他对 clocks会发生什么情况并不明显。默认情况下,这些工具通常将所有 clocks 视为 related clocks ,但依赖它并不安全。

许多 FPGA 工具都支持 set_clock_groups 命令。这是定义 clocks之间关系的最佳选择。由于此命令的重要性,最好在 design中使用它之前参考工具的文档。

对于上面的示例,此命令可以在 Vivado 上像这样使用(或与其他工具类似):

set_clock_groups -asynchronous \
  -group [list \
     [get_clocks -of_objects [get_pins pll_i/clk_out1] ] \
     [get_clocks -of_objects [get_pins pll_i/clk_out2] ] ] \
  -group [get_clocks -of_objects [ get_pins pll_i/clk_in1] ]

get_clocks 和 get_pins 的这种用法之前已经解释过: 每一个 get_clock 命令根据 clk_wiz_1 的相关 port 的名字找到一个 clock object (注意 clk_wiz_1的 instantiation 的名字是 pll_i)。例如,最后一个 get_clock 命令获取 @clk的 clock object 。

此示例显示 set_clock_groups 如何定义 clocks的组。在这种情况下,一组由 @pll_clk_6 和 @pll_clk_8组成,第二组仅由 @clk 组成。这个 constraint 告诉工具属于同一组的所有 clocks 都是 related clocks。同样,如果两个 clocks 属于不同的组,工具会将它们视为 unrelated clocks。

换句话说,当且仅当 path 两侧的 clocks 属于同一组时,这些工具才会在 path 上强制执行 timing constraints 。

design的 timing constraints中允许使用多个 set_clock_groups 命令。但最好是用一个 set_clock_groups 命令把所有的 clocks 分成几组。这避免了矛盾,也有助于防止混淆: 此命令的主要优点是它是 clocks之间关系的简明描述。简短,简洁和数学。这就是我们想要的方式。

请注意, set_clock_groups 应在所有 create_clock 命令之后使用,因为提到的 clocks objects 应该已经存在。

clocks之间的不一致关系

如果 clocks 在 design中有的地方被认为是 related clocks ,有的地方被认为是 unrelated clocks ,那么就不能用 set_clock_groups了。

例如, @clk 和 @pll_clk_6 在上面的 Verilog 代码中被视为 unrelated clocks 。但理论上,可能会有额外的 logic 将它们视为 related clocks。尽管这不是一个好主意,但可以为这个额外的 logic在 @pll_clk_6 和 @clk 之间强制执行 timing constraints 。

如果 set_clock_groups 因为这个原因不能用,先问问自己是不是不想换 logic,就可以用 set_clock_groups 。这不仅仅是因为这个命令太好了: 如果没有一个简单的规则来说明哪些 clocks 是 related clocks ,哪些不是,则很容易在 clock domain crossings上出错。如果您仍然不想在 logic中进行此类更改,解决方案是定义 false paths。

简要介绍 set_false_path 命令

有两个用于声明 false paths的主要命令: set_clock_groups 和set_false_paths

上面介绍了 set_clock_groups 命令: 属于不同组的两个 clocks 之间的任何 path 都被视为 false path。但是 set_clock_groups 不能总是用于所有应该声明为 false path的 paths 。在某些情况下, paths 的选择必须比 clocks的定义组更具体。 set_false_path 命令通过允许特定选择 paths解决了这个问题。

例如,让我们用 set_false_path 命令替换上面的 set_clock_groups 命令。唯一需要修复的是 path 从 @bar 到 @baz_metaguard。所有其他 paths 的 timing 要求按原样正确执行。所以这是为这个 path编写 set_false_path 命令的一种方法。但是不要从这个例子中学习:

set_false_path -from [get_cells bar_reg__0] -to [get_cells baz_metaguard_reg]

此命令使用 get_cells 选择 path的开头和 path的结尾。这就需要知道两边 cell objects 的名称了。在这种情况下,我们有名称“bar_reg__0”,这说明了依赖名称的问题: 这个名字应该是“bar_reg”,但正如已经解释的那样,由于巧合,它以“bar_reg__0”结尾。

所以这个例子展示了 set_false_path的问题之一: design 中 logic elements 的详细选择通常需要依赖 object的名称。这个问题和可能的解决方案之前已经讨论过了

这个命令可以简化: 由于 @baz_metaguard 是 metastability guard,因此 paths 到 register 来自哪里并不重要。那么为什么不忽略所有 paths 到这个 register?

set_false_path -to [get_cells baz_metaguard_reg]

这个命令的效果是完全一样的。

set_false_path 而不是 set_clock_groups

另一种可能是根据 clocks定义 paths 。事实上,上面的 set_clock_groups 命令可以用这些 constraints代替:

set_false_path -from [get_clocks -of_objects [get_pins pll_i/clk_out1]] \
               -to [get_clocks -of_objects [ get_pins pll_i/clk_in1] ]

set_false_path -from [get_clocks -of_objects [get_pins pll_i/clk_out2] ] \
               -to [get_clocks -of_objects [ get_pins pll_i/clk_in1] ]

set_false_path -from [get_clocks -of_objects [ get_pins pll_i/clk_in1] ] \
               -to [get_clocks -of_objects [get_pins pll_i/clk_out1] ]

set_false_path -from [get_clocks -of_objects [ get_pins pll_i/clk_in1] ] \
               -to [get_clocks -of_objects [get_pins pll_i/clk_out2] ]

这是创建相同 false paths的漫长而详细的方法。不是将 clocks 分组,而是每对 unrelated clocks有两个 set_false_path 命令: 每个方向一个命令。很明显,这么多 constraints很容易出错。这是一个包含三个 clocks的简单示例。

尽管如此, set_false_path 经常被这样使用,而不是 set_clock_groups。这很可能是因为有人从某处复制了 timing constraints 。

错误如何发生的示例

让我们看一个可能的错误的简单示例: 从上面的讨论中,很明显只有一个 path 需要声明为 false path: 从 @bar 到 @baz_metaguard。因此,在上一个示例中的四个 set_false_path 命令中,只有这个有意义:

set_false_path -from [get_clocks -of_objects [get_pins pll_i/clk_out2] ] \
               -to [get_clocks -of_objects [ get_pins pll_i/clk_in1] ]

其他三个 set_false_path 命令不涵盖任何 paths。但是等等,进一步简化 constraint 怎么样?也许所有以 @clk 结尾的 paths 都应该是 false paths?这个怎么样?

set_false_path -to [get_clocks -of_objects [ get_pins pll_i/clk_in1] ]

实际上,因为定义“clk”的 create_clock 命令就在 set_false_path 命令之上,所以可以这样写:

set_false_path -to [get_clocks clk]

这款 constraint 短而优雅。不幸的是,这是非常错误的: 我建议所有以 @clk 结尾的 paths 都应该是 false path。但是从 @baz_metaguard 到 @baz的 path 呢?那是从 @clk 到 @clk的 path 。当然,这个 path 肯定不是 false path。但是最后两个 set_false_path 命令包括所有以 @clk结尾的 paths ,即使 path 以 @clk开头也是如此。

犯这种错误很容易,特别是如果 false path 的 constraints 是在没有精确的数学思维方式的情况下编写的。创建特殊的 timing reports可能会有所帮助,它可以揭示哪些 paths 是 false paths ,哪些不是。


关于 FPGA内部的 paths 的 timing constraints 的实际讨论到此结束。下一页讲解 multi-cycle paths,也属于这个话题。但是,通常不推荐 multi-cycle path constraints 。因此,可以直接跳到 I/O constraints的介绍

此页面由英文自动翻译。 如果有不清楚的地方,请参考原始页面
Copyright © 2021-2024. All rights reserved. (6f913017)