本页是另一页的补充内容,建议你先阅读那页再回来读本页。这两页都属于一个关于时序的系列文章,该系列解释了时序计算背后的理论、展示了如何编写多条时序约束,并讨论了时序收敛(timing closure)的原则。
除非万不得已,不要使用简单的搜索模式
本页介绍如何在 SDC 格式的时序约束中使用通配符。尽管通配符可以用于多个 Tcl 命令,但本页重点讨论那些通常支持 -hierarchical 选项的命令:get_cells、get_pins 和 get_nets。这些 Tcl 命令的用法在另一个页面中已有说明。注意,有些 FPGA 工具并不对这三个命令都支持 -hierarchical。
遗憾的是,这三个命令的搜索能力相当有限,而且容易让人困惑:如果不准确理解通配符的工作方式,搜索结果可能会出乎意料。尤其是使用 -hierarchical 时,结果常常令人惊讶,如下文所示。
因此,只要所用 FPGA 工具在相应命令上支持-filter 选项,就应该优先使用它。在工具不支持的情况下,才别无选择地使用简单通配符。
本页中的示例都基于与另一相关页面相同的 Verilog 代码。
简单的搜索模式
用于查找逻辑元件及其它对象的命令,可以带搜索模式,也可以不带。不带搜索模式时,会找到所有相关对象。例如,要查找顶层层次中的所有引脚:
get_pins
而下面这条命令则查找整个 FPGA 设计中的所有引脚:
get_pins -hierarchical
如果使用了搜索模式,结果就会被限制在该模式内。例如,要查找一个名字已知、在层次结构中位置也已知的特定引脚:
> get_pins foo_reg_reg/Q foo_reg_reg/Q > get_pins pll_i/clk_in1 pll_i/clk_in1 > get_pins pll_i/inst/clk_in1 pll_i/inst/clk_in1
模式中也可以包含通配符。例如:
> get_pins foo_reg_reg/* foo_reg_reg/Q foo_reg_reg/C foo_reg_reg/CE foo_reg_reg/D foo_reg_reg/R > get_pins pll_i/* pll_i/clk_in1 pll_i/clk_out1 pll_i/clk_out2 > get_pins pll_i/inst/* pll_i/inst/clk_in1 pll_i/inst/clk_out1 pll_i/inst/clk_out2 > get_pins pll_i/*/* pll_i/inst/clk_in1 pll_i/inst/clk_out1 pll_i/inst/clk_out2 > get_pins pll_i/*/clk* pll_i/inst/clk_in1 pll_i/inst/clk_out1 pll_i/inst/clk_out2
通配符的行为
通配符有两种:
- 星号(*),可以替代任意数量的字符。
- 问号(?),只能替代一个字符。
但这两个通配符都不会匹配层次结构分隔符。换句话说,* 和 ? 都不能替代 /(在 Quartus 中则是 |)。无论是否使用 -hierarchical 选项,这一点对通配符始终成立(但要注意,如果使用 -filter 或 -regexp,情况就不同了)。
因此,对象在层次结构中的精确位置必须显式地写出来:
> get_pins */clk_* pll_i/clk_in1 pll_i/clk_out1 pll_i/clk_out2 > get_pins */*/clk_* pll_i/inst/clk_in1 pll_i/inst/clk_out1 pll_i/inst/clk_out2
注意,不同工具使用的层次结构分隔符可能不同。如前所述,Quartus 使用竖线(|)而不是 / 作为分隔符。
-hierarchical 选项允许在设计的整个层次结构中的任何位置查找逻辑元件。这就不需要指定对象在层次结构中的精确位置,也可以用一条命令在整个 FPGA 设计中进行查找。
现在,我们把同样的表达式与 -hierarchical 一起再运行一遍:
> get_pins -hierarchical */clk_* pll_i/clk_in1 pll_i/clk_out1 pll_i/clk_out2 pll_i/inst/clk_in1 pll_i/inst/clk_out1 pll_i/inst/clk_out2 > get_pins -hierarchical */*/clk_* WARNING: [Vivado 12-508] No pins matched '*/*/clk_*'.
-hierarchical 的含义是:搜索模式会在设计层次结构的各个位置依次应用。在上面的例子中,*/clk_* 首先在顶层层次应用,于是找出 pll_i/clk_in1 等;同一模式随后又在 pll_i/ 内部应用,于是找出 pll_i/inst/clk_in1 等。
但为什么 */*/clk_* 在使用 -hierarchical 后反而找不到任何东西?同样的模式在不使用该选项时明明能找出一些结果。使用 -hierarchical 后,搜索结果不是理应更多吗?
使用 -hierarchical 会限制搜索模式
奇怪的是,-hierarchical 选项不仅改变了搜索模式的适用范围,还会限制哪些模式是合法的。遗憾的是,当使用了非法的模式时,工具并不会报错,而是直接返回“什么都没有找到”。
这三个 Tcl 命令(get_cells、get_pins 和 get_nets)各自都有限制搜索模式的规则。要了解具体限制,请参考你所使用的 FPGA 工具的文档。下面是标准的解释(详见 Synopsys 的文档)。
注意,人们常把 -hierarchical 简写为 -hier,两者的含义完全相同。
get_cells -hierarchical
当 get_cells 与 -hierarchical 一起使用时,模式只匹配对象的名称。如果模式中含有层次结构分隔符,结果将始终为空。例如:
> get_cells -hierarchical *_buf pll_i/inst/clkf_buf pll_i/inst/clkout1_buf pll_i/inst/clkout2_buf > get_cells -hierarchical inst/*_buf WARNING: [Vivado 12-180] No cells matched 'inst/*_buf'.
注意,如果模式中含有 /,那就是一种错误用法,因为这类模式永远找不到任何东西。但工具不会报错,只会返回空结果。
由于模式中不允许出现层次结构分隔符,get_cells 只能有以下几种用途:
- 在不使用 -hierarchical 的情况下,查找层次结构中某个特定位置上的 cell。
- 通过 -hierarchical 查找整个 FPGA 设计中的 cell。
- 如果工具支持 -filter 或 -regexp,就改用这些选项,它们不受这种限制。
下面这个示例展示了如何为所有具有特定命名格式的 cell 声明伪路径:
set_false_path -to [get_cells -hierarchical *metaguard*]
使用这类时序约束时,只需要让所有作为亚稳态保护(metastability guard)的寄存器名字中都包含 metaguard 即可。但这条约束的风险在于,这个表达式可能无意中匹配到 FPGA 设计中某个不相关的逻辑元件。因此,最好选择一个比 metaguard 更少见的关键词。
get_nets -hierarchical
get_nets 遵循与 get_cells 相同的规则:不使用 -hierarchical 时,get_nets 查找顶层层次中与模式匹配的所有网络;使用 -hierarchical 时,模式只匹配对象的名称,如果模式中含有层次结构分隔符,结果始终为空。
> get_nets pll_i/clk_i* pll_i/clk_in1 > get_nets clk_i* WARNING: [Vivado 12-507] No nets matched 'clk_i*'. > get_nets -hierarchical clk_i* pll_i/clk_in1 pll_i/inst/clk_in1 > get_nets -hierarchical pll_i/clk_i* WARNING: [Vivado 12-507] No nets matched 'pll_i/clk_i*'.
get_pins -hierarchical
当 get_pins 与 -hierarchical 一起使用时,模式会匹配引脚的完整名称,例如 baz_reg/Q、clkout1_buf/I 等等。此时,/ 被视为名字的一部分,而不是层次结构分隔符。换句话说,cell 名称与引脚标识符之间的字符可以被通配符替代。这只对最后一个层次结构分隔符成立,而且只有在使用 -hierarchical 时才如此。
例如:
> get_pins -hierarchical clkout1_buf/* pll_i/inst/clkout1_buf/O pll_i/inst/clkout1_buf/CE pll_i/inst/clkout1_buf/I > get_pins -hierarchical clkout1_bu* pll_i/inst/clkout1_buf/O pll_i/inst/clkout1_buf/CE pll_i/inst/clkout1_buf/I > get_pins -hierarchical clkout1_buf WARNING: [Vivado 12-508] No pins matched 'clkout1_buf'.
注意,clkout1_bu* 匹配到了 clkout1_buf/O(以及其它)。* 之所以能替代 /O,完全是因为使用了 -hierarchical。
与 get_cells 一样,如果模式中含有层次结构分隔符,结果通常为空。这与上面的例子并不矛盾:如前所述,最后一个 / 被视为引脚名称的一部分。
> get_pins pll_i/inst/clkout1*/I pll_i/inst/clkout1_buf/I > get_pins -hierarchical pll_i/inst/clkout1*/I WARNING: [Vivado 12-508] No pins matched 'pll_i/inst/clkout1*/I'. > get_pins -hierarchical pll_i/inst/*/* WARNING: [Vivado 12-508] No pins matched 'pll_i/inst/*/*'. > get_pins -hierarchical pll_i/*/*/* WARNING: [Vivado 12-508] No pins matched 'pll_i/*/*/*'. > get_pins -hierarchical pll_i/*/* WARNING: [Vivado 12-508] No pins matched 'pll_i/*/*'. > get_pins -hierarchical pll_i/* pll_i/clk_in1 pll_i/clk_out1 pll_i/clk_out2 > get_pins pll_i/* pll_i/clk_in1 pll_i/clk_out1 pll_i/clk_out2
注意,当不使用 -hierarchical 时,通配符永远不匹配层次结构分隔符,哪怕是最后一个 / 也不行:
> get_pins pll_i/inst/clkout1_buf/I pll_i/inst/clkout1_buf/I > get_pins pll_i/inst/clkout1_buf/* pll_i/inst/clkout1_buf/O pll_i/inst/clkout1_buf/CE pll_i/inst/clkout1_buf/I > get_pins pll_i/inst/clkout1_bu* WARNING: [Vivado 12-508] No pins matched 'pll_i/inst/clkout1_bu*'. > get_pins pll_i/inst/clkout1_bu*/* pll_i/inst/clkout1_buf/O pll_i/inst/clkout1_buf/CE pll_i/inst/clkout1_buf/I
从这些例子可以清楚地看出,get_pins 是多么令人困惑。和前文建议的一样:如果工具支持 -filter 或 -regexp,就果断改用它们。
小结
尽管通配符是一种查找逻辑元件的方法,但搜索结果往往并不符合人们的自然预期。同样,-hierarchical 选项在某些场景下确实有帮助,但它既会对搜索模式带来限制,还会让行为变得更加难以捉摸。
因此,建议使用其它方法来选择逻辑元件:如果 FPGA 工具支持 -filter、-regexp 或 -of_objects,那么其中某个选项很可能是更好的选择。只有在这些选项都不可用、或者在具体场景中都不适用时,使用简单通配符才有意义。在这种情况下,务必格外警惕搜索模式的确切含义。