01signal.com

时钟周期约束(clock period constraint)和时钟对象(clock objects)

此页面属于关于时序(timing)的一系列页面。前几页解释了时序计算背后的理论,讨论了时钟周期约束,并展示了时序收敛(timing closure)的原理。现在是时候开始了解时序约束(timing constraints)的技术细节了。

create_clock 作为 Tcl 命令的含义

前面几页都是围绕着这个时序约束(timing constraint)展开的:

create_clock -period 4 -name clk [get_ports clk]

直到现在我才故意不讨论这一行的语法。所以是时候解释一下这到底意味着什么了。

这个时序约束是用 SDC (Synopsys Design 约束) 格式编写的,这是时序约束最常见的格式。 Vivado 和 Quartus 使用此格式,以及其他几种 FPGA 工具。

SDC 文件本质上是用 Tcl编写的脚本(script)。因此, SDC 文件的内容是一个简短的计算机程序,而不仅仅是信息的集合。但是, SDC 文件作为脚本的功能仅限于命令的一小部分,这些子集旨在用于编写约束(constraints): 并非 Tcl 脚本中允许的所有内容都可以在 SDC 文件中完成。

create_clock 命令用于定义时序约束。但实际上,这个命令告诉 FPGA 工具创建一个新的时钟对象。而“对象(object)”这个词的意思与软件工程中通常的意思相同。因此,新的时钟对象是作为对象存储在 Tcl interpreter内存中的,而对象有自己的属性(properties)。

例如, create_clock 命令中标有“-name clk”的部分将值“clk”提供给名为“name”的属性。回想一下前面的页面,时序报告(timing reports)中使用了这个名称: 名称“clk”与时序路径(timing paths)一起出现是因为这个约束(constraint)(或者更准确地说,因为这个时钟对象(clock object))。

后来,我们看到时钟还有其他名字,比如 clk_out1_clk_wiz_1 和 clk_out2_clk_wiz_1。这些实际上是其他时钟对象的名称,由工具自动创建。

有一个 Tcl 命令用于列出所有时钟: get_clocks。因此,对于上一页中带有两个时钟的示例,这是 Vivado的 Tcl console上的会话:

> get_clocks
clk clkfbout_clk_wiz_1 clk_out1_clk_wiz_1 clk_out2_clk_wiz_1

下一页将更详细地解释get_clocks 和类似的命令。

也可以查看这些对象的属性。这些属性无需全部了解: 我展示这个只是为了说明时钟是对象。就个人而言,我从来不需要直接操作任何对象的属性。

> report_property [get_clocks clk]
Property           Type     Read-only  Value
CLASS              string   true       clock
INPUT_JITTER       double   true       0.040
IS_GENERATED       bool     true       0
IS_PROPAGATED      bool     true       1
IS_USER_GENERATED  bool     true       0
IS_VIRTUAL         bool     true       0
NAME               string   true       clk
PERIOD             double   true       4.000
SOURCE_PINS        string*  true       clk
SYSTEM_JITTER      double   true       0.050
WAVEFORM           double*  true       0.000 2.000

> report_property [get_clocks clk_out1_clk_wiz_1]
Property           Type     Read-only  Value
CLASS              string   true       clock
EDGES              int*     true       1 2 3
EDGE_SHIFT         double*  true       0.000 2.000 4.000
INPUT_JITTER       double   true       0.000
IS_GENERATED       bool     true       1
IS_INVERTED        bool     true       0
IS_PROPAGATED      bool     true       1
IS_RENAMED         bool     true       0
IS_USER_GENERATED  bool     true       0
IS_VIRTUAL         bool     true       0
MASTER_CLOCK       clock    true       clk
NAME               string   true       clk_out1_clk_wiz_1
PERIOD             double   true       8.000
SOURCE             pin      true       pll_i/inst/mmcme3_adv_inst/CLKIN1
SOURCE_PINS        string*  true       pll_i/inst/mmcme3_adv_inst/CLKOUT0
SYSTEM_JITTER      double   true       0.050
WAVEFORM           double*  true       0.000 4.000

