时序约束系列:
看其他书也就图一乐,真要学习还是得看 Xilinx。(开个玩笑 )
在数字设计中,时钟代表可靠地将数据从寄存器传送到寄存器的时间参考。Vivado IDE 通过时序引擎使用时钟特性来计算时序路径需求,通过裕量计算(slack computation)报告设时序序裕量。
时钟必须正确定义,以获得最佳精度下的最大时序路径覆盖率。时钟具有以下特征:
上面时钟的描述:
Clk0: period = 10, waveform = {0 5}
Clk1: period = 8, waveform = {2 8}
上面的是理想时钟的描述,实际有抖动、偏斜等特性。
period 和 waveform 特性代表了理想的时钟特性。当进入FPGA并通过时钟树传播时,时钟边缘被延迟,并受到噪声和硬件行为的影响。这些特征称为时钟网络延迟(clock network latency)和时钟不确定性(clock uncertainty)。
时钟不确定性包括:
默认情况下,Vivado IDE总是将时钟视为传播时钟,即非理想时钟,以便提供一个准确的松弛值,包括时钟树插入延迟和不确定性。
主时钟是通过输入端口或千兆收发器输出管脚(例如,一个恢复的时钟)进入设计的板级时钟。
主时钟只能通过 create_clock 命令定义。
主时钟必须附加到网表对象上。这个网表对象代表了时钟树中所有时钟边沿的起源和传播点。换句话说,主时钟的源点定义了Vivado IDE在计算松弛方程中使用的时钟延迟和不确定性时使用的时间零点。
注意:Vivado IDE忽略所有来自于主时钟定义点上游单元的时钟树延迟。如果在设计中的某个 pin 上定义了一个主时钟,那么它的延迟只有一部分用于时间分析。如果该时钟与设计中的其他相关时钟交互,可能存在问题,因为时钟之间的偏斜,以及因此产生的松弛值可能不准确。
必须首先定义主时钟,因为其他时序约束经常引用它们。
主时钟定义的例子:
上图时钟:
create_clock -period 10 [get_ports sysclk]
如果有一个 周期 10ns、占空比 25 %、相位偏移 90° 的时钟 devclk 接在 ClkIn 端口上:
create_clock -name devclk -period 10 -waveform {2.5 5} [get_ports ClkIn]
高速收发器主时钟定义的例子:
create_clock -name sysclk -period 3.33 [get_ports SYS_CLK_clk_p]
虚拟时钟是指在设计中没有物理连接到任何网表元素的时钟。
虚拟时钟是通过 create_clock 命令定义的,不指定源对象。
虚拟时钟通常用于指定以下情况下的输入和输出延迟约束:
虚拟时钟必须在输入和输出延迟约束使用之前定义。
Generated Clock 在设计内部由称为时钟修改块(Clock Modifying Block)的特殊单元驱动(例如,MMCM)或某些用户逻辑。
生成的时钟与主时钟相关联。create_generated_clock 命令考虑主时钟的起始点。主时钟可以是一个主时钟或另一个生成的时钟。
生成时钟属性直接来自于它们的主时钟。而不是指定周期或波形,必须描述修改电路如何转换主时钟。
主时钟和生成时钟之间的关系可以是以下任何一种:
定义生成时钟前首先定义所有主时钟。它们是定义生成的时钟所需要的。
注意:为了计算生成时钟的延迟,时序分析工具跟踪生成时钟的源引脚和主时钟的源引脚之间的时序和组合路径。在某些情况下,可能希望只通过组合路径跟踪来计算生成时钟延迟。可以使用-combinational命令行选项来实现这一点。
用户定义生成的时钟为:
使用-source选项指定主时钟。这表示设计中主时钟传播所通过的引脚或端口。通常使用产生的时钟源单元的主时钟源点或输入时钟引脚。
例子:
# 主时钟
create_clock -name clkin -period 10 [get_ports clkin]
# 1 clock source 是主时钟源点
create_generated_clock -name clkdiv2 -source [get_ports clkin] -divide_by 2 [get_pins REGA/Q]
# 2 clock source 是REGA时钟引脚
create_generated_clock -name clkdiv2 -source [get_pins REGA/C] -divide_by 2 [get_pins REGA/Q]
另外还有一些其他选项的使用:
# 通过 -edges 替换 -divide_by 约束2分频时钟
create_generated_clock -name clkdiv2 -source [get_pins REGA/C] -edges {1 3 5} [get_pins REGA/Q]
可以使用 -edges, -edge_shift 选项实现占空比改变和相移。
create_clock -name clkin -period 10 [get_ports clkin]
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]
# First rising edge: 0ns + 2.5ns = 2.5ns
# Falling edge: 5ns + 0ns = 5ns
# Second rising edge: 10ns + 2.5ns = 12.5ns
自动派生时钟也称为自动生成时钟。Vivado IDE自动在时钟修改块(CMBs)的输出管脚上创建这些约束,前提是已经定义了相关的主时钟。
Xilinx 7器件,CMB包含:
UltraScale器件,CMB包含:
给自动生成时钟重命名:
可以重命名由工具自动创建的生成的时钟。重命名过程包括调用create_generated_clock命令和有限数量的参数:
create_generated_clock -name new_name [-source master_pin] [-master_clock master_clk] source_object
默认情况下,Vivado IDE会对所有时钟之间的路径进行时序分析,除非通过使用时钟组(clock group)或虚假路径(false path)约束来指定。set_clock_groups命令禁用所识别的时钟组之间的时序分析,而不禁用同一组内的时钟之间的时序分析。与set_false约束不同的是,在两个时钟之间的两个方向上都会忽略时序分析。
可以多次使用-group选项指定多个时钟组。如果在设计中没有时钟组中的时钟,则时钟组为空。set_clock_groups约束仅当至少有两个组有效且不为空时才有效。如果只有一个组仍然有效,而所有其他组都为空,则不应用set_clock_groups约束,会生成错误消息。
使用原理图查看器或时钟网络报告(Clock Networks Report)来可视化时钟树的拓扑结构,并确定哪些时钟不能同时时序分析。还可以使用时钟交互报告(Clock Interactions Report )来查看两个时钟之间的现有约束,并确定它们是否共享相同的主时钟(即,它们具有已知的相位关系),或者标识没有公共周期(不可扩展)的时钟。
注意:忽略两个时钟之间的时序分析并不意味着它们之间的路径可以在硬件上正常工作。为了防止亚稳态,您必须验证这些路径有适当的重新同步( re-synchronization)电路,或异步数据传输协议。
当两个时钟的相对相位可以预测时,它们就是同步的。
当它们的树来自网表中的同一个根,并且它们有一个共同的周期时,通常就是这种情况。
例如,一个生成时钟及其周期比为2的主时钟是同步的,因为它们通过相同的网表资源传播到生成的时钟源点,并且具有两个周期的共同周期。他们可以安全地在一起时序分析。
当不能确定两个时钟的相对相位时,它们就是异步的。
例如,两个时钟分别由板上的振荡器产生并进入FPGA通过不同的输入端口没有已知的相位关系。因此,它们必须被视为异步的。如果它们是由黑板上的同一个振荡器产生的,这就不成立了。
在大多数情况下,主时钟可以被视为异步的。当与它们各自生成的时钟相关联时,它们就形成了异步时钟组。
当共同周期超过1000个周期时,时序引擎不能确定它们的共同周期,两个时钟是不可扩展的。在这种情况下,在时序分析期间使用了1000个周期中最差的setup关系,但时序引擎不能确保这是最悲观的情况。
典型的情况下,两个时钟与奇数小数周期比。例如,考虑两个时钟,clk0和clk1,由两个共享相同主时钟的mmcm生成:
他们的时钟上升沿不会在1000个周期内对齐。时序引擎在两个时钟之间的时序路径上使用0.01 ns的setup路径要求。即使两个时钟在它们的时钟树根处有已知的相位关系,它们的波形也不允许在它们之间进行安全的时序分析。
与异步时钟一样,松弛计算正常出现,但值不可信任。由于这个原因,不可扩展的时钟通常被比作异步时钟。对于约束和跨时钟域电路,这两类时钟必须以相同的方式处理。
异步时钟和不可扩展的时钟不能安全的时序分析。它们之间的时序路径可以通过 set_clock_groups 命令忽略。
注意:set_clock_groups命令的优先级高于常规时序例外(timing exception)。如果需要约束和报告异步时钟之间的一些路径,必须只使用时序例外,而不是set_clock_groups。
异步时钟组的例子:
情景:
创建异步时钟组:
使用-asynchronous选项创建异步时钟组。
set_clock_groups -name async_clk0_clk1 -asynchronous -group {clk0 usrclk itfclk} -group {clk1 gtclkrx gtclktx}
如果无法预先预测生成的时钟的名称,可以使用get_clocks -include_generated_clocks 动态检索,-include_generated_clocks选项是一个SDC拓展。
上面的例子也可以写成:
set_clock_groups -name async_clk0_clk1 -asynchronous \
-group [get_clocks -include_generated_clocks clk0] \
-group [get_clocks -include_generated_clocks clk1]
一些设计有几种操作模式,需要使用不同的时钟。时钟之间的选择通常由时钟多路复用器完成,如BUFGMUX和 BUFGCTRL或一个 LUT(避免使用)。
因为这些单元是组合单元,所以Vivado IDE将所有传入的时钟传输到输出。使用Vivado IDE,时钟树上可以同时存在多个时钟,这对于一次性报告所有操作模式很方便,但在硬件中是不可能的。
这样的时钟被称为独占时钟。使用set_clock_groups选项对它们进行约束:
独占时钟组使用实例
情景L
一个MMCM实例生成连接到BUFGMUX实例clkmux的clk0和clk1。clkmux的输出驱动设计的时钟树。
默认情况下,Vivado IDE会分析clk0和clk1之间的路径,即使这两个时钟共享相同的时钟树,并且不能同时存在。
必须输入以下约束来禁用两个时钟之间的分析:
set_clock_groups -name exclusive_clk0_clk1 -physically_exclusive \
-group clk0 -group clk1
除了定义时钟波形,还必须指定与操作条件和环境相关的可预测和随机变化。
在板上和FPGA内部传播后,时钟边缘以一定的延迟到达目的地。这种延迟通常表示为:
由网络延迟(也称为插入延迟, insertion delay)引入的延迟要么是自动估计(pre-route 设计),要么是精确计算(post-route 设计)。
许多非xilinx时序引擎需要SDC命令set_propagated_clock来触发沿着时钟树的传播延迟计算。Vivado工具不需要此命令。相反,它默认计算时钟传播延迟:
对于Xilinx fpga,主要使用set_clock_latency命令来指定设备外部的时钟延迟。
# sysClk 的最小源延迟(包含slow 和 fast corner)
set_clock_latency -source -early 0.2 [get_clocks sysClk]
# sysClk 的最大源延迟(包含slow 和 fast corner)
set_clock_latency -source -late 0.5 [get_clocks sysClk]
对于ASIC器件,时钟抖动通常用时钟的不确定性来表示。
然而,对于Xilinx fpga,抖动属性是可预测的。它们可以由时序分析引擎自动计算,也可以单独指定。
输入抖动(input jitter)
输入抖动是连续的时钟边缘与标准或理想的时钟到达时间的差值。输入抖动是一个绝对值,表示时钟边缘两侧的变化。
使用set_input_jitter命令分别为每个主时钟指定输入抖动。不能直接指定生成时钟的输入抖动。Vivado IDE时序引擎自动计算生成的时钟从其主时钟继承的抖动。
系统抖动(System Jitter)
系统抖动是由于电源噪声、板噪声或任何额外的系统抖动造成的整体抖动。
使用set_system_jitter命令仅为整个设计设置一个值,即所有时钟。
以下命令通过输入端口clkin在主时钟上设置一个+/- 100ps的抖动:
set_input_jitter [get_clocks -of_objects [get_ports clkin]] 0.1
注意:输入抖动和系统抖动对时钟不确定性的整体计算的影响是不容忽视的,不能遵循单一的方程。时钟不确定性的计算与路径有关,取决于时钟拓扑结构、路径中涉及的时钟对、时钟树上是否存在MMCM/PLL以及其他考虑因素。Report Timing命令的文本和 GUI展示了每个时序路径的时钟不确定性的原因。
使用set_clock_uncertainty命令根据需要为不同的边界情况(corner)、延迟或特定的时钟关系定义额外的时钟不确定性。从时序的角度来看,这是一种方便的方式,可以为设计的一部分添加额外的裕量边界。
无论约束的顺序如何,时钟间(inter-clock)的不确定性总是优先于简单时钟的不确定性。在下面的例子中,虽然时钟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]
当两个时钟域之间定义了一个时钟间不确定性时,确保约束所有可能的时钟域的相互作用: