【数字IC/FPFA】时序约束--时钟约束

时钟周期约束,顾名思义,就是我们对时钟的周期进行约束,这个约束是我们用的最多的约束了,也是最重要的约束。
下面我们以vivado中的时钟约束为例,介绍时钟约束的相关内容。

Create_clock

在Vivado中我们通过使用create_clock来创建时钟周期约束。使用方法如下:

create_clock -name <name> -period <period> -waveform {<rise_time> <fall_time>} [get_ports <input_port>]

其中,参数name为创建的时钟的名称,period为时钟周期,waveform是时钟波形参数,第一个数为上升沿时间,第二个为下降沿发生的时间。
通过create_clock创建的时钟必须是主时钟primary clock,主时钟通常有两种情形:一种是时钟由外部时钟源提供,通过时钟引脚进入FPGA,该时钟引脚绑定的时钟为主时钟;另一种是高速收发器(GT)的时钟RXOUTCLK或TXOUTCLK
例1:
【数字IC/FPFA】时序约束--时钟约束_第1张图片
在上图中,板级时钟通过sysclk端口进入FPGA,通过一个输入缓冲器和一个时钟缓冲器后到达寄存器,我们可以使用如下命令进行主时钟的定义:

create_clock -period 10 [get_ports sysclk]  

例2:
【数字IC/FPFA】时序约束--时钟约束_第2张图片
在本例中,时钟源由高速收发器gt0提供,并通过rxclk端口进入FPGA,之后经过混合时钟管理单元MMCM生成其他时钟,以gt0发出的时钟为主时钟,其他生成时钟都有一个共同的时钟源,使用如下命令进行约束:

create_clock -name rxclk -period 3.33 [get_pins gt0/RXOUTCLK]

例3:
【数字IC/FPFA】时序约束--时钟约束_第3张图片
在例三中,我们采用差分时钟输入,这也是高速时钟的输入方式。上图中差分时钟驱动一个PLL,定义主时钟时必须只创建差分缓冲器的正极输入,如果同时创建了正极、负极输入,将会导致错误的CDC路径。我们使用如下命令进行约束:

create_clock -name sysclk -period 3.33 [get_ports SYS_CLK_clk_p]

create_generated_clock

创建衍生时钟,用法如下

create_generated_clock -name <generated_clock_name> 
                       -source <master_clock_source_pin_or_port> 
                       -multiply_by <mult_factor> 
                       -divide_by <div_factor> 
                       -master_clock <master_clk> 
                       <pin_or_port>

从时序约束的名字就能看出来,这个是约束我们在FPGA内部产生的衍生时钟, 所以参数中有个-source,就是指定这个时钟是从哪里来的,这个时钟叫做master clock,是指上级时钟,区别于primary clock。它可以是我们上面讲的primary clock,也可以是其他的衍生时钟。该命令并不是设定时钟的周期或波形的,而是描述时钟电路如何对上级时钟进行转换。这种转换可以是下面的几种:
1.简单的频率分频
2.简单的频率倍频
3.频率倍频与分频的组合,获得一个非整数的比例,通常由MMCM或PLL完成
4.相移或波形反相
5.占空比改变
6.上述所有关系的组合
衍生时钟又分两种情况:
1.Vivado自动推导的衍生时钟,往往由特殊单元(如MMCM、PLL)生成。
2.用户自定义的衍生时钟。
例1:
【数字IC/FPFA】时序约束--时钟约束_第4张图片
这是一个简单的二分频电路,我们可以采用如下两种方法对生成时钟进行约束:

#定义主时钟,周期10ns,50%占空比
create_clock -name clkin -period 10 [get_ports clkin]
#约束方法1,主时钟作为源点
create_generated_clock -name clkdiv2 -source [get_ports clkin] -divide_by 2 [get_pins REGA/Q] 
#约束方法2,REGA的时钟管脚作为源点
create_generated_clock -name clkdiv2 -source [get_pins REGA/C] -divide_by 2 [get_pins REGA/Q]

此外,我们还可以使用-edges选项进行约束,如下所示:

#该约束与上面等效
create_generated_clock -name clkdiv2 -source [get_pins REGA/C] -eedges {1 3 5} [get_pins REGA/Q]
 #1 3 5 分别为生成时钟一个周期的三个沿对应master clock的沿的位置
 #即生成时钟的第一个上升沿对应master clock的第一个沿,生成时钟的第二个沿对应master clock的第3个沿,生成时钟的第三个沿(下一个周期的上升沿)对应master clock的第5个沿

例2:
【数字IC/FPFA】时序约束--时钟约束_第5张图片
例1是通过分频、倍频得到衍生时钟的一个例子,本例则是通过改变占空比与相移得到一个衍生时钟。我们使用-edge_shift选项可以正向或反向设定每一个生成时钟波形的相移量。需要注意的是,-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 clkshift -source [get_pins mmcm0/CLKIN] -edges {1 2 3} 
-edge_shift {2.5 0 2.5} [get_pins mmcm0/CLKOUT]
#即生成时钟的第一个上升沿,和正向移动2.5ns后的跳变沿1对齐,生成时钟的第二个沿,和源时钟的第二个沿对齐,而生成时钟的第三个沿,和相移2.5ns后的跳变沿3对齐。

例3:
同时倍频与分频,这种情况通常用于定义MMCM或PLL的输出,一般使用这些IP核时会自动创建相应约束。假设MMCM将上级时钟倍频到4/3倍,这时需要我们同时使用-divede_by和-multiply_by选项来实现:

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

例4:自动生成时钟 Automatically Derived Clocks
这种类型时钟算是生成时钟的一种特例,“自动”是指在已经定义了上级时钟的情况下,Vivado会自动为时钟管理单元CMBs(Clock Modifying Blocks)的输出管脚创建约束,官方称作Automatically Derived Clocks或Auto-generated Clock
如果约束中已经存在用户在某一网表对象上定义的时钟,则不会创建相同对象上的自动生成时钟。
下面给出一个具体例子,下图中上级时钟clkin驱动clkip/mmcm0单元的CLKIN输入,该单元是一个MMCME2资源的实例,则自动生成时钟的定义源点为clkip/mmcm0/CLKOUT,顶层与此源点连接的网络名为clkip/cpuClk,自动生成时钟的名字便是cpuClk。
【数字IC/FPFA】时序约束--时钟约束_第6张图片

set_clock_groups

默认情况下,Vivado会检测设计中所有时钟之间的路径时序,添加如下两种约束可以控制该功能:
set_clock_groups:建立时钟组,Vivado不会对不同时钟组的时钟之间进行时序分析
set_false_path:将两个时钟之间的路径设置为false path后,不会对该路径进行任何时序分析;
根据时钟间的关系,可以做如下分类:
1.同步时钟:即两个时钟间有可预知的相对相位,通常它们的时钟树源自网表中的同一个根,且有一个公共周期
2.异步时钟:两个时钟间有无法预知的相对相位。比如两个独立的晶振信号通过两个输入端口进入FPGA中,生成两个时钟。由于两个主时钟没有明确的相位关系,两个生成时钟间便是异步的;
3.不可扩展时钟:Xilinx官方称作Unexpandable Clocks,是指时序引擎在1000个周期内无法判断两个时钟是否有公共周期。这种情况通常发生在两个时钟周期比是一个特殊的分数,比如一个主时钟通过MMCM生成一个周期为5.125ns的时钟clk1和一个周期为6.666ns的时钟clk2,尽管它们在时钟树的根上有一个确定的相位关系,但是在1000个周期内时钟上升沿无法再次对齐。
例1:异步时钟组
同步时钟可以安全地进行时序分析,异步时钟和不可扩展时钟虽然通过时序分析也会得到一个裕量值,但这个值不可作为可靠结果。因此从这个角度出发,不可扩展时钟也可以视作一种特殊的异步时钟,因此就需要通过设置时钟组来忽略异步时钟的时序路径上的时序分析 。
如下图所示,一个主时钟clk0通过MMCM生成两个时钟usrclk和itfclk;另一个主时钟clk1通过另一个MMCM生成两个时钟clkrx和clktx,则我们用如下命令创建异步时钟组:

set_clock_groups -name async_clk0_clk1 
                 -asynchronous 
                 -group {clk0 usrclk itfclk} 
                 -group {clk1 gtclkrx gtclktx}
#如果生成的时钟名称事先不知道,也可以用如下写法
set_clock_groups -name async_clk0_clk1 -asynchronous -group [get_clocks -include_generated_clocks clk0] -group [get_clocks -include_generated_clocks clk1]

例2:互斥时钟组 Exclusive Clock Groups
下面再介绍另一种会用到时钟组的情况:某些设计会有几个操作模式,不同操作模式使用不同的时钟,这些时钟通常由专用的时钟选择器进行选择,如BUFGMUX和BUFGCTRL。
这些单元都是组合逻辑单元,Vivado会将所有输入传递到输出。在Vivado IDE中,这几个时钟可以同时存在时钟树上,方便同时报告所有操作模式,但是在硬件中这是不可能的,它们之间是互斥的,这些时钟便称作互斥时钟
举个例子,一个MMCM实例生成的两个时钟clk0和clk1,与一BUFGMUX实例clkmux相连,clkmux的输出驱动设计时钟树。默认情况下,虽然clk0和clk1共享同一时钟树,但不能同时存在,然而Vivado还是会分析clk0和clk1之间的路径,这个问题要通过设置互斥时钟组来解决,达到禁止分析这两个时钟间路径的目的。约束方法如下:

set_clock_groups -name exclusive_clk0_clk1 
                 -physically_exclusive 
                 -group clk0 -group clk1

在ASIC工艺中通常使用-physically_exclusive和-logically_exclusive代表不同的信号完整性分析模式,但对于Xilinx FPGA而言,二者是等价的,都可以使用。

时钟延迟、抖动与不确定性

上述约束可以说都是对时钟的理想特征进行约束,为了更精确地进行时序分析,设计者还必须设定一些与运行环境相关的可预测变量和随机变量,这部分也称作时钟的不确定性特征

时钟延迟latency

经过板子和FPGA器件内部的传输,时钟边沿到达目的地后会有一个确定的延迟,这个延迟可以分为两个部分看待:
网络延迟:也称作插入延迟,指在FPGA内部传输带来的延迟;Vivado会自动分析计算该延迟,布线过程前只是一个粗略的估计,布线后便可以得到一个精确的值;对于生成时钟,包含其本身的网络延迟和上级时钟的网络延迟两部分。
源端延迟:通常指FPGA器件外,时钟进入源点前的传输延迟,这部分延迟与PCB设计相关,需要用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]

时钟抖动jitter

对于ASIC器件来说,时钟抖动通常代表了时钟不确定性特征,但对于Xilinx FPGA而言,抖动属性被当作可预测变量看待。抖动有的需要单独设置,有的在时序分析过程中自动计算,抖动分为两种:
输入抖动:指实际时钟边沿与理想时钟边沿到达时刻之间的差值,使用set_input_jitter命令为每个主时钟单独设置输入抖动,但是不能直接为生成时钟设置输入抖动,这部分由工具自动计算,如果(1)生成时钟由一个组合或时序单元创建,生成时钟的抖动与上级时钟相同;(2)生成时钟由 MMCM或PLL驱动,生成时钟的抖动为一个自动计算的值。
系统抖动:指电源噪声、板级噪声或其它原因引起的整体的抖动,对于整个设计,使用set_system_jitter命令设置一个值即可,会应用到所有时钟。
下面给出一个约束输入抖动的例子:

#主时钟传输过程中有±100ps的抖动
set_input_jitter [get_clocks -of_objects [get_clocks sysclk]] 0.1

不过,时钟抖动对整个时钟不确定性计算的影响不是太大。计算时钟不确定性时对每条路径都是独立的,且主要依赖于时钟拓扑结构、路径上的时钟对、时钟树上是否存在MMCM/PLL单元等其它因素。