需要注意的是, create_clock 只是创建了一个对象(object)。这个命令的参数(parameters)仅决定如何设置这个对象的属性。例如,写着“-period 4”的部分(在我反复展示的时序约束中)只是意味着某个属性(property)(称为“PERIOD”)应该具有值 4。

如果你想亲自尝试这些 Tcl 命令,请注意 FPGA 工具之间存在差异。

在 Vivado中,这些命令需要打开 Implemented 设计才可以使用。

在 Quartus中,先打开 TimeQuest Timing Analyzer,然后点击 Create Timing Netlist、 Read SDC File 和 Update Timing Netlist。然后在 Tcl console上尝试一些命令,例如:

> join [ query_collection -all [ get_clocks ] ] "\n"
> get_clock_info -waveform [get_clocks clk]

“时钟”这个词的含义

当 FPGA 工具使用“clock”一词时,通常是指时钟对象,而不是 FPGA内部的物理信号。在时序报告中尤其如此。

回想一下上一页,我曾多次使用术语“理论上的时钟”。这些实际上是时钟对象。它们在时序报告中被称为“时钟”,但在时序分析(timing analysis)中的使用表明它们只是信息的容器。

那么这些时钟对象和真正的信号之间有什么联系呢?我们已经在时序分析中看到了时钟对象的名称。这一切是如何协同工作的?

当工具执行设计的静态时序分析(static timing analysis)时,将检查所有路径(paths)。如果路径以触发器(flip-flop)开头,则工具会检查连接到触发器的时钟输入的信号(即网络(net)): 是否有任何时钟对象与此信号相关?例如,当信号是 @clk时,相关的时钟对象是与 create_clock 命令一起被命名为“clk”的时钟对象。找到相关的时钟对象后,工具可以从此对象的属性中提取必要的信息。

路径末端的触发器也会发生同样的事情。所以现在工具有两个时钟对象对应于路径。利用这些对象的信息,工具可以执行时序分析。

当然,同样的程序适用于任何时序逻辑元件(sequential element),而不仅仅是触发器。

为什么了解这一点很重要?其中,因为有时候时序报告里面有 error message 说有寄存器(registers)没有时钟。通常,这并不意味着触发器与其时钟输入没有任何连接。相反,这意味着工具没有找到与此时钟输入相关的时钟对象。也就是说,工具并没有查到这个触发器(flip-flop)的时钟输入的任何信息。所以问题通常不在逻辑设计,而是少了一个时序约束(或者写错了)。

值得再说一遍: 当它在时序报告中显示“时钟”时,这并不意味着逻辑设计中有一个具有该名称的信号,而是已经创建了一个具有该名称的时钟对象。我们怎么知道哪个信号?那是下一个话题。

这是谁的时钟?

使时序报告难以阅读的原因之一是时钟的名称。逻辑设计中的大多数时钟信号都是由锁相环(PLL)创建的,我们已经看到时序报告中出现的名称可能毫无用处。大多数 FPGA 工具允许通过向 SDC 文件添加命令来重命名时钟对象,但在大多数项目中并没有这样做。黄金法则 4是避免使用对您的项目来说很特别的东西。

当时钟的来源是 IP block (例如 Gigabit transceiver、 PCIe block 或 on-chip processor core)时,名称问题变得更加困难。在这种情况下,时钟的名称通常很少说明它的来源和相关内容。

那么这个问题该如何解决呢?让我们从最简单的情况开始,当时钟的名称来自我们自己的 SDC 文件中的 create_clock 命令时。这又是相同的时序约束:

create_clock -period 4 -name clk [get_ports clk]

这个命令中的最后一部分是“[get_ports clk]”。在 Tcl 语言中,方括号表示将括号中的内容作为 Tcl 命令执行,然后用这个命令的结果代替这些括号。

get_ports 命令找到名为“clk”的 I/O 端口。这个命令的结果就是代表这个端口的对象。所以在上面的 create_clock 命令中,这个对象是这个命令的 argument 。这就是 create_clock 在时钟对象和真正的信号之间建立联系的方式。

注意端口的名称和对象的名称都是“clk”。不要求它们相同,但建议这样做: 对象的名称出现在时序报告中。因此,端口这个名字通常是最好的选择。

也可以使用网络对象(net objects)和引脚对象(pin objects)作为信号的标识符。这在代表 IP blocks自动生成的时序约束中很常见。但是,如果您觉得有必要在您自己的约束中执行此操作,则很可能是您做错了什么。

因此,如果在 SDC 文件中使用了 create_clock 命令,则很容易判断时钟对象与哪个信号相关。但是工具自动创建的时钟对象又如何呢?

在这种情况下,识别时钟的最佳方法是查看时序报告。例如,在上一页的示例中,哪个时钟对象与 @pll_clk_8 相关?找出答案的一个简单方法是在时序报告中执行 text search 。于是搜索“pll_clk_8”,找到以下部分:

Location          Delay type                Incr(ns)  Path(ns)    Netlist Resource(s)
--------------------------------------------------------------  -------------------
                  (clock clk_out1_clk_wiz_1 rise edge)
                                              16.000    16.000
AG12                                           0.000    16.000  clk (IN)
                  net (fo=0)                   0.000    16.000  pll_i/inst/clkin1_ibuf/I
AG12              INBUF (Prop_INBUF_HRIO_PAD_O)
                                               0.738    16.738  pll_i/inst/clkin1_ibuf/INBUF_INST/O
                  net (fo=1, routed)           0.105    16.843  pll_i/inst/clkin1_ibuf/OUT
AG12              IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O)
                                               0.049    16.892  pll_i/inst/clkin1_ibuf/IBUFCTRL_INST/O
                  net (fo=1, routed)           0.975    17.867  pll_i/inst/clk_in1_clk_wiz_1
MMCME3_ADV_X1Y0   MMCME3_ADV (Prop_MMCME3_ADV_CLKIN1_CLKOUT0)
                                              -4.438    13.429  pll_i/inst/mmcme3_adv_inst/CLKOUT0
                  net (fo=1, routed)           0.501    13.930  pll_i/inst/clk_out1_clk_wiz_1
BUFGCE_X1Y1       BUFGCE (Prop_BUFCE_BUFGCE_I_O)
                                               0.101    14.031  pll_i/inst/clkout1_buf/O
X2Y0 (CLOCK_ROOT) net (fo=1, routed)           1.369    15.400  pll_clk_8
SLICE_X49Y58      FDRE                                          foo_reg_reg/C

这是 clk_out1_clk_wiz_1的源时钟路径(Source Clock Path),这就是问题的答案。

另一种方法是使用 Tcl 命令获取信息。具体如何操作因 FPGA 工具而异。在 Vivado中,打开 Implemented Design后可以使用如下所示的命令:

> get_clocks -of_objects [ get_nets pll_clk_8 ]
clk_out1_clk_wiz_1

此方法需要知道网络的名称。有时它像本例一样简单,有时它需要找到这个网络(net)的名称。 FPGA 工具通常提供一种使用图形用户界面(GUI)执行此操作的方法。也可以使用 Tcl 命令来实现此目的。

事实上,我希望 Tcl 的几个示例让您相信了解如何正确使用 Tcl 的重要性。这就是下一页的内容。

使用 get_port的意义

在上面的例子中, create_clock 命令依靠 get_port 在时钟对象和物理输入引脚之间建立连接。如上所述,此连接对于了解哪些逻辑单元(logic elements)连接到此时钟(或从其生成的时钟)是必要的。

但是使用 get_port 并不是唯一的可能性。例如,也可以引用全局时钟缓冲器(global clock buffer)的输出引脚(output pin)。是这样的:

create_clock -name clk -period 4 [get_pins my_BUFG_inst/O]

不同之处在于工具将全局时钟缓冲器的输出引脚视为时钟的起源。也就是说,时钟路径(clock paths)的计算是从这个位置开始的。此原点的第一个时钟边沿(clock edge)出现在 0 ns,因此此输出引脚成为时间参考。

这是一个合法的时序约束,但它有两个重要的缺点:

因此,应尽可能使用 get_port 。否则,除了它本身,时钟的时序应该被认为是未知的。


本页介绍了许多 Tcl 命令,但没有充分解释它们。下一页填补了这一空白。

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