Xilinx约束学习笔记(一)—— 约束方法学

本文作者: NeverCode
本文转载自: https://www.cnblogs.com/nevercode/p/15169653.html

《Xilinx约束学习笔记》为自己阅读 Xilinx 官方 UG903 文档后的学习笔记,大多数为翻译得来,方便大家学习。

1 约束方法学
1.1 组织约束文件
Xilinx 建议将时序约束和物理约束分开保存为两个不同的文件。甚至可以将针对某一个模块的约束单独保存在一个文件中。

1.1.1 综合和实现可以使用不同的约束文件
可以使用 USED_IN_SYNTHESIS 和 USED_IN_IMPLEMENTATION 属性指定约束文件是在综合或实现过程中使用。

注意:特别是IP、DCP这类使用OOC模式的模块,因为这些模块在综合过程中是一个黑盒,当顶层约束指定的约束路径为黑盒中的内容时,可能在综合过程中会报找不到目标的错误。因此,最好的方法是将约束会为两个文件,一个综合用,一个实现时用。

在工程模式中可以使用如下代码指定约束文件使用时机。

set_property USED_IN_SYNTHESIS false [get_files wave_gen_pins.xdc]
set_property USED_IN_IMPLEMENTATION true [get_files wave_gen_pins.xdc]

非工程模式中,不需要如此设置。因为什么时候使用约束文件,只和读取约束文件的时机相关。如下:其中 wave_gen_timing.xdc 会在综合和实现过程中使用,而 wave_gen_pins.xdc 只会在实现过程中使用。

read_verilog [glob src/*.v]
read_xdc wave_gen_timing.xdc
synth_design -top wave_gen -part xc7k325tffg900-2
read_xdc wave_gen_pins.xdc
opt_design
place_design
route_design

1.2 约束的顺序
推荐约束顺序如下:

## Timing Assertions Section
# Primary clocks
# Virtual clocks
# Generated clocks
# Clock Groups
# Bus Skew constraints
# Input and output delay constraints

## Timing Exceptions Section
# False Paths
# Max Delay / Min Delay
# Multicycle Paths
# Case Analysis
# Disable Timing

## Physical Constraints Section
# located anywhere in the file, preferably before or after the timing constraints
# or stored in a separate constraint file

1.3 创建综合约束
Vivado 综合将设计中的 RTL 描述转换为工艺映射网表。此过程分为多个步骤进行,包括一些时序导向的优化。FPGA 包含许多逻辑特性,可以有许多不同的应用方式。需要通过约束来引导综合引擎工作,以满足实现时所需的要求。

综合约束可以分为4类:

  • RTL Attributes
  • Timing Constraints
  • Physical and Configuration Constraints
  • Elaborated Design Constraints
  • 1.3.1 RTL Attributes
    RTL Attributes 必须写入 RTL 文件中。他们通常用来选择逻辑的某些部分的映射样式,以及保留某些寄存器和网线,或控制最终网表中的设计层次结构。

    IMPORTANT: The DONT_TOUCH attribute does not obey the properties of USED_IN_SYNTHESIS and USED_IN_IMPLEMENTATION . If you use DONT_TOUCH properties in the synthesis XDC, it is propagated to implementation regardless of the value of USED_IN_IMPLEMENTATION .

    注意:DONT_TOUCH 属性不受 USED_IN_SYNTHESIS 和 USED_IN_IMPLEMENTATION 的控制,当在综合约束中使用 DONT_TOUCH 时,他会传递到实现过程中,无论 USED_IN_IMPLEMENTATION 的属性值是什么。

    set_property DONT_TOUCH true [get_cells fsm_reg]

    1.3.2 Timing Constraints
    Timing Constraints 必须通过一个或多个 XDC 文件传递给综合引擎。只有以下与建立时间分析相关的约束对综合结果有实际影响:

  • create_clock
  • create_generated_clock
  • set_input_delay
  • set_output_delay
  • set_clock_groups
  • set_false_path
  • set_max_delay
  • set_multicycle_path
  • 1.3.3 Physical and Configuration Constraints
    Physical and Configuration Constraints 会被综合算法忽略。(既然会被忽略为什么又提到?)

    1.3.4 Elaborated Design Constraints
    创建综合 XDC 的第一个版本时,只需要使用简单的时序约束来描述高级设计要求即可。因为此阶段的路径延迟并不准确,目的只是为了在实现开始前,尽量让综合的结果满足时序。并且在此阶段可能需要反复迭代 RTL 代码和 XDC 文件,以便查找各种网名和排除各种语法错误。

    在 Elaborated Design 的创建过程中,某些 RTL 名称被修改或丢失。需要注意如下几点:

  • 网表中寄存器的名称会比在 RTL 代码中的名称多一个 _reg 的后缀。
  • 有些寄存器或网线会被吸收掉,例如二维寄存器会被综合成 Memory Block,乘除法会综合成 DSP。
  • 在使用 get_* 查询路径时,最好不要使用 -hierarchical 参数,路径中使用/显示描述路径的层级。
  • 不要对组合逻辑的网线附加约束。它们很可能会被合并到一个 LUT 中并从网表中消失。
  • 1.4 创建实现约束
    在某些情况下,综合网表中的对象名称与 Elaborated Design 中的名称不同。如果是这种情况,就必须使用正确的名称重新创建一些约束,并将它们保存在仅用于实现的 XDC 文件中。当工具可以正确加载所有 XDC 文件后,就可以运行时序分析以便:

  • 添加缺少的约束,例如输入和输出延迟。
  • 添加时序例外,例如伪路径、多周期路径和最小/最大延迟约束。
  • 识别由于设计中的长路径而导致的严重违规,修改 RTL 代码。
  • 在综合期间,为了提高设计性能,有些寄存器可能被复制。但综合器不会把复制的单元添加到用户 XDC 约束中。如要将时序约束附加到 Vivado Synthesis 复制的对象上,根据约束的写入方式不同,复制的单元有可能不会被 XDC 约束覆盖到,这可能会影响结果的实现质量。可以使用 -include_replicated_objects 参数来避免此问题。

    例如 set_false_path –from [get_cells –hierarchical *rx_reg] 可以改为 set_false_path -from [get_cells -hierarchical *rx_reg -include_replicated_objects] 。

    下面几个例子都可以获取到被复制的单元。ORIG_CELL_NAME 表示原单元名称。另外注意 -filter 和 -include_replicated_objects 不能一起使用,因为被复制的名称为 *reg_replica* ,会被 -filter 过滤掉。

    get_cells -include_replicated_objects *rx_reg
    get_cells -include_replicated_objects [get_cells -hier -filter {NAME =~ *rx_reg}]
    get_cells -hierarchical -filter {NAME =~ *rx_reg || ORIG_CELL_NAME =~ *rx_reg}

    1.4.1 对黑盒的约束
    对于使用OOC模式的黑盒模块,顶层约束只能够访问到黑盒的输入输出脚。

  • 在 OOC 模块中自动推衍出的时钟,不能对其进行重命名。
  • 不能引用 OOC 模块内部定义的时钟名称。传播到 OOC 模块输出的时钟是根据连接到模块端口的网线命名的,而不是根据它在模块内部的名称,即使时钟在模块 XDC 内部被重命名。
  • 如果顶级约束需要引用来自 OOC 模块的时钟,则应使用诸如 get_clocks -of_objects [get_pins ] 之类的查询语句。
  • 1.5 约束范围
    如果有需要,可以选择将来自某个 XDC 文件的约束范围限定到特定的模块或单元。这对于在没有任何顶层信息的情况下创建和应用约束到子级模块很方便。模块级约束必须独立于顶级约束开发,并且必须尽可能通用,以便它们可以在各种环境中使用。它们也不得影响超出块范围的任何逻辑。默认情况下,Vivado 中生成的所有 IP 核都使用此机制将其约束加载到工程中。

    1.5.1 XDC 范围属性

  • SCOPED_TO_REF:此属性采用模块名称。约束仅应用于指定模块的所有实例。
  • SCOPED_TO_CELLS:此属性采用分层单元名称列表。约束范围被单独应用于每个分层单元。
  • SCOPED_TO_REF + SCOPED_TO_CELLS:如果指定了这两个属性,则约束将应用于 SCOPED_TO_CELLS 列表的每个单元格,位于 SCOPED_TO_REF 指定的模块内。
  • # SCOPED_TO_REF 指定模块名:
    set_property SCOPED_TO_REF uart_tx_ctl [get_files uart_tx_ctl.xdc]

    # SCOPED_TO_CELLS 指定实例名:
    set_property SCOPED_TO_CELLS uart_tx_i0/uart_tx_ctl_i0 [get_files uart_tx_ctl.xdc]

    # SCOPED_TO_CELLS 指定实例名,SCOPED_TO_REF 指定上层模块名:
    set_property SCOPED_TO_REF uart_tx [get_files uart_tx_ctl.xdc]
    set_property SCOPED_TO_CELLS uart_tx_ctl_i0 [get_files uart_tx_ctl.xdc]

    当一个模块被例化多次时,可使用如下约束。ORIG_REF_NAME 指定模块名。

    set_property SCOPED_TO_REF [get_cells -hierarchical -filter {ORIG_REF_NAME == uart_tx_ctl}] [get_files uart_tx_ctl.xdc]

    1.5.2 XDC 范围机制
    除了端口,约束范围依赖于 current_instance 机制,它是 (SDC) 标准的一部分。当使用 current_instance 命令将范围设置为某个设计层次结构时,对象查询命令只能返回包含在该级别或以下级别的对象。

    唯一的例外是时序时钟对象和网表端口:

    时序时钟对象由 create_clock 或 create_generated_clock 定义。无论当前的实例设置如何,它们在整个设计中都是可见的。 get_clocks 命令可以查询当前实例中不存在或传播到当前实例之外的时钟。 Xilinx 不建议在构建范围约束时在时钟上定义时序例外,除非时钟完全包含在当前实例中。要在 XDC 中引用时钟时,必须已经先定义了该时钟。当引用在定义之前时,可能需要更改项目中 XDC 文件的顺序。

    即使使用 current_instance 命令将范围设置为较低级别的实例时,get_ports 命令依然会返回顶级端口。但是,当使用 read_xdc -ref/-cells 命令读取范围为较低级别实例的 XDC 文件时,或者在设置 SCOPED_TO_REF/SCOPED_TO_CELLS 文件属性后加载设计时,get_ports 命令的行为是不同的:

  • 与 get_ports 一起使用的端口名称是作用域实例接口的端口名称,而不是顶级端口名称。
  • 如果作用域实例端口直接连接到顶级端口,则 get_ports 命令返回顶级端口,并将约束应用于顶级端口。
  • 如果在作用域实例端口和顶级端口之间存在任何单元,包括 IO 和时钟缓冲器,则 get_ports 命令变为 get_pins 命令并返回作用域实例引脚。
  • 1.5.3 范围查询指南
    get_cells/get_nets/get_pins 对象查询仅限于作用域实例及其子级别。其中对象的 NAME 属性显示了对象相对于顶层的完整层次结构路径,而不仅仅是范围实例。

    如果在 NAME 属性上使用 get_* 命令的 -filter 选项,则必须使用 glob 字符串匹配运算符,并提供以 * 开头的模板。例如 get_nets -hierarchical -filter {NAME =~ *clk} 。

    如果 Block/IP 的端口直接连接到顶级端口,则 get_ports 返回顶级端口。否则,get_ports 返回一个分层引脚。

    网表辅助命令也有范围: all_ffs 、all_latches 、all_rams 、all_registers 、all_dsps 、all_hsios 仅返回当前实例中包含的实例。

    IO 辅助命令不能在范围约束 XDC 中使用: all_inputs 、all_outputs

    时钟命令没有作用域,将返回您设计的所有时序时钟。get_clocks、all_clocks

    可以通过使用 get_clocks -of_objects 探测网表,查询顶级和本地时钟对象。

    使用 get_clocks -of_objects [get_ports ] 检索进入当前实例的时钟

    使用 get_clocks -of_objects [get_pins ] 检索当前实例内部自动生成的时钟,其中 instName 是时钟生成器实例。

    使用 -of_objects 选项可以查询设计中的任何对象:例如:get_pins -leaf -of_objects [get_nets local_net]

    支持查询连接到当前实例接口网络的顶级端口:get_ports -of_objects [get_nets ]

    不允许查询IP/子模块接口引脚。例如 get_pins clk 返回错误。

    路径跟踪命令也有作用域:all_fanin/all_fanout 遍历作用域设计并在其边界处停止。

    使用 get_cells/get_pins/get_nets 命令并指定详细的路径,而不是使用带有 -clock 选项的 all_registers 命令来查询连接到特定时钟的所有单元。因为 all_registers 返回的列表可能非常大,而只有少数对象需要约束。这会对运行时产生负面影响。

    1.5.4 范围时序约束指南
    为避免对顶层设计产生负面影响,重要的是确保给 IP 或模块编写的时序约束不会传播到其范围之外。例如,进入到 IP 或模块的两个时钟,在其范围约束 XDC 中定义不相关路径,但这种不相关性可能不适用于整个设计的其余部分。如果这两个时钟在设计的其余部分相关时,这个约束则会引起问题。再如,范围约束 XDC 文件中定义的时序例外可能比顶级约束具有更高的优先级,并且可以覆盖它们,这同样是不希望的。为避免这种情况,建议将约束应用于 IP 本地的网表对象。在两个全局时钟之间存在不相关路径的情况下,时序例外路径也必须从 IP 内的一组起点单元应用到 IP 内的另一组终点单元。这种技术被称为点对点时序例外而不是全局时序例外。

    1.5.5 IP/子模块XDC的推荐约束规则

    块级约束必须符合以下规则:

    如果期望顶层设计中定义时钟,则不要在块级约束中创建时钟。可以使用 get_clocks -of_objects 的方式在块内查询时钟。示例:

    set blockClock [get_clocks -of_objects [get_ports clkIn]]

    如果确实需要在模块内部定义时钟,则它必须位于输入或双向端口上,并且此端口必须直接驱动输入/双向缓冲器的。再或者位于创建/转换时钟的单元的输出上。例如:带有输入缓冲器的输入时钟、时钟分频器和 GT 恢复时钟。

    仅当端口直接连接到顶级端口,并且 I/O 缓冲区在 IP 内例化时,才指定输入和输出延迟。

    不要定义两个未绑定到 IP 的时钟之间的时序例外。

    不要按名称引用时钟,因为名称可能会因顶级时钟名称或模块被多次例化而有所不同。

    如果模块可以在同一个顶层设计中多次实例化,则不要添加布局约束。

    1.6 约束效率
    1.6.1 检阅约束覆盖率
    在编写时序约束时,应当保持约束简单,并仅在相关网表对象上指定约束。低效约束会导致更长的运行时间和更大的内存消耗。低效约束还可能产生不当约束,因为时序例外覆盖的路径可能会比预期更多,并与其他约束发生冲突。

    Vivado 提供了多种获取时序例外反馈的方法:

    1. 方法学检查 XDCB-1 ( report_methodology ) 报告引用大型对象集合(超过 1000)的时间约束。
    2. 报告例外命令 (report_exceptions) 提供有关已定义的时序例外的覆盖和冲突信息。

    Xilinx 建议仔细分析以下报告:

    report_exceptions -scope_override
    该报告会列出顶层时序约束和范围时序约束部分或全部重叠的部分。但是,它不会报告一个范围时序约束和另一个范围时序约束间的重叠部分。此选项可用于验证IP 约束没有被用户的顶级约束未覆盖 。

    report_exceptions –coverage
    该报告为每个时序例外提供了一个逻辑路径的覆盖范围。将传递给时序例外的对象数量与有效覆盖的起点和终点数量进行比较。我们应该注意查看在对象数量和起点/终点数量之间具有显着差异的约束。

    report_exceptions –ignored
    此报告提供了被其他时序约束覆盖的时序约束列表(例如,被 set_clock_group 覆盖的 set_false_path)。我们应该检查有覆盖的约束的正确性或删除无用的约束。

    report_exceptions –ignored_objects
    此报告提供了被忽略的起点和终点的列表。例如,不存在从这些起点出发的路径或到不存在到达这些终点的路径。

    1.6.2 提升约束运行效率
    由于设计中的管脚数是单元数的数倍,因此使用 get_pins 比 get_cells 会对运行时间产生重大影响。在处理 XDC 约束(例如 open_checkpoint 运行时)或执行 Tcl 脚本时,可能会遇到运行效率下降。 Xilinx 建议利用引脚和单元对象之间的关系来加快大量引脚查询的运行时间。与其在设计中的所有引脚中直接根据引脚名称查找特定的引脚列表,不如先找到所需引脚的单元,然后再对这一次查询结果进行过滤,以此对所需引脚进行查询。

    # 直接对整个设计中的所有PIN进行查询,效率低
    get_pins –hier * -filter {NAME=~xx*/yy*}
    # 可以替换成如下两种方法,以提升运行效率
    get_pins –filter {REF_PIN_NAME=~yy*} –of [get_cells –hier xx*]
    get_pins –filter {REF_PIN_NAME=~yy*} –of [get_cells –hier * -filter {NAME=~xx*}]

    # 如下示例,直接查询PIN
    set_max_delay 15 -from [get_pins -hier -filter {NAME=~*/aclk_dpram_reg*/*/CLK}] \
    -to [get_cells -hier -filter {NAME=~*/bclk_dout_reg*}] -datapath_only
    # 可替换如下写法
    set_max_delay 15 -from [get_pins -of [get_cells -hier –filter
    {NAME =~ *aclk_dpram_reg*/*}] -filter {REF_PIN_NAME == CLK}] \
    -to [get_cells -hier bclk_dout_reg*] -datapath_only

    最新文章

    最新文章