在ASIC或FPGA设计中,multicycle约束是无法避免的一个问题,如若理解不清晰,容易造成错误的multicycle约束,本文简要阐述下个人理解的multicycle约束。
首先讨论下慢时钟域至快时钟域的multicycle设置,创建时钟如下:
create_clock -name CLKS -period 20 -waveform {0 10} [get_ports CLKS]
create_clock -name CLKD -period 5 -waveform {0 2.5} [get_ports CLKD]
当launch flip-flop和capture flip-flop具有不同的时钟频率,PT会检查两个同步时钟不同时钟沿所有可能的时序关系,从中选出一种最严格的场景来做时序检查。在此之前,PT会自动扩展至所有时钟周期的最小公倍数,本例中最小公倍数刚好是20(称为common base period)。Launch寄存器在时刻20ns将数据打出,capture寄存器在时刻25ns处采样数据,setup和hold时序检查如下:
图1 慢时钟域至快时钟域默认setup/hold检查
从图1中可以看出在common base period期间,capture寄存器每个时钟周期都在采样数据。然而我们的设计初衷并非如此,并不需要在每个capture时钟上升沿去采样数据,而是每4个时钟周期采样一次有效数据即可。这种假设留给数据路径4个时钟周期去传播数据,更容易满足时序收敛,我们可以这样设置(【-end】表明multicycle 4是参考end point或者capture clock):
set_multicycle_path 4 -setup -from [get_clocks CLKS] -to [get_clocks CLKD] -end
此时默认的setup和hold检查如下:
图2 setup multicycle设置后时序检查
图2所示为仅设置setup multicycle后的默认时序检查情况,hold检查是默认在setup检查的前一个有效时钟沿。然而在大多数情况下,这并不是我们想要的检查点,因为此时hold检查过于严格,hold检查应该前移到launch的有效沿,可以通过如下方式设置(【-end】表明我们想回退end point或者capture clock移动的时钟数):
set_multicycle_path 3 -hold -from [get_clocks CLKS] -to [get_clocks CLKD] -end
设置完hold multicycle后,时序检查如下:
图3 setup/hold multicycle设置后时序检查
在此,简要介绍下multicycle设置时-start以及-end参数的差异:
-start:指定相对launch clock移动的时钟数,hold默认-start参数;
-end:指定相对capture clock移动的时钟数,setup默认-end参数;
(1) Set_multicycle_path 4 -setup -from [get_clocks CLKS] -to [get_clocks CLKD]
(2) Set_multicycle_path 4 -setup -from [get_clocks CLKS] -to [get_clocks CLKD] -end
(a) Set_multicycle_path 3 -hold -from [get_clocks CLKS] -to [get_clocks CLKD]
(b) Set_multicycle_path 3 -hold -from [get_clocks CLKS] -to [get_clocks CLKD] -start
即setup设置时,(1)与(2)等价;即hold设置时,(a)与(b)等价。
假如上例中设置hold multicycle时,没有指定-end参数会怎样呢?首先当设置setup multicycle后,时序检查如图2所示,此时默认的hold检查点在setup检查点前一个有效沿,当我们没有显示指定-end参数,则默认为-start,则hold检查如下图所示:
图4 错误的hold multicycle约束
下面讨论下快时钟域至慢时钟域的multicycle设置,创建时钟如下:
create_clock -name CLKS -period 5 -waveform {0 2.5} [get_ports CLKS]
create_clock -name CLKD -period 20 -waveform {0 10} [get_ports CLKD]
默认的setup和hold检查如下:
图5 快时钟域至慢时钟域默认setup/hold检查
存在四个可能的时序检查,如上图中setup1、setup2、setup3、setup4,不难发现四个检查中最严格的为setup1,launch时钟沿在35ns处,capture时钟沿在40ns处。同样地,有四种可能的hold检查,上图画出的为最严格的hold检查。
通常而言,设计者可能会将从快时钟到慢时钟的数据路径指定为multicycle path。假设数据路径是宽松的,允许四个时钟周期的launch clock,下面是指定这种情形的multicycle设置:
Set_multicycle_path 4 -setup -from [get_clocks CLKS] -to [get_clocks CLKD] -start
Setup和hold时序检查如下:
图6 setup multicycle设置后时序检查
图6所示为仅设置setup multicycle后的默认时序检查情况,hold检查的launch沿也相应往前推了3个launch时钟周期。然而在大多数情况下,这并不是我们想要的检查点,因为此时hold检查过于严格,hold检查应该后移到launch的有效沿,可以通过如下方式设置:
Set_multicycle_path 3 -hold -from [get_clocks CLKS] -to [get_clocks CLKD] -start
图7 setup/hold multicycle设置后时序检查
假如上例中设置setup multicycle时没有指定-start参数会怎样呢?首先当设置setup的multicycle时,由于我们没有显示指定-start,则默认为-end,则此时默认的setup和hold时序检查如下:
图8 错误的setup multicycle设置后时序检查
此时,继续设置hold的multicycle,最终的时序检查如下:
图9 错误的setup/hold multicycle设置后时序检查
不知道各位同学有没有发现什么规律?在设置multicycle时到底应该是-start参数还是-end参数呢?如果不想每次都按照原理去推演一遍过程,可以这么简单的记忆:multicycle设置总是相对参考于较快频率的时钟。比如:慢钟到快钟,则-end;快钟到慢钟,则-start。如果src和dst时钟频率一致,那其实设置-start或-end则其实不重要。
multicycle约束需要谨慎,并非简单是N拍变化一次的数据或者静态配置的数据就可以设置multicycle,而是要从设计上确认是否可以设置multicycle。设计上按照N拍采数来设计,如增加valid或en信号控制,则这种情况下可以设置;若没有valid或en信号,单纯是N拍变化一次的数据则不能设置,因为后级电路每拍都会采样,如果设置multicycle按照多拍收时序,则存在亚稳态的风险;静态配置信号,一般不能设置multicycle,除非存在全局使能控制信号,在所有静态配置信号配置完成后,使能该信号,同时确保该信号是经过同异步处理的,则上述静态配置信号可以设置multicycle或者false_path,否则不能设置;静态配置信号,设置false_path或者multicycle的前提是不会影响后级电路的功能,至多是早一拍或晚一拍采样,不应该影响功能。