2. 定义时钟
2.1 关于时钟
为了获得最佳精度路径覆盖信息,必须正确定义时钟。
- 时钟要定义在时钟树的根 pin 或 port 上,称为 source point。
- 时钟的边缘应该由周期和波形进行组合描述。
- 周期使用纳秒做为单位进行定义。它对应于波形重复的时间。
- 波形是一系列的上升沿和下降沿绝对时间列表,单位为纳秒,并且所有时间在一个时钟周期内。列表必须包含偶数个值。第一个值始终对应于第一个上升边缘。如果没有指定波形,波形的默认占空比为 50%,相移为 0。
2.1.1 传播时钟
周期和波形属性只展现出了时钟的理想特性。当时钟进入 FPGA 并通过时钟树传播时,时钟边沿被延缓,并受噪声和硬件行为引影响。这些特性称为时钟网络延迟和时钟不确定性。时钟的不确定性包括:
- 时钟抖动(clock jitter)
- 相位错误
- 用户指定添加的不确定性
默认情况下,Vivado 在做时序分析时,始终将时钟视为传播时钟,即非理想时钟,以此提供准确的余量值,其中包括时钟树插入延迟和不确定性。
2.1.2 专用硬件资源
FPGA 有大量专用的时钟管脚,这个管脚可以专门用来做时钟的输入。FPGA 内部包含有 MMCM、PLL 和 BUR 之类的时钟资源。
2.2 基准时钟(Primary Clock)
基准时钟是通过 FPGA 输入端口或千兆收发器输出引脚(例如,恢复时钟)进入设计的时钟。基准时钟只能通过 create_clock
指令进行定义。(为什么是千兆收发器?下面的话应该可以解释,7 系列的 GT 恢复时钟不能自动推导,必须手动定义。而 US 和 USP 系列的可以自动推导,不需要人为定义)
Primary clocks must be defined on a gigabit transceiver output only for Xilinx® 7 series FPGAs. For UltraScale and UltraScale+™ devices, the timer automatically derives clocks on the GT output ports.
基准时钟必须附加到网表对象。该网表对象代表设计中的所有时钟边沿起点,并且是时钟树上向下游传播的起点。换句话说,基准时钟的源点定义了零时间点,这个点被 Vivado 用来计算余量方程时,作为时钟延迟和不确定性的零起点。Vivado 会忽略来自定义基准时钟点上游单元的所有时钟树延迟。如果基准时钟错误的定义在了路径中间的引脚上,则只有部分延迟用于时序分析。
这可能会引起问题,因为时钟之间的偏斜和余量值会变得不准确。
2.2.1 基准时钟示例
# 周期 10ns, 来源于外部,通过 sysclk 端口输入,占空比 50%,相位为 0。
create_clock -period 10 [get_ports sysclk]
# 周期 10ns, 来源于外部,通过 ClkIn 端口输入,占空比 25%,相位为 90。
create_clock -name devclk -period 10 -waveform {2.5 5} [get_ports ClkIn]
# GT 的恢复时钟无法自动推导时,需要手动约束。Vivado 在计算余量时,会从RXOUTCLK开始。
create_clock -name rxclk -period 3.33 [get_pins gt0/RXOUTCLK]
# 对于差分时钟,时钟必须定义在 P 端上,N 端上不能有定义。如果 P 和 N 各自定义一次,会导致软件认为是异步路径。
create_clock -name sysclk -period 3.33 [get_ports SYS_CLK_clk_p]
2.3 虚拟时钟(Virtual Clocks)
虚拟时钟是一种没有物理连接到设计中任何网表元素的时钟。虚拟时钟是通过 create_clock
指令定义的,但无需指定源对象。虚拟时钟通常用于指定输入和输出延迟约束:
# 创建时钟,但不指定时钟源
create_clock -name clk_virt -period 10
2.4 衍生时钟(Generated Clocks)
2.4.1 关于衍生时钟
衍生时钟产生于 FPGA 设计内部,通常由 MMCM 或用户逻辑产生。衍生时钟有一个关联的主时钟(master clock),指令 create_generated_clock
需要指定一个主时钟,它可以是基准时钟或者是另一个衍生时钟。衍生时钟属性直接源自其主时钟,定义衍生时钟时,不是指定它们的周期或波形,而是描述如何转换主时钟到衍生时钟。衍生时钟和主时钟之间的关系可以是以下任何一种:
- 简单的分频
- 简单的倍频
- 分频和倍频的组合,用来得到一个非整数比的分频。
- 移相或反相
- 改变占空比
- 所有上面的组合
为了计算衍生时钟的延迟,工具会跟踪衍生时钟的源引脚和主时钟的源引脚之间的时序路径和组合路径。在某些情况下,可能需要仅跟踪组合路径以计算生成的时钟延迟。可以使用
-combinational
行选项执行此操作。
2.4.2 用户自定义的衍生时钟
2.4.2.1 示例1:简单的2分频
create_clock -name clkin -period 10 [get_ports clkin]
# Option 1: master clock source is the primary clock source point
create_generated_clock -name clkdiv2 -source [get_ports clkin] -divide_by 2 [get_pins REGA/Q]
# Option 2: master clock source is the REGA clock pin
create_generated_clock -name clkdiv2 -source [get_pins REGA/C] -divide_by 2 [get_pins REGA/Q]
2.4.2.2 示例2:使用 -edge 选项进行2分频
可以不使用 -divide_by 选项,而是使用 -edges 选项直接基于主时钟边沿描述衍生时钟波形。该参数是一组主时钟边沿的序号,用来标记衍生时钟的跳变沿的位置。从衍生时钟的上升沿开始描述。
# waveform specified with -edges instead of -divide_by
create_generated_clock -name clkdiv2 -source [get_pins REGA/C] -edges {1 3 5} [get_pins REGA/Q]
2.4.2.3 示例3:使用 -edge 和 -edge_shift 选项改变占空比和相位
当需要做移相时,可以使用 -edge_shift
选项。衍生时钟的每个边沿都可以单独的进行正向或负向移相。-edge_shift
选项 不能和以下选项同时使用:
- -divide_by
- -multiply_by
- -invert
假设主时钟 clkin 的周期为 10 ns,占空比为 50% 。clkin 输入到 mmcm0 后,衍生出一个时钟,其占空比为 25%,移相 90 度。衍生时钟定义基于主时钟的第 1、2 和 3 边沿。这些边沿跳变分别发生在 0ns、5ns 和 10ns 上。要获得所需的波形,将第一和第三边沿移动 2.5ns。
create_clock -name clkin -period 10 [get_ports clkin]
# First rising edge: 0ns + 2.5ns = 2.5ns
# Falling edge: 5ns + 0ns = 5ns
# Second rising edge: 10ns + 2.5ns = 12.5ns
create_generated_clock -name clkshift -source [get_pins mmcm0/CLKIN] -edges {1 2 3}
-edge_shift {2.5 0 2.5} [get_pins mmcm0/CLKOUT]
注意:
-edge_shift
的值可以为正数,也可以为负数。
2.4.2.4 示例4:同时使用 -divide_by 和 -multiply_by
Vivado 允许同时指定 -divide_by
和 -multiply_by
,这是对 SDC 的扩展。虽然这对于手动定义 MMCM 或 PLL 生成的时钟特别方便,但是 Xilinx 建议让软件自动创建这些约束。如果手动定义了约束,必须确认约束的设置和锁相环本身的配置是相匹配的。
# 假设 MMCM 生成的时钟频率为原主时钟的 4/3。
create_generated_clock -name clk43 -source [get_pins mmcm0/CLKIN] -multiply_by 4
-divide_by 3 [get_pins mmcm0/CLKOUT]
2.4.2.5 示例5:追踪主时钟的组合逻辑路径
在此示例中,假设主时钟同时驱动基于寄存器的时2分频器和时钟多路复用器,时钟多路复用器可从选择主时钟或2分频时钟。在此方案中,从主时钟到生成的时钟有两条路径,即时序逻辑路径和组合逻辑路径。我们希望在多路复用器输出上创建一个衍生时钟,该输出反映了从主时钟到多路复用器的组合路径的延迟。这可以通过使用 -combinational
选项完成的:
create_generated_clock -name clkout -source [get_pins mmcm0/CLKIN] -combinational [get_pins MUX/O]
2.4.2.6 示例6:由 ODDR 驱动的转发时钟
在此示例中,由 ODDR 单元驱动的输出端口上创建转发时钟。转发时钟参考驱动 ODDR/CLKDIV 引脚的主时钟,并且与主时钟(-divide_by 1) 具有相同的周期。
create_generated_clock -name ck_vsf_clk_2 -source [get_pins ODDRE1_vsfclk2_inst/CLKDIV] -divide_by 1 [get_ports vsf_clk_2]
2.4.3 自动推导出的衍生时钟
自动推导的时钟也称为自动生成时钟。Vivado 会自动在 CMB( Clock Modifying Blocks)的输出引脚上创建这些约束,前提是相关的主时钟已经定义。
- Xilinx 7 系列的 CMB 可以是:
- MMCM*/ PLL*
- BUFR
- PHASER*
- Xilinx UltraScale 系列的 CMB 可以是:
- MMCM* / PLL*
- BUFG_GT / BUFGCE_DIV
- GT* _COMMON / GT*_CHANNEL / IBUFDS_GTE3
- BITSLICE_CONTROL / RX*_BITSLICE
- ISERDESE3
如果用户定义的时钟(主时钟或衍生时钟)也在同一网列表对象(即在同一定义点(pin 或 net)上定义,Vivado 则不会自动创建衍生时钟。
2.4.3.1 自动衍生时钟示例
以下自动衍生时钟示例是由 MMCM 生成的时钟。 主时钟 clkin 驱动 MMCME2 实例 clkip/mmcm0 的输入 CLKIN。自动生成的时钟的名称是 cpuClk,其定义点是 clkip/mmcm0/CLKOUT。
使用
get_clocks -of_objects <pin/port/net>
命令在不知道其名称的情况下查询自动生成的时钟。这使的约束或脚本相对通用,不用关心时钟名称是否有改动。
2.4.3.2 本地网名
如果 CMB 实例位于设计层次结构内,则生成的时钟名称将使用本地网名(即没有父单元名的名称)。例如,对于名称为 clkip/cpuClk 的层次网线:
- 父单元名称为 clkip 。
- 生成的时钟名称为 cpuClk。
2.4.3.3 名称冲突
如果两个自动生成的时钟之间的名称有冲突,Vivado 会添加独有的后缀来区分它们,例如:
- usrclk
- usrclk_1
- usrclk_2
强制修改衍生时钟的名称:
- 在 RTL 中选择独特且相关的网名。
- 使用
create_generated_clock
强制使用指定的名称。
2.4.4 重命名自动衍生时钟
可以对工具自动创建的衍生时钟进行重命名。重命名通过使用 create_generated_clock
指令和有限的参数完成。
create_generated_clock -name new_name [-source master_pin] [-master_clock master_clk] source_object
必须指定的参数有新生成的时钟名称和生成时钟的源对象。生成时钟的源对象是创建衍生时钟的对象(CMB 的输出引脚、UltraScale GT 的输出引脚等)。只有当多个时钟通过源引脚传播时,才能使用源和主参数,以消除任何模糊性。当有多个时钟通过源对象传播时,必须指定 -source
和 -master
参数,以消除任何不明确的地方。
注意:如果有
-edges
/-edge_shift
/-divide_by
/-multiply_by
/-combinational
/-duty_cycle
/-invert
选项传递到create_generated_clock
指令,则自动生成衍生时钟不会被重命名,相反会重新定义一个新的衍生时钟。
注意:使用 OOC 模式的模块在综合时,模块被当做黑盒,模块内部引脚和时钟名称不可访问。在这种情况下,用于综合的顶层 XDC 约束不能指定时钟名称或重命名模块内生成的自动衍生时钟。可以使用一些查询指令引用相关目标,如
get_clocks -of_objects [get_pins <OOC_MODULE_OUTPUT_CLOCK_PORT>]
。用于实现的 XDC 约束没有此限制。
重命名的限制:
- 自动衍生时钟只能在其源引脚上重命名,例如在 CMB(PLL、MMCM. .. ) 的输出处。自动衍生时钟不能在 BUFG 的输出上重命名,即便时钟是通过它传播的。
- 无法重命名基准时钟或用户定义衍生时钟。只有自动衍生时钟才能使用此机制进行重命名。
- source_object 必须匹配创建自动衍生时钟的对象。
- 如果工具无法重命名衍生时钟,则会返回错误。重命名完成时,主时钟也必须存在。
- 自动衍生时钟可以在 XDC 内的任何时间重命名,即使已被某些时序约束引用。
2.5 时钟组(Clock Groups)
2.5.1 关于时钟组
默认情况下,Vivado 会对设计中所有时钟之间的路径进行时序收敛,除非使用了时钟组或伪路径进行约束。set_clock_groups
指令会让 Vivado 不对时钟组之间的路径进行时序分析,而同一组内的时钟之间的仍会进行时序收敛。与 set_false_path
约束不同,两个时钟之间的两个方向的路径都会被忽略。
可以多次使用 -group
选项指定多个时钟组。如果组中的时钟在设计中都不存在,则组将变为空。set_clock_groups
约束至少需要两组,并且都不为空组时才有效。如果只有一个组有效,其他组都为空时,set_clock_groups
约束不会生效,并返回错误消息。
使用原理图查看器(Schematic Viewer)或时钟网络报告(Clock Networks Report)查看可视化时钟树的拓扑,确定哪些时钟不能一起进行收敛。您还可以使用时钟交互报告来(Clock Interactions Report)查看两个时钟之间的现有约束,并确定它们是有相同的主时钟(即它们具有已知的相位关系),或者判断出周期没有公倍数的时钟(Unexpandable)。
谨慎!忽略两个时钟之间的时序分析并不意味着它们之间的路径将在硬件上能正常工作。为了防止亚稳态,必须确认这些路径是否具有适当的同步电路或异步数据传输协议。
2.5.2 时钟分类
-
同步时钟
当两个时钟的相对相位关系是已知的,它们就是是同步时钟。通常它们的时钟树源头来自网列表中的同一根,它们的周期有公倍数。例如,衍生时钟和他的主时钟的周期比率为 2,这两个时钟是同步的。因为它们有相同时钟源点,并且周期为2倍关系。它们可以安全地一起进行时序收敛。 -
异步时钟
当无法确定两个时钟的相对相位关系时,这两个时钟就是异步的。例如,由板上两个独立晶振生成的时钟,通过不同输入端口进入 FPGA,这两个时钟就是异步的。如果它们是由板上的同一晶振生成的,这两个就不是异步时钟。在大多数情况下,基准时钟可以被视为异步时钟。 -
不可扩展的时钟(Unexpandable Clocks)
当时序引擎在 1000 个周期中无法找到两个时钟周期的公倍数时,则认为两个时钟无法扩展。在这种情况下,在时序分析时会使用 1000 周期中最小的相位关系,但时序引擎无法保证这是最差的情况。通常这两个时钟之间的周期比比较奇怪的情况。例如,两个时钟 clk0 和 clk1,由相同主时钟的两个 MMCM 生成,clk0 周期为 5.12 ns,clk1 周期为 6.66 ns。他们的上升沿在 1000 个周期内没有对齐的时候,时序引擎会取最差的情况 0.01 ns 做时序收敛。与异步时钟一样,余量计算会正常进行,但其值是不可信的。因此,无可扩展的时钟经常被处理为异步时钟,必须用处理异步时钟相同的方式对待这两个时钟,包括其约束和异步电路。
2.5.3 异步时钟组
异步时钟和不可扩展时钟不能被时序收敛。使用 set_clock_groups
指令可以在时序分析时忽略它们之间的时序路径。
注意:
set_clock_groups
比普通的时序例外的优先级要高,如果需要约束和报告异步时钟间的路径,那就不能使用set_clock_groups
,只能使用时序例外。
2.5.3.1 异步时钟组示例
- 基准时钟 clk0 定义在输入管脚上,并连接到了 MMCM。MMCM 生成了 usrclk 和 itfclk 两个时钟 。
- 另一个基准时钟 clk1 定义在了 GTP 输出的恢复时钟上,并连接到了另一个 MMCM。此 MMCM 生成了 gtclkrx 和 gtclktx 两个时钟。
使用 -asynchronous
选项创建异步时钟组。
set_clock_groups -name async_clk0_clk1 -asynchronous -group {clk0 usrclk itfclk} -group {clk1 gtclkrx gtclktx}
如果衍生时钟的名称无法事先得知,可以使用 get_clocks -include_generated_clocks
动态获取。所以上面的约束也可以写成如下方式,其移植性更强。
set_clock_groups -name async_clk0_clk1 -asynchronous -group [get_clocks -include_generated_clocks clk0] -group [get_clocks -include_generated_clocks clk1]
注意:上面的约束中,异步是指组与组之间异步,组内各时钟仍会进行时序分析和收敛。
2.5.4 独占时钟组(Exclusive Clock Groups)
有些设计拥有多种操作模式,在不同的模式下需要使用不同的时钟。时钟之间的选择通常使用时钟多路复用器完成,如 BUFGMUX 和 BUFGCTRL 或 LUT(尽量不使用LUT做时钟选择)。由于这些单元是组合逻辑,所这些时钟都通过同一个时钟树传播。这些时钟会同时报告中呈现,但在硬件方面是不可能的,同一时刻只会有一个时钟。这种不会同时工作的时钟称作独占时钟。
2.5.4.1 独占时钟组示例
独占时钟使用 set_clock_groups
的 -logically_exclusive
或 -physically_exclusive
选项进行定义。在 Vivado 中,这两个选项的意义是相同的,任意使用一个即可。
假设一个 MMCM 输出了 clk0 和 clk1,这两个时钟连接到了一个 BUFGMUX(实例名为clkmux),输出 clkmux 驱动时钟树。默认情况下,Vivado 会分析 clk0 和 clk1 之间的路径,即便两个时钟驱动同一个时钟树,并且两个时钟不可能同时使用。必须使用如下约束停止分析两个时钟之间的路径。
set_clock_groups -name exclusive_clk0_clk1 -physically_exclusive -group clk0 -group clk1
2.6 时钟延迟、抖动和不确定性
除了定义时钟波形外,还必须指定与操作条件和环境相关的可预测变化和随机变化。
2.6.1 时钟延迟
时钟在 PCB 板上和 FPGA 内部传播后,时钟沿会经过一段延时后到达目的地。此延时通常有:
- 源延时(通常在时钟源点之前,在 FPGA 设备外部)。
- 网络延时。
网络延时(也称为插入延时),其延时值要么是自动估算(pre-route design),要么是精确计算(post-route design)。
Xilinx FPGA 使用 set_clock_latency
指令主要是用来指定器件外部的延时。
# Minimum source latency value for clock sysClk (for both Slow and Fast corners)set_clock_latency -source -early 0.2 [get_clocks sysClk]# Maximum source latency value for clock sysClk (for both Slow and Fast corners)set_clock_latency -source -late 0.5 [get_clocks sysClk]
2.6.2 时钟不确定性
2.6.2.1 时钟抖动
对于 ASIC 设备,时钟抖动通常表示在时钟不确定性特征中。然而,对于 FPGA 来说,抖动特性是可以预知的。它们可以通过时序分析引擎自动计算,也可以单独指定。
-
输入抖动(Input Jitter)
输入抖动是连续时钟边缘与理想时钟到达时间的差别。输入抖动是一个绝对值,表示时钟边缘两侧的变化。使用set_input_jitter
指令单独指定每个基准时钟的输入抖动。衍生时钟上的输入抖动无法直接指定,Vivado 时序引擎会自动从主时钟继承的抖动到衍生时钟。- 对于由 MMCM 或 PLL 生成的时钟,输入抖动被计算的不同的抖动替换。
- 对于由组合逻辑或时序逻辑生成的时钟,生成时钟抖动与其主时钟抖动相同。
以下命令在通过输入端口 clkin 传播的基准时钟上设置 +/-100 ps 抖动:
set_input_jitter [get_clocks -of_objects [get_ports clkin]] 0.1
-
系统拉动(System Jitter)
系统抖动是由于电源噪声、板噪声或系统的任何额外抖动而导致的整体抖动。使用set_system_jitter
指令只为整个设计设置一个值,即针对所有时钟。
2.6.2.2 附加时钟不确定性
使用 set_clock_uncertainty
指令定义不同角落、延时或特定时钟关系所需的额外时钟不确定性。这一种方便为设计增加额外余量的方法。
无论约束的顺序如何,时钟相互间的不确定性总是优先于简单的时钟不确定性。在下示例中,虽然时钟 clk1 上最后定义了 1.0 ns 的简单时钟不确定性,但从时钟 clk1 到时钟 clk2 的计时路径受到 2.0 ns 时钟不确定性的限制。
set_clock_uncertainty 2.0 -from [get_clocks clk1] -to [get_clocks clk2]set_clock_uncertainty 1.0 [get_clocks clk1]
文章来源: 博客园
- 还没有人评论,欢迎说说您的想法!