作者简介
白栎旸(笔名:皮特派),厦大通信系硕士,芯片设计与算法工程师,WiFi芯片算法负责人。先后供职于多家国内知名芯片公司和创业团队,从事数字电路架构和算法设计工作,具有丰富的数字设计经验和算法经验,以及长期与模拟设计团队联合设计数模混合电路的经验,擅长射频电路相关数字校准算法设计以及SoC芯片的架构设计,主持研发的芯片累积产量已达上亿颗。作为第一发明人已获授权的国家发明专利共4项。移知课程《从算法到RTL实现》主讲人。
本文将以具体实例来讲解时序约束中set_multicycle_path的约束方法及其效果。
本例的波形如图1所示,图中有两根信号。位于上面的信号是被采样的数据,名称为I2C_SCL_IN。位于下面的信号是要采样I2C_SCL_IN的时钟,称为sdi_clk_dly。由于它是采样时钟,在路径上属于capture clock。
图1 本文基于的时序波形
这里设定I2C_SCL_IN是每400ns变一次电平,就是说,它的频率是800ns,从时间0点开始,以高电平为起点。产生I2C_SCL_IN的时钟是一个虚拟时钟,即在芯片中不存在的时钟,命名为vir_clk2。它的频率自然是I2C_SCL_IN的2倍,即400ns。
sdi_clk2_dly的周期是1600ns,50%占空比,但它的高电平并不是从时间0点开始,而是如图所示,向右移动了450ns,才开始采样。sdi_clk_dly用下降沿采样I2C_SCL_IN。
第一步,我们不设multicycle path,直接综合,看综合结果。图 2是setup timing,可以看到,要求的采样点在1250ns处,就是sdi_clk2_dly的第一个下降沿所在的位置。I2C_SCL_IN信号的发出点是在1200ns,就是1250ns左边相邻的那个I2C_SCL_IN变化沿。
图2 不设multi,建立时间
图3是不设multicycle path得到的hold timing。采样位置不变,还是1250ns,但是I2C_SCL_IN信号的分析点1200ns向右移了400ns(一个vir_clk2周期),等于1600ns,即1250ns右边相邻的I2C_SCL_IN变化沿。
注:本文举的例子是launch clock和capture clock不同频不同相的例子,比较特殊。更多时候,我们遇到的都是同频同相的,此时,hold timing的分析点将仍然是1250ns这个点。
图3 不设multi,保持时间
总结:在不设multicycle_path的情况下,setup timing分析点提前hold timing分析点一个周期(launch clock周期)。如本例中,采样点都是1250ns,但setup timing分析点在1200ns,而hold timing分析点在1600ns,两点间隔一个lauch clock周期,即400ns。
下一步实验,我们设从vir_clk2到sdi_clk2_dly的所有路径,其setup multicycle值为1,hold multicycle值为0,如图 4所示。launch clock和capture clock,你选频率快的那个作为multicycle移动的单位。如果launch clock快,就用-start,如果capture clock快,就用-end。如果是同频同相的,做了时钟树平衡的两个时钟,那就随便你用-start或-end,结果一样。setup和hold都要设,setup设得比hold大1。
set_multicycle_path 1 -setup -start -from vir_clk2 -to sdi_clk2_dly
set_multicycle_path 0 -hold -start -from vir_clk2 -to sdi_clk2_dly
图4(代码) 设置multicycle_path的sdc语法(简称设置为“1,0”)
图 5是setup分析结果,比较一下我们什么都不设的情况,是不是完全一样呢?
图 6是hold分析结果,是不是也跟不约束multicycle结果一样呢?
总结:setup multicycle设成1,hold multicycle设成0,跟不设multicycle结果一样。换句话说,不设multicycle,就相当于给setup multicycle设成1,给hold multicycle设成0。由此,我们知道了setup multicycle的默认值是1,hold multicycle的默认值是0。
图5 设置setup multicycle_path为1的setup时序分析结果
图6 设置hold multicycle_path为0的hold时序分析结果
继续我们的实验。这回把setup multicycle设成2,把hold multicycle设成1试试。约束如图 7所示。
set_multicycle_path 2 -setup -start -from vir_clk2 -to sdi_clk2_dly
set_multicycle_path 1 -hold -start -from vir_clk2 -to sdi_clk2_dly
图7
(代码)
设置multicycle_path的sdc语法(简称设置为“2,1”)
我们看看效果。采样点不变,还是1250ns,但是setup分析点变了(如图 8所示)。原来是1200ns,现在向左移动了400ns,变成了800ns。可以看到,setup的时序冗余度slack放宽了一个lauch clock周期。
这一效果并不意外,因为约束-start -setup,其正方向就是向左移动分析点,我们从默认值1设为2(2-1=1),就是说向左移动1个lauch clock周期。
图8 设置setup multicycle_path为2的setup时序分析结果
再看hold分析结果(如图 9所示):还是默认位置不变,分析点仍在1600ns处。
图9 设置setup multicycle_path为1的hold时序分析结果
有人奇怪,明明-start -hold的值从0变成了1,为啥分析结果不变呢。
因为-start -hold是相对变化,不是绝对变化。它需要根据setup的分析点位置来定hold的分析点位置,也就是说,hold是以setup分析点作为参考点的(锚点),hold是相对于参考点在移动。虽然-start -hold的值从0变成了1,但setup分析点向左移动了1个周期,hold分析的正方向是与setup相反的。setup向左移动1个周期,那hold设成1,就意味着hold分析点向右移动1个周期。
有人问:向右?从哪开始向右移?从1600ns吗?那移动完不就时2000ns了吗?为啥这里还是1600ns呢?
答案是:从1200ns处向右移1个周期,正好是1600ns。
为什么是从1200ns处移动呢?
因为setup移动时,它并不是独立地自己左移,它还会带着hold一起左移。setup从1200移动到800,hold被它带着,从1600移动到了1200。为了让hold返回原来的位置1600,我们就增加了-start -hold 这句约束,将左移到1200的hold再右移回来。
为什么非要右移到1600ns呢?在1200ns处分析hold不是挺好的吗?
好啥呀,采样点在1250ns,hold意思是在采样之后数据仍然要坚持不动的时间,那应该在采样后分析这个时间呀。1200ns是在采样前,在采样前数据就变了,那还采个啥?
总结:setup multicycle设成2,hold multicycle设成1,会让setup timing放宽1个周期(launch clock周期)的时序要求,而hold要求并没有放宽,也没有收紧,而是原地不动。
为了证明上文所说的:hold分析点如果不另加约束的话,它会跟着setup的约束而运动。我再增加一个实验。约束如下(图 10):我把对hold的约束注释掉,咱看看效果。
set_multicycle_path 2 -setup -start -from vir_clk2 -to sdi_clk2_dly
#set_multicycle_path 0 -hold -start -from vir_clk2 -to sdi_clk2_dly
图10
(代码)
不要hold约束,只进行setup的约束(简称设置为“2,x”)
setup的效果就不用再贴图了哈,跟上面的一样,因为约束一样嘛,我们重点看hold的分析。
图 11是hold的分析,它的分析点在1200ns,证明了我上面的说法:hold以setup为锚点,setup动,hold不用约束,自动就跟着动。除非我们加约束把hold再移回去。
图11 跟着setup一起跑的hold分析点
最后,我们做个有趣的实验。我们说,setup的默认值是1,一般设置,就是从1开始,要放宽对setup的要求,就逐渐提高数值,比如设成2、3、4等等。这些设置的结果在看完上文后,大家应该都能分析。但如果我们把setup设成0呢,比默认值1还小,那结果会是怎样的呢?
我们的时序约束如图 12所示,hold的设置仍然注掉,我们看看它的行为。
set_multicycle_path 0 -setup -start -from vir_clk2 -to sdi_clk2_dly
#set_multicycle_path 0 -hold -start -from vir_clk2 -to sdi_clk2_dly
图12
(代码)
将setup设成0(简称设置为“0,x”)
在秀时序之前,我们先猜猜结果会怎样。设1是默认位置,即采样点左边1个周期。设2是向左移1个周期,即采样点左边2个周期。那么这回我设成0,应该是反方向,向右移,即采样点右边1个周期。分析点应该在1600ns处。
再看结果(图 13),采样点不在1250ns了,而是换到了-350ns,分析点换成了0ns。跟上面我们分析的一致吗?
图13 设置setup multicycle_path为0的setup时序分析结果
大家看本文第一张时序图,-350ns,其实就是1250ns时钟下降沿左边的相邻下降沿。我们分析的是1250ns右边第一个vir_clk2的沿,即1600ns处。而如果采样点变为-350ns,那么它右边第一个vir_clk2的沿,即0ns处。所以我们分析没错。
分析是没错啦,但为啥平时没人设成0呢?大家想想,setup timing是数据先发生,再有一个时钟来采它。如果时钟采的时候数据还没发生,那采的就不是这个数据了。我们看到,采样位置是-350ns,但数据实际上是0ns到达的,那能采到这个数据吗?根本不能,所以没人尝试过设成0。我们这里的实验也仅仅是给大家说明语法而已。
对应的hold也贴出来(图 14),我们hold没约束,所以跟着setup向右移动,应该是移到了400ns。看看结果吧。
果然如此,hold分析点在400ns处。
图14 跟着setup一起跑的hold分析点
一般,hold就要设得比setup小1。这样才能让hold分析点回到原位。那本例中,setup已经设为0了,难道hold还能设为-1不成?当然能,约束如图 15所示。
set_multicycle_path 0 -setup -start -from vir_clk2 -to sdi_clk2_dly
set_multicycle_path -1 -hold -start -from vir_clk2 -to sdi_clk2_dly
图15
(代码)
将setup设成0,hold设成-1(简称设置为“0,-1”)
setup没变,我们只看hold。结果如图 16所示,果不出所料,hold分析点从原来的400ns,左移到了0ns。约束setup右移,用同样方法约束hold就是左移。
图16 设置setup multicycle_path为-1的hold时序分析结果
完结,希望能够排除你心中的疑惑。