附加的时钟不确定性 Additional Clock Uncertainty

使用set_clock_uncertainty命令可以根据需要为特定的时钟关系定义附加的时钟不确定性,这样在时序分析时,可以为设计中的某些部分增加额外裕量。
前面文章说过XDC约束带有顺序性,后面的约束会重写前面的约束。但在这里,时钟间的不确定性总是优先于单个时钟的不确定性,不管约束顺序如何,看下面的例子:

set_clock_uncertainty 2.0 -from [get_clocks clk1] -to [get_clocks clk2] 
set_clock_uncertainty 1.0 [get_clocks clk1]

这里首先约束从clk1到clk2有一个2ns的时钟不确定性,接着又约束clk1有1ns的时钟不确定性,但是后面这条约束不会改动从clk1到clk2之间的关系,同时,要注意clk1到clk2有时钟间的不确定性,clk2到clk1也有时钟间的不确定性,所以要约束完整。

创建虚拟时钟

虚拟时钟通常用于设定对输入和输出的延迟约束,这个约束其实是属于IO约束中的延迟约束,之所以放到这里来讲,是因为虚拟时钟的创建,用到了本文的一些理论。顾名思义,虚拟时钟,就是没有与之绑定的物理管脚。
虚拟时钟主要用于以下三个场景:
外部IO的参考时钟并不是设计中的时钟
FPGA I/O路径参考时钟来源于内部衍生时钟,但与主时钟的频率关系并不是整数倍
针对I/O指定不同的jitter和latency
  简而言之,之所以要创建虚拟时钟,对于输入来说,是因为输入到FPGA数据的捕获时钟是FPGA内部产生的,与主时钟频率不同;或者PCB上有Clock Buffer导致时钟延迟不同。对于输出来说,下游器件只接收到FPGA发送过去的数据,并没有随路时钟,用自己内部的时钟去捕获数据。
  如下图所示,在FPGA的A和B端口分别有两个输入,其中捕获A端口的时钟是主时钟,而捕获B端口的时钟是MMCM输出的衍生时钟,而且该衍生时钟与主时钟的频率不是整数倍关系。
【数字IC/FPFA】时序约束--时钟约束_第7张图片
这种情况下时序约束如下:

create_clock -name sysclk -period 10 [get_ports clkin]
create_clock -name virclk -period 6.4
set_input_delay 2 -clock sysclk [get_ports A]
set_input_delay 2 -clock virclk [get_ports B]

可以看到,创建虚拟时钟用的也是create_clock约束,但后面并没有加get_ports参数,因此被称为虚拟时钟。
再举个输出的例子,我们常用的UART和SPI,当FPGA通过串口向下游器件发送数据时,仅仅发过去了uart_tx这个数据,下游器件通过自己内部的时钟去捕获uart_tx上的数据,这就需要通过虚拟时钟来约束;而当FPGA通过SPI向下游器件发送数据时,会发送sclk/sda/csn三个信号,其中sclk就是sda的随路时钟,下游器件通过sclk去捕获sda的数据,而不是用自己内部的时钟,这是就不需要虚拟时钟,直接使用set_output_delay即可。
需要注意的是,虚拟时钟必须在约束I/O延迟之前被定义。

最大最小延迟约束

顾名思义,就是设置路径的max/min delay,主要应用场景有两个:

输入管脚的信号经过组合逻辑后直接输出到管脚

异步电路之间的最大最小延迟
【数字IC/FPFA】时序约束--时钟约束_第8张图片
设置方式为:

set_max_delay <delay> [-datapath_only] [-from <node_list>][-to <node_list>][-through <node_list>]
set_min_delay <delay> [-from <node_list>] [-to <node_list>][-through <node_list>]

max/min delay的约束平时用的相对少一些,因为在跨异步时钟域时,我们往往会设置asynchronous或者false_path对于异步时钟,我们一般都会通过设计来保证时序能够收敛,而不是通过时序约束来保证

你可能感兴趣的:(数字IC设计,数字IC设计,时序约束,时序分析)