本文转载自:孤独的单刀的CSDN博客
写在前面
之前文章讨论的时序约束可以说都是对时钟的理想特征进行约束,为了更精确地进行时序分析,设计者还必须设定一些与运行环境相关的可预测变量和随机变量,这部分也称作时钟的不确定性特征,包括时钟抖动Clock Jitter、时钟不确定性Clock Uncertainty和时钟延迟Clock Latency。
1、时钟抖动Clock Jitter
理想的时钟信号是完美的方波,但是实际的方波却是存在一些时钟抖动的。那么什么是时钟抖动呢? 相对于理想时钟沿,实际时钟存在不随时间积累的、时而超前、时而滞后的偏移称为时钟抖动(时钟脉冲宽度发生暂时变化,也就是时钟周期或大或小)。有抖动的时钟信号如下图:
对于ASIC器件来说,时钟抖动通常代表了时钟的不确定性特征;但对于Xilinx FPGA而言,抖动属性被当作可预测变量看待;抖动有的需要单独设置,有的在时序分析过程中会自动计算,抖动分为两种:
输入抖动(set_iput_jitter):指实际时钟边沿与理想时钟边沿到达时刻之间的差值,可以使用set_iput_jitter命令为每个主时钟单独设置输入抖动
系统抖动(set_system_jitter):指电源噪声、板级噪声或其它原因引起的整体的抖动,对于整个设计,使用set_system_jitter命令设置一个值即可,会应用到所有时钟
对于时钟抖动,一般情况下都建议直接使用vivado工具默认产生的抖动值,而不是自行设置。若设计者有实际应用的需求,则可以使用set_iput_jitter和set_system_jitter语法来分别设置输入抖动和系统抖动。输入抖动和系统抖动都将作为时钟不确定性(Clock Uncertainty)的一部分存在。
set_iput_jitter的基本语法结构如下:
set_iput_jitter [get_clocks <clock_name>] <jitter_in_ns>
get_clocks 用于指定事先定义好的需要约束的主时钟名<clock_name>
<jitter_in_ns>用于指定需要约束的抖动值,单位ns
set_system_jitter的基本语法结构如下:
set_system_jitter <jitter_in_ns>
<jitter_in_ns>用于指定需要约束的抖动值,单位ns
时钟的系统抖动值和输入抖动值通常都是符合高斯分布的一些随机值,因此以其均方值作为最坏的情况进行计算,即最坏情况的系统抖动值Tsj计算公式如下:
Tsj = sqrt (SourceClockSystemJitter ^ 2 + DestinationClockSystemJitter ^ 2)
^ 2表示开平方,sqrt 表示开根号
默认情况下,vivado设置的系统抖动值一般为0.050ns,所以 Tsj = sqrt (0.05 ^ 2 + 0.05 ^ 2 ) = 0.071ns。
2、时钟不确定性Clock Uncertainty
除了时钟抖动外其他能影响时钟周期性偏差的因素,都可以使用时钟不确定性约束set_clock_uncertainty命令来进行约束。使用set_clock_uncertainty命令可以根据需要为特定的时钟关系定义附加的时钟不确定性,这样在时序分析时,可以为设计中的某些部分增加额外裕量。
set_clock_uncertainty的基本语法结构如下:
set_clock_uncertainty -setup -from[get_clocks <clock0_name>] -to [get_clocks<clock1_name>] <uncertainty_value>
-setup表示定义建立时间的不确定性设置,也可以使用-hold来定义保持时间的不确定性。若不指定-setup或-hold,则表示同时定义建立时间和保持时间的不确定性
-from指定源时钟,-to指定目的时钟,对于非CDC路径,一般不需要指定其路径
get_clocks用于指定实际的时钟物理节点名称<clock0_name>和<clock1_name>
<uncertainty_value>指定时钟不确定时间,单位为ns
尽管使用set_iput_jitter 和 set_system_jitter约束的时钟抖动值最终都会算作时钟不确定性的一部分,但使用set_clock_uncertainty 约束的时钟不确定值并不会影响set_iput_jitter 和 set_system_jitte约束的抖动值,而是额外增加约束至时钟不确定性中用于时序分析。
为了区分set_clock_uncertainty 约束的抖动值和自动计算出来的抖动值,将set_clock_uncertainty 约束的抖动值称为用户不确定性(User Uncertainty)时间,它会作为最终的时钟不确定性的一部分存在。
3、时钟抖动和时钟不确定性的约束实战
首先新建一个vivado的RTL工程,再添加一个Verilog文件,内容如下:
module test ( input sys_clk , input rst , output reg [7:0] cnt ); always @(posedge sys_clk)begin if(rst) cnt <= 0; else cnt <= cnt + 1'b1; end endmodule
这个工程要实现的功能非常简单,就是一个8bit的循环计数器。
然后再往工程里添加一个时序约束文件timing.xdc,内容如下:
create_clock -period 10.000 -name sys_clk -waveform {0.000 5.000} [get_ports sys_clk]
这句约束的意思是将输入的主时钟频率约束在100MHz,如果你不懂主时钟约束,可以参考《基于Xlinx的时序分析与约束(4)----主时钟约束》
管脚的绑定因为只是看时序报表不涉及具体的开发,所以就省去了(vivado自动分配,不影响看查看时序)。
工程新建完成后,点击综合、实现(完成布局布线)。然后点击实现implementation下的report timing summary,打开timing界面:
随机选取,双击路径1打开其详细界面:
可以看到,此时的时钟不确定度是0.035ns,点击这个值会出现具体的算法:
TSJ是最坏情况的系统抖动时间,它由上面的公式 Tsj = sqrt (SourceClockSystemJitter ^ 2 + DestinationClockSystemJitter ^ 2) 计算得来,在vivado默认其系统抖动为0.05ns的情况下,其值算得为0.071ns
TIJ是set_input_jitter设定的输入抖动时间,因为目前还没有添加该约束,所以其值为0
DJ是由一些硬件原语(如PPL或MMCM等)产生的离散时钟抖动
PE也是由于使用PPL或MMCM等产生的相位误差,一般是个固定的值
UU这条没有显示是由于目前没有设定set_clock_uncertainty
根据上述公式,代入数值后求得此时的时钟不确定度值为0.035ns,那么这个值最后会用在哪里?
上图是数据要求到达时间的具体算法,现在有 建立时间裕量 = 数据要求到达时间 - 数据实际到达时间。 从上图可以看到时钟不确定性是作为一个负值加到数据要求到达时间里去的,这实际上相当于减少了建立时间裕量,是一种保守的算法,其目的是为了减少时钟非理想特性所带来的影响。
接下来设置一下输入抖动和时钟不确定性。
把工程布局布线完成后,点击 edit timing constraints,打开时序约束编辑界面:
左侧是约束分类区,展示了各种各样的时序约束;右侧是对应的约束编辑区 ;下方是已有的约束的展示区域。此时只有一条之前添加的主时钟约束。
接着点击set clock uncertainty,然后点击+号,添加一条时钟不确定性的约束语句(设定0.2ns的用户设定时钟不确定性):
然后点击set input jitter, 然后点击+号,添加一条输入时钟抖动语句(设定0.1ns的sysclk的输入时钟抖动):
然后点击set system jitter, 然后点击+号,添加一条系统时钟抖动语句(设定0.15ns的系统时钟抖动):
此时vivado左侧的保存约束按钮又可以按下了,按下将这几条语句保存:
此时,再打开timing.xdc文件,就已经出现了刚刚设置的约束语句:
此时需要把工程重新布局布线implementation一下,完成后再按上面的步骤,仍然打开路径1,观察其信息:
Tsj = sqrt (SourceClockSystemJitter ^ 2 + DestinationClockSystemJitter ^ 2),系统抖动的值由默认值0.05ns改成了0.15ns,所以计算得到其值为sqrt (0.15 ^ 2 + 0.15 ^ 2) ≈ 0.212ns
时钟输入抖动设置为0.1ns
由于没有使用PLL或MMCM,所以DJ和PE的值均为0
多出来的UU是用户自己设定的时钟不确定性,其值为0.2ns
根据公式:((TSJ^2 + TIJ^2)^1/2 + DJ)/2+ PE + UU,代入各项得:((0.212^2 + 0.1^2)^1/2 + 0)/2 + 0 + 0.2 = 0.317ns
4、时钟延迟Clock Latency
经过PCB和FPGA器件内部的传输,时钟边沿到达目的地后会有一个确定的延迟,这个延迟可以分为两个部分看待:
网络延迟(network latency):也称作插入延迟,指在FPGA内部传输带来的延迟;Vivado会自动分析计算该延迟,布线过程前只是一个粗略的估计,布线后便可以得到一个精确的值;对于生成时钟,包含其本身的网络延迟和上级时钟的网络延迟两部分
源端延迟(source latency):通常指FPGA器件外,时钟进入源点前的传输延迟,这部分延迟与PCB设计相关,需要用set_clock_latency命令进行约束
source latency 指从时钟源到定义时钟的pin(create clock的位置)的延迟。network latency指从定义时钟的位置到寄存器的clock pin的延迟。如下图所示:
对于已经做过主时钟约束的时钟,vivado在时序分析时都会自动计算其时钟延迟并给出详细报告。而对于FPGA外部输入的同步时钟信号,有时为了建模需要,设计者可能需要增加一些时钟延迟约束以指定这些时钟在FPGA器件之外的一些时钟延迟特性。
时钟延迟命令set_clock_latency命令的基本语法如下:
set_clock_latency [- clock <args>] [-rise] [-fall] [-min] [-max] [-source] <latency> <objects>
- clock后指定约束时钟(由<objects指定)所相对的时钟名称<args>,若不定义时钟<args>,则时钟延迟值会自动应用到所有目标时钟<objects>所驱动的时序路径
[-rise]、 [-fall]指定时钟延迟的边沿
[-min]、 [-max]指定时钟延迟的最小值/最大值
[-source]指定时钟延迟的基本类型, [-source]即源端延迟,也可以是网络延迟[-network],默认值为[-network]
<latency>指定时钟延迟值,单位ns
<objects>指定约束时钟的名称
对于外部引脚输入的时钟信号,其由晶振经过PCB板级延迟到达FPGA引脚的路径延迟就可以作为源端延迟[-source]来定义;而网络延迟[-network]则用于定义时钟信号从设计中的某个指定节点传输到寄存器的时钟输入端口的延迟。时钟到达寄存器输入端口的总延迟包括了时钟源端延迟和网络延迟。
5、时钟延迟约束实战
以下是一条引脚到寄存器的源时钟(虚拟时钟)在没有做任何时钟延迟约束时的路径的时序报告,此时的ideal clock network latency值为默认的0.00ns:
接下来,打开timing constrains界面,编辑添加一条时钟延迟约束语句:
其界面设置如下:
这里相当于为虚拟时钟vrclk设置了2ns的时钟源延迟,再打开相同的路径,看下时序报告:
可以看到,增加了一个clock source latency,其值为设定的2ns。此时的数据到达时间增加了2ns,由原来的11.636ns变成了13.636ns,实际上是给源端的时钟增加了一个延迟值,即Tclk1增加了2ns。
6、参考
ug903,Vivado Design Suite User Guide--Using Constraints