写这个博客,纯粹记录下自己这几天看完有关静态时序约束方面书籍的理解。
1.相关基础概念。
1)steup_time
2)steup_relationship
3)setup_slack
4)hold_time
5)hold_relationship
6)hold_slack
2.创建时钟周期约束(create clock)。
3.创建供源时钟约束(create generate clock)。
4.创建外部时钟约束(set clock latency)。
5.设置不确定时钟约束(set clock uncertainty)。
6.设置输入延时约束(set input delay)。
1).单信号位宽
2).多信号位宽
7.设置输出延时约束(set output delay)。
1).单信号位宽
2).多信号位宽
8.驱动PLL时钟约束(derive pll clocks)。
9.设置相关节点约束(set False path or Set Multicycle Path )。
10.设置最大最小延迟路径(set Maximum/minumum delay)。
一:关于建立时间与建立关系
在锁存沿到来之前,数据的时间,理想情况下为1个时钟周期。
如下模型:
二:建立余量
公式:setup_slack=data_require_time-data_arrive_time
data_require_time =锁存沿+tclk2-Tsu
data_arrive_time=启动沿+tco+tclk1+tdata
启动沿:一般为发送数据端的上升沿
锁存沿:一般为接收数据端的上升沿
TCLK1 : 发送端的时钟延迟
TCLK2 : 接收端的时钟延迟
Tco :寄存器数据更新延迟(属于内部延迟)
Tsu : 接收端的寄存器建立时间(查表)
Tdata : 数据传输延时,包括组合逻辑,布局布线的延迟。
结论:如果建立余量为正值,则我们可以说建立时序约束合格。
三:保持时间与保持关系
保持时间是指锁存沿锁存数据之后多长时间,数据必须保持稳定的时间,而保持关系是指锁存沿与下一个启动沿之间的时间关系。
四:保持余量
对于保持余量有两种方法可以求得
1).头脑方法:
公式:hold_slack=data_hold_time-data_require_time
data_hold_time=启动沿+tclk1+tco+tdata+时钟周期
data_require_time=锁存沿+tclk2+Th
Th:接收端寄存器保持时间(查表)
2).尾部办法
公式:hold_slack=data_hold_time-data_require_time
data_hold_time=启动沿+tclk1+tco+tdata
data_require_time=理想保持关系值+tclk2+Th
理想保持关系值=锁存沿与下一个启动沿之间的差值
结论:如果保持余量为正值,则我们可以说保持时序约束合格。
//////////////////////////////////////////////////////////
五:创建时钟周期约束
假设我们系统时钟为50M,那么我们新建一个.sdc文件,点击Edit,如下:
设置周期20ns,占空比50%,选中端口如下:
设置结果:
结束。
这个约束针对于时钟周期约束。
六:创建供源时钟约束(三种情况)
1)直接供源模型
假设我们系统时钟为100M,它通过FPGA的管脚输出给外部ext1_clk,ext2_clk.
具体代码如下:
assign ext1_clk=FPGA_CLK;
assign ext2_clk=FPGA_CLK;
这个时候就需要使用供源时钟约束了。
结束
2)寄存器模型供源时钟
如图所示,fpga_clk通过一个2分频逻辑,产生两个时钟,具体代码如下
由以上代码可知,我们通过一个寄存器ext_div2产生一个2分频时钟,然后再通过FPGA的引脚将这个2分频时钟输送出去,这样的模型就是寄存器供源时钟模型。
这个时候的约束命令如下:
首先点击Edit
然后选择如下
参数设置如下
先设定源时钟为fpga_clk,供源时钟为ext_div2,如下:
然后接着如下设置:
注意:这里不能直接将源时钟选为FPGA_CLK,然后供源时钟设为ext1_clk,ext2_clk,否则会出警告,因为这里是寄存器模型,所以必须先设定成寄存器才行。
3)PLL型供源时钟
这种模型也是我们用的最对多的一种,举例如下:
由上图可知fpga_clk经过FPGA内部的一个PLL然后生成两个100M的时钟ext1_clk/ext2_clk。
具体参考代码如下:
由上图可知,PLL的输出口ext_clk在最后驱动ext1_clk,ext2_clk.
记住有锁相环PLL的时钟约束时,首先我们在SDC文件中需要加上derive_pll_clocks这句话。
具体约束参数如下:
至此,三种供源时钟模型我们都约束完了,搞定。
七:设置潜伏时钟输出延时
这个约束的主要作用是什么呢?我们的时序大体分为理想模型和物理模型,所谓的理想模型就是指没有延迟,没有抖动等因素,而物理模型一般就没有那么完美了,它包含延迟,抖动,偏移,潜伏等影响因素,我们知道时钟源产生外部时钟时,源寄存器与目的寄存器之间会有一个时钟差,即clock_skew(时钟偏移),我们知道时钟除了路径的延时,它还有本身的延迟,但是这个延时是不确定的,它有大有小,假设运气不好,接在一个非常差的时钟源上,那么FPGA_CLK的本身时钟延迟可能比较大,如果稳定的时钟源,可能延迟就比较小了,我们称延时大的为late/max,延时小的称为early/min,这都是针对同一个时钟信号,不像数据信号那样,delay max针对多位宽数据延迟最大的那个(建立关系),而delay min针对延迟最小的那个(保持关系)。
时钟源一般分为有抖动,无延迟(both),或者有延迟,无抖动。
主要是抖动产生不一样的时钟本身延迟。
1).有延迟,无抖动的情况:这个延迟指时钟路径延迟,没有抖动就是时钟源本身没有延时,那么OK,假设这样一个例子:
IC1输入数据给FPGA,FPGA输出数据给IC2,其中IC1的时钟有1ns延迟,FPGA 的时钟有2ns延迟,IC2的时钟有3ns延迟,另外数据D[3:0]其中数据的最大延迟为4ns,而最小延迟为2ns,其中Tco和Tsu及Th的参数我们都能知道。
这个时候我们可以算出最大输入延迟和最小输入延迟。
不带时钟偏移的公式
output max =delay max+Tsu=4.5ns
output min =delay min -Th =1.5ns
input max = delay max+Tco=4.5ns
input min=delay min +Tco=2.5ns
不过上述这些都不是我们讲解的,我们要讲解的是set clock latency:
首先因为上述的公式不带时钟偏移量,所以我们要单独告诉TimeQuest外部时钟延迟参数,这个时候就涉及到了set clock latency的使用,具体如下:
因为我们有三个外部时钟即ex1_clk,fpga_clk,ext2_clk,所以需要设置三次,另外我们这里是有延迟,无抖动,所以没有late,也没有early,我们需要选择both。
这里为止,第一种无抖动的外部模型我们已经结束。
2)有抖动的情况
我们知道如果时钟源不好的话,时钟本身会产生抖动,这种抖动的影响就会造成同一个时钟间本身的延迟不同,如果时钟源好的话,可能延迟就相对较小,这个时候我们就称为early/min,相反,如果时钟源不好,抖动相对厉害的话,这个延迟本身可能就比较大了,这个时候我们称它为Late/max。
假设一个时钟的early=1ns,而late=2ns,那么加上本身的时钟传输路径延迟,具体模型如下:
则 ext1_clk delay min=1(min/early)+1=2ns
ext1_clk delay max=2(max/late)+1=3ns
则fpga_clk delay min=2+1=3ns
fpga_clk delay max=2+2=4ns
则ext2_clk delay min=3+1=4ns
ext2_clk delay max=3+2=5ns
同样的我们计算出不加clock skew的输入输出最大最小延迟
output max =delay max+Tsu=4.5ns
output min =delay min -Th =1.5ns
input max = delay max+Tco=4.5ns
input min=delay min +Tco=2.5ns
正是因为上述公式没有加入时钟偏移的计算量,所以我们同样需要在TimeQuest中单独告诉外部延迟参数,具体设置如下:
因为这次我们是带抖动的时钟,所以会有最大最小的产生,设置参数如下:
最小值early设置
最大值late设置,这里是同一个时钟即如下ext1_clk
剩下的FPGA_CLK与ext2_clk设置办法相同,最终约束命令出现在SDC中如下:
具体的约束设置完了,但是还存在一个重要的问题,就是时序的问题,我们知道如果有时钟抖动,那么一个寄存器,就有可能产生2个时钟early或者late,那么我们在做TimeQuest分析时,至少是2个寄存器,那么就是4个时钟,那么就可能产生4种时序,
1. early early
2. early late
3. late early
4. late late
具体分析模型如下:
这是一种外部模型,由FPGA向IC发送数据,fpga_clk与ext1_clk都有min=1ns,late=2ns的抖动延迟,假设D[0]有2ns延迟,则模型如图:
左边为early early
右边为early late
我们可以看出左边建立时间为8,保持时间为2,
我们可以看出右边建立时间为9,保持时间位1,
再来看这种情况的模型:
左边为 late early
右边为 late late
我们可以看出左边建立时间为7,保持时间为3,
我们可以看出右边建立时间为8,保持时间位2,
综上所述,产生4种时序,而且都是正确的,那么我们分析到底该怎么选呢?我们可以这样想,上面4种
early late 建立时间最长,保持时间最短
late early 保持时间最长,建立时间最短
OK,搞定,就这样选,最安全,其他两种无视即可。
我们称这两种模型为SEDL(Source early destination late)针对保持关系,SLDE(Source late destination early)针对建立关系。
SEDL(Source early destination late)针对保持关系。
SLDE(Source late destination early)针建立持关系。
那么我们计算下SEDL的时钟偏移clock skew
SEDL SKEW=2-1=1ns
那么在计算SLDE的时钟偏移
SLDE SKEW=1-2=-1ns
所以对于output max/input max
可以改成如下公式
output max=delay max-SLDE SKEW+Tsu
input max=Tco+delay max-SLDE SKEW
////////////////////////////////////////////////////////
output min=delay max-Th-SEDL SKEW
input min=delay min+Tco-SEDL SKEW
这样 就可以不用set clock latency来告诉TimeQuest外部延迟信息了,因为他包含在公式里了。
记住计算时,要加上路径延迟,如图:
计算input min/max
如图:
再来output min/max
至于选择set clock latency还是公式包含法,高兴就好。
八:set clock uncertainty
不想吐槽,断网没保存。。。。辛辛苦苦写的,又要再写一遍,崩溃。。。。
好了,我们知道时钟有抖动,有偏移,有潜伏,这些都属于不确定因素,这个set clock uncertainty就是针对SDEL SKEW 和 SEDL SKEW约束的。
由以下公式可知:
现在我们去掉时钟偏移,变身如下:
将SDEL SKEW ,SEDL SKEW单独算出告诉TimeQuest即可:
然后将这些信息通过set clock uncertainty告诉 TimeQuest,具体步骤如下:
搞定。
九:set input delay
这应该是时序约束中最重要的内容之一啦,首先它分为单字节位宽和多字节位宽,对于单字节位宽来说,它不存在最大最小输入延迟,所以约束时选择both即可。如下:
这个delay value值根据公式算出即可
我们主要讲解多位宽的情况
首先多位宽,如果延迟压力不均匀,则会造成不同的数据延迟不同,如图:
如图D[0]的延迟为1ns,D[1]的延迟为2ns,D[2]的延迟为3ns,所以这就长生了最大延迟和最小延时,公式如下:
其中delay max为所有数据位宽中延迟最大的,如D[2]=3ns,clock skew为外部IC的源时钟ext1_clk和fpga_clk的目的时钟之间的偏移差,clock skew=fpga_clk-ext1_clk,另外Tco为外部IC的寄存器数据更新时间,这个查datasheet可以知道。
十:set output delay
这个输出延时与输入延时道理都差不多,只是计算公式偶有不同:
十一:set Multicycle path
我们知道寄存器与寄存器之间进行数据传输时,中间可能或经过一部分组合逻辑延时,这个组合逻辑延时和资源,代码优化程度,甚至是网表质量好坏都有关系,一般网表质量好的组合逻辑延时就相对较少,反之亦然。
假设我们时钟时50M,那么周期就是20ns,如果数据传输延时小于这个周期,倒没什么关系,如果大于,比如一个乘法器,延时可能是30ns左右,很明显这样保持余量就不满足,又或者我把50M的频率升高到100M,那么我的周期只有10ns左右,而我经过10ns锁存沿到达之后,而数据还在组合逻辑哪里,所以这样就不满足保持时间关系了,那么这个时候就需要用到set Multicycle path,让它告诉TimeQuest需要改动启动沿与锁存沿之间的周期数,即告诉TimeQuest我可能不是一个时钟周期就处理一个数据,可能是多个,这样就可以延长处理数据的时间,就不怕锁存沿来了数据还没到。
就比如10ns的时钟周期,不足以给30ns左右的组合逻辑延迟,那么我们就将周期加大到40ns,这个周期加大不是改变频率,频率还是100M,而是通过set Multicycle path来约束,如图:
这就是告诉TimeQuest有关寄存器之间时4个时钟周期工作,另外要记住当我们把steup relationship增加到4个时钟周期的时候,然后 hold relationship也会移动3个时钟周期,即steup relationship=40ns,hold relationship=30ns,不要问我为啥,工具规定,如图:
然而这就不好玩了,一旦理想保持关系值一增加,hold slack就很难满足要求了,因为根据公式:
一旦增加保持余量就减少啦。。。。
所以我们必须减少hold relationship的值,所以把hold value设置为3 表示向左移三个时钟周期,保证hold relationship=0,如图:
OK,约束告一段落。
十二:set false path
这玩意跟具体代码有关,一般慎用。
关于多时钟组约束,没有例子。。。就自己学习吧。