天天看点

时序约束

所有的时序约束都是要告诉编译器,我的时钟和数据要满足怎样的关系,然后交给编译器去计算最糟糕的情况下能不能满足条件,还差多少ns就会不满足条件。

主时钟

主时钟通常由两个来源:

(1)板级时钟通过输入端口进入设计;(2)GT收发器的输出管脚(如恢复时钟)。

主时钟必须与一个网表对象相连,该对象代表了所有时钟边沿的开始点,并且在时钟树中向下传递。也可以说,主时钟的源点定义了0时刻,Vivado靠此来计算时钟延迟和不确定性。

主时钟只能通过

create_clock

命令来定义,且必须放在约束的开始,这是因为其它时序约束几乎都要参考主时钟。下面给出两个主时钟的例子。第一个例子如下图所示,采用单端时钟输入:

时序约束

板级时钟通过sysclk端口进入FPGA,通过一个输入缓冲器和一个时钟缓冲器后到达寄存器。使用如下命令定义:

creat_clock -period 10 [get_ports sysclk] # priod 10ns 
creat_clock -name devclk -period 10 -wavefor {2.5 5} [get_ports sysclk]
           

虚拟时钟

这种类型的时钟对于初学者来说用的可能很少,虚拟时钟通常用于设定输入和输出的延迟约束。之所以称为“虚拟”,是因为这种时钟在物理上没有与设计中的任何网表对象相连。定义时使用

create_clock

命令,但无需指定源对象。在下列情况需要用到虚拟时钟:

  • 所有设计时钟都不是外部器件I/O的参考时钟。
  • FPGA的I/O路径与一个内部生成的时钟相关,但是该时钟不能合适地通过对板级时钟计时来生成(如两个周期的比不是整数)。
  • 希望为与I/O延迟约束相关的时钟设定不同的抖动和延迟,但是不希望修改内部时钟的特征。

比如时钟clk_virt的周期为10ns,且不与任何网表对象相连,可以这样定义

create_clock -name clk_virt –period 10

,没有指定objects参数。注意,虚拟时钟必须在使用之前便定义好。

生成时钟

生成时钟是指在设计内部由特殊单元(如MMCM、PLL)或用户逻辑驱动的时钟。生成时钟与一个上级时钟(注:官方称作master clock,为与primary clock作区分,这里称作上级时钟)相关,其属性也是直接由上级时钟派生而来。上级时钟可以是一个主时钟,也可以是另一个生成时钟。

生成时钟使用

create_generated_clock

命令定义,该命令不是设定周期或波形,而是描述时钟电路如何对上级时钟进行转换。这种转换可以是下面的关系:

  • 简单的频率分频
  • 简单的频率倍频
  • 频率倍频与分频的组合,获得一个非整数的比例,通常由MMCM或PLL完成
  • 相移或波形反相
  • 占空比改变
  • 上述所有关系的组合

Vivado计算生成时钟的延迟时,会追踪生成时钟的源管脚与上级时钟的源管脚之间的所有组合和时序路径。某些情况下可能只希望考虑组合逻辑路径,在命令行后添加-combinational选项即可。

这里先解释一下本文甚至本系列大量使用的两个词,端口(Port)和管脚(Pin)。端口通常用

get_ports

命令获取,管脚使用

get_pins

命令获取。二者的含义是不同的,但管脚的范围更广泛,比如设计中用到的一个寄存器都有3个管脚:clk、D和Q。下面给出几个定义生成时钟的例子:

1、分频

下图中,主时钟clkin通过端口进入FPGA,使用一个寄存器REGA对其2分频,得到的生成时钟clkdiv2驱动其它的寄存器管脚。

时序约束

可以采用如下两种方法对生成时钟进行约束:

# 定义主时钟
creat_clock -name clkin -period 10 [get_ports clkin]
# 约束方法1, 主时钟作为源点
creat_generated_clock -name clkdiv2 -source [get_ports clkin] -divide_by 2 [get_pins REGA/Q]
# 约束方法2, REGA的时钟管脚作为源点
creat_generated_clock -name clkdiv2 -source [get_ports REGA/C] -divide_by 2 [get_pins REGA/Q]
           

-source

设置上级时钟, 只能设定为一个端口或管脚类型,不能设定为时钟类型对象

-divide_by

设置分频系数,还可使用

-edges

选项, 其为一个列表,该列表通过主时钟的边沿来描述生成时钟的波形。列表中的值为主时钟边沿的序号(注意观察上图),由时钟上升沿开始,定义了生成时钟边沿的时间点。

create_generated_clock -name clkdiv2 -source [get_pins REGA/C] -edges {1 3 5} [get_pins REGA/Q]
           

2、改变占空比和相移

仅改变时钟的相移可通过

-edge_shift

正向或反向设定一个生成时钟波形的相移量,不能与

-devide_by、-multiply_by、-invert

同时使用。

下图中上级时钟为clkin,进入MMCM0单元,产生一个25%占空比、相移90°的时钟

时序约束

可以采用如下方法对生成时钟进行约束。使用上级时钟的1、2、3标号边沿(即0ns、5ns、10ns)定义生成时钟,为了得到预期波形,1和3标号边沿要分别移动2.5ns,得到2.5ns、5ns、12.5ns的波形。

#定义主时钟,周期10ns,50%占空比
create_clock -name clkin -period 10 [get_ports clkin]
#定义生成时钟,周期10ns,25%占空比,90°相移
create_generated_clock -name clkshifit -source [get_pins mmcm0/CLKIN] -edges {1 2 3} -edge_shift {2.5 0 2.5} [get_pins mmcm0/CLKOUT] 
           

3、同时倍频和分频

这种情况通常用于定义MMCM或PLL的输出,一般使用这些IP核时会自动创建相应约束。考虑上例中的图,假设MMCM将上级时钟倍频到4/3倍,无法直接倍频,需要同时使用

-divIde_by

-multiply_by

选项来实现:

creat_generated_clock -name clk43 -source [get_pins mmcm0/CLKIN] -multiply_by 4 -divide_by 3 [get_pins mmcm0/CLKOUT]
           

时钟抖动 Jitter

两个时钟周期之间存在的差值

时序约束

时钟偏移 Skew

同一个时钟信号到达两个不同寄存器之间的时间的差值

时序约束

命令

creat_clock            # 主时钟
creat_generated_clock  # 生成时钟
-name                  # 时钟名称
-period 10             # 周期, ns
-divide_by 2           # 分频系数
-multiply_by 2         # 倍频系数
-edges {1 3 5}         # 描述时钟边沿
-edge_shift            # 边沿平移