多周期路径 Multicycle Paths
默认情况下,vivado时序引擎是按照单周期关系分析数据关系的,即数据在发起沿发送,在捕获被捕获,发起沿和捕获沿相差一个周期;但是很多情况是,数据路径逻辑较为复杂,导致延时较大,使得数据无法在一个时钟周期内稳定下来, 或者数据可以在一个时钟周期内稳定下来,但是在数据发送几个周期之后才使用;在这些情况中,设计者的意图都是使数据的有效期从发起沿为起始直至数个周期之后的捕获沿,这样的意图无法被时序分析工具猜度出来,必须由设计者在时序约束中指明;否则时序分析工具会按照单周期路径检查的方式执行,往往会误报出时序违规;此时,我们可以将这样的path约束为multicycle path,多周期路径的约束我们会用到set_multicycle_path;set_multicycle_path 可以用来修改与源时钟或者目的时钟相关的路径所需要的时钟周期数!
如何理解多周期路径约束?
先看看单时钟周期的情形,如下图所示:红色标记为默认情况下的建立时间检查,蓝色标记为默认情况下的保持时间检查,且注意保持时间的检查是以建立时间的检查为前提,即总是在建立时间检查的前一个时钟周期确定保持时间检查:
如果是多周期,如下图所示,此时两个寄存器之间尽管使用同一个时钟但因为使能信号的作用,使得两者数据率变为时钟频率的一半,意味着发起沿和捕获沿相隔2个时钟周期:
此时新的建立时间检查如下图中的红色实线所示,红色虚线为默认情况下的建立时间检查:
在此基础上,保持时间的检查变为下图中的蓝色实线(建立时间检查前移一个时钟周期):
但显然,此时的保持时间检查是不对的,可想象一下,如果是一个时钟频率为原始时钟频率的一半的时钟,保持时间检查应该如下图中的蓝色实线所示:
多周期路径的约束我们会用到set_multicycle_path,常用的约束语法格式:
set_multicycle_path <path_multiplier> [-setup|-hold] [-start|-end]
[-from <startpoints>] [-to <endpoints>] [-through <pins|cells|nets>]
对于大多数情况,可以采用如下公式计算路径的周期数:
Hold cycles = <setup path multiplier> - 1 - <hold path multiplier>
这里我们结合上述分析重点介绍一下相应参数的含义:
- <path_multiplier>:周期数,对于建立时间检查默认为1,保持时间检查默认为0;
*语句中数字的含义:
- 对于-setup:表示该多周期路径建立时间所需要的时钟周期个数;
- 对于-hold:表示相对于缺省捕获沿(图中的Default hold),实际捕获沿(图中的New hold)应回调的时钟周期个数;
*参考时钟周期的选取:
- -end表示参考时钟为捕获端(收端)所用时钟,对于-setup缺省为-end;
- -start表示参考时钟为发送端(发端)所用时钟,对于-hold缺省为-start;
Multicycles in Single Clock Domain 单时钟域的多周期路径
如上图所示,两个寄存器之间的数据路径为N个周期,默认情况下的建立和保持时间检查如下所示:
例1.Relaxing Setup While Maintaining Hold 放宽建立检查维持保持检查
上图中两个寄存器之间的数据路径周期数为2,因此下面的语句设定了一个新的建立检查关系:
set_multicycle_path 2 -setup -from [get_pins data0_reg/C] -to [get_pins data1_reg/D]
新的建立检查关系如下所示:
即默认的保持时间检查总是建立时间检查往前推一个周期
但是很显然,此时的保持时间检查是不对的,它应该在最开始的位置,即上图中的发起沿的位置,所以要用到第二条多周期路径约束:
set_multicycle_path 1 -hold -end -from [get_pins data0_reg/C] \
-to [get_pins data1_reg/D] #保持检查往前移动1个周期
# end表示参考时钟为捕获端时钟,这里对默认进行了修改,因为保持检查的默认时钟为发起端时钟;
# 当然,这里由于是单一的时钟域,两个时钟是等同的,所以 end为选择项
对于建立路径周期数为4,多周期路径约束为:
set_multicycle_path 4 -setup -from [get_pins data0_reg/C] -to [get_pins data1_reg/D]
set_multicycle_path 3 -hold -from [get_pins data0_reg/C] -to [get_pins data1_reg/D]
一般情况下, 对于建立路径周期数为N,保持时间建立周期数为N-1,多周期路径约束为:
set_multicycle_path N -setup -from [get_pins data0_reg/C] -to [get_pins data1_reg/D]
set_multicycle_path N-1 -hold -from [get_pins data0_reg/C] -to [get_pins data1_reg/D]
Multicycle Paths and Clock Phase-Shift 时钟相位偏移中的多周期路径
一些情况下,必须对两个具有相同周期但是带相位偏移时钟进行时序约束;这种情况下,最重要的理解时序引擎在默认的情况下设定的建立保持关系,如果不做适当的调整就会导致在两个时钟域之间产生过度约束,情形如下图所示:
默认情况下不带多周期路径约束的建立保持关系:
上图中捕获时钟相对于发起时钟发生了0.3ns的相移,这导致按照单周期时序检查的情况时序根本无法收敛;这时,必须调整建立检查时间和保持检查时间,可用如下的约束:
set_multicycle_path 2 -setup -from [get_clocks CLK1] -to [get_clocks CLK2]
# 数字量为1时为默认的单周期约束,即相对于发起时钟沿往前1个捕获沿
这导致相对于建立需求时间的 捕获沿往后移动了一个周期,保持时间会由建立时间得到默认值,如下图所示:
对于捕获时钟反向偏移相位的情况,如下图所示:
如果偏移量较小,不需要设置多周期路径约束来权衡偏移量;但是如果偏移量较大,此时需要调整发起沿或者捕获沿来满足建立保持需求;
Multicycles Between SLOW-to-FAST Clocks 慢时钟到快时钟的多周期路径
如下图所示,clk2的频率是clk1频率的3倍:
默认的建立保持关系如下图:
可以看出,捕获沿总是在于发起时钟对齐后的下一个上升沿;需要设置的多周期路径约束为:
set_multicycle_path 3 -setup -from [get_clocks CLK1] -to [get_clocks CLK2]
set_multicycle_path 2 -hold -end -from [get_clocks CLK1] -to [get_clocks CLK2]
# 保持检查默认的参考时钟为发起时钟,这里加入了end,表明了参考时钟为捕获时间,即相对于捕获沿往前回调2个周期
Multicycles Between FAST-to-SLOW Clocks 快时钟到慢时钟的多周期路径
如下图所示,clk1的频率是clk2频率的3倍:
默认的建立保持关系如下图:
需要设置的多周期路径约束为:
set_multicycle_path 3 -setup -start -from [get_clocks CLK1] -to [get_clocks CLK2]
set_multicycle_path 2 -hold -from [get_clocks CLK1] -to [get_clocks CLK2]
# 这里的参考时钟为发送时钟,所以在建立时间检查的约束中加入start
下表是对以上几种多周期路径约束语法的总结: