查看原文
其他

Tcl与Design Compiler :其他的时序约束选项(2)

IC_learner IP与SoC设计 2022-04-30

前文可见:Tcl 与 Design Compiler :其他的时序约束选项(1)


前面介绍的设计都不算很复杂,都是使用时钟的默认行为作为电路的约束,都存在有路径给你约束,即信号的变化要在一个时钟周期内完成,并达到稳定值,以满足寄存器的建立和保持的要求。此外进行可测性设计(design for test)时,为了提高测试的覆盖率,我们经常使用多路(multiplex,简称mux)传输电路的控制时钟,使电路的时钟信号可以由输入端直接控制。这些电路约束属于复杂的约束,除了理论上的讲解之外,还会进行实战,实战内容主要为围绕前面的伪路径和多周期路径进行的,主要内容如下:


 ·异步设计路径和逻辑上不存在的路径的时序约束(时序例外)

 ·多时钟周期的时序约束

 ·分频电路和多路时钟传输的时钟约束

 ·实战



01        异步设计路径和逻辑上不存在的路径的时序约束(时序例外)



(1)异步设计的路径约束


前面说的都是同步时序电路,下面就用介绍一下异步时序电路的约束吧。异步时序电路的时钟来自不同的时钟,模块之间的时钟是不同频或者同频不同相的关系,一些时钟在我们的设计里没有对应的端口,如下图所示:



上图中,一共用4个时钟源,有5种不同的时钟;我们要综合电路使用的是时钟CLKC,时钟源是OSC3,前后模块的时钟各不一样,因此是异步电路。


(在传统的同步和异步设计分类上,有些由同一个晶振产生的时钟由于可能没有固定的相位关系,因此会被认为是异步设计;在那种情况下,我们也可以使用这里的异步约束进行相关的时序约束)


进行异步电路设计时,设计者要注意会产生亚稳态,导致某些寄存器的输出为不定态。为了避免产生亚稳态问题,可以考虑在设计中使用双时钟、不易到亚稳态的触发器(double-clocking,metastable-hard Flip-Flops),或使用双端口(dual-port)的FIFO等等。


对于穿越异步边界的任何路径,我们必须禁止对这些路径做时序综合。由于不同时钟源的时钟之间相位关系是不确定的,一直在变,对跨时钟域的路径作时间约束是毫无意义的。因此我们不要浪费DC的时间,试图使异步路径“满足时序要求”。我们可用set_false_path命令为跨时钟域的路径作约束(其实是解除时序路径的约束)。这也就是异步电路里面的时序约束比较重要的。


例如对于下面的异步电路:



设计之间是异步的,存在垮时钟域的路径(如上图所示),我们就要用set_false_path命令为跨时钟域的路径作约束,上图的异步电路对应的跨时钟域约束如下所示:


#Make sure register-register paths meet timing

create_clock  -period  20  [get_ports CLKA]

create_clock  -period  10  [get_ports CLKB]

#Don't optimize logic crossing clock domains

set_false_path  -from  [get_clocks  CLKA]  -to  [get_clocks  CLKB]

set_false_path  -from  [get_clocks  CLKB]  -to  [get_clocks  CLKA]


如果设计中的所有时钟都是异步的,可用下面命令为跨时钟域的路径做约束:



用set_false_path命令对路径作时序约束后,DC做综合时,将中止对这些路径做时间的优化。


(2)逻辑上不存在的路径的约束


set_false_ path命令除了可以用于约束异步电路外,还可以用于约束逻辑上不存在的路径(logically false paths)。逻辑上不存在的路径是什么呢,下面通过一个例子说明,对于下面的电路:



当选择信号是0的时候,前面的MUX打开的是A1,后面MUX打开的是B2,因此数据的通路就是A1B2(数据从A1流到B2);当选择信号是1的时候,前面的MUX打开的是B1,后面MUX打开的是A2,因此数据的通路就是B1A2。由此可以看到,选择信号无论是1还是0,前面的MUX的A1引脚和后面的MUX的A2引脚之间是没有数据流通的,也就是该逻辑通路并不存在。同样,前面的MUX的B1引脚和后面的MUX的B2引脚之间的逻辑通路也不存在。因此这两条数据通路就是逻辑上不存在的路径,比如从点A1到点A2之间有一条物理上的连接路径,但是点A1输入信号并不通过这条路径传输到A2;这种物理上存在连接关系,但是逻辑不存在的路径称为逻辑伪路径,在DC中,伪路径“false path”称为时序例外(timing exceptions)。可以用下面的拓扑图理解:



我们可以用report_timing_requirements命令报告设计中所有的例外(包括有效的例外和无效的例外)。在report_timing_requirements命令加选项"-ignored",将把无效的例外报告出来,例如:



上面的报告中,我们可以知道,从引脚{IO_PCI_CLK\pclk}到引脚{IO_SDRAM_CLK\ SDRAM_ CLK}并不存在实际的信号流通,也就是这是一条逻辑伪路径。引脚{IO_SDRAM_CLK\SDRAM_CLK}不是路径的终点(根据定义,路径的终点必须是输出端口或寄存器的数据输入引脚);引脚FF1/Q不是路径的起点(根据定义,时序路径的起点必须是输入端口或寄存器的时钟引脚)。注意:report_timing_requirements命令无”-valid”,选项。该命令的所有选项如下:



去掉任何不要的例外,可使用reset_path命令,例如: dc_shell  >  reset_path  -from  FF1/Q


02         多时钟周期的时序约束


(1)关于建立时间


如下图所示加法器电路,时钟clk的周期定义为10ns,按设计规格,加法器的延迟约为6个时钟周期:



①默认的的建立时间约束


默认的时间建立时间约束将指示DC在10ns的时候对C_reg进行建立时间是否满足的分析;很显然,默认的时序约束会使寄存器的数据输入引脚C_reg/D信号变化,不满足建立(setup)的要求,将产生亚稳态,寄存器C_reg的输出为不定态。也就是一个时钟周期的约束不能满足约束要求。


②修改后的建立时间约束


对于多时钟周期的建立时间约束,可以使用下面命令进行修改:


create_clock  -period  10  [get_ports  CLK]

set_multicycle_path6-setup  -to  [get_pins  C_reg[*]/D]

(等价于set_multicycle_path-setup  6  -to  [get_pins  C_reg[*]/D] )


注意这条命令是要知道多时钟周期的终点寄存器的(注意:这条命令设置了所有的前级寄存器时钟端口到C_reg寄存器的D端口路径都是多时钟周期路径,而set_multicycle_path6-setup  -from  A_reg/Clk  -to  [get_pins  C_reg[*]/D],则是仅仅现在从A寄存器的时钟端口到C_reg寄存D端口的这一条路径而已),通过这条命令,就告诉DC将仅仅在第6个上升沿,即60 ns作建立的分析(也就是间隔6个时钟周期后再做建立时间分析)。这时,加法器的最大允许延迟是:



对应的时序关系如下图所示:




(2)关于保持时间


①默认的保持时间约束


对于保持时间的约束,我们是不是默认就OK了呢?在前面的建立时间和保持时间的概念中,我们知道默认的保持分析时间在建立分析的前一周期,(此处应该有链接)也就是说,在这个多时钟周期的加法器中,DC将在50 ns这个时刻分析电路有无违反保持要求,要求加法器的最小延时是(注意这是默认的情况下的所做的时序要求):



默认的保持时间分析对应的时序关系如下所示:



也就是说,经过修改过后的多时钟周期建立时间约束和默认的保持时间约束就会告诉DC,要DC综合出一条路径使其建立时间满足60 ns的要求,并且同时满足保持时间50ns的要求


但是要综合出这样一条路径实际上是没有必要的,这样做只会增加电路的复杂度。为什么会这样呢?这是因为默认保持时间不满足约束,也就是说,不应该在50ns的时候进行保存时间的检测,需要修改多时钟周期保持时间的约束


②修改后的保持时间约束


那在上面什么时候做保持时间分析比较合适呢?我们知道在时间为60 ns的时刻,引起寄存器C_reg的D引脚信号变化的是时钟CLK在0时刻的触发沿。此刻(在0ns时),时钟CLK把寄存器A_reg和B_reg的D引脚信号采样到它们的输出端。再通过加法器把信号传输到寄存器C_reg的D引脚。由此可见会冲掉C_reg的D端数据只是A_reg和B_reg的D引脚的变化的时候,也就0ns时刻,因此应该对保持时间做出调整,应该在0ns的时候做保持时间的检测,也就是应该提前5个时钟周期,从50ns提前到0ns。


修该后的约束如下所示:



对应的时序关系如下所示:



保持时间的分析提前了5个周期,加法器的允许延时为:



仅仅通过约束告诉DC这是一个多时钟周期的加法器电路是不够充分的,一方面是由于后面的触发器应该经过6个时钟周期之后才能采到正确的值(但是C_reg不知道什么采到的值是正确的),另一方面是约束仅仅是告诉DC如果这块电路的延时太大或者太小的时候要报错;可以这么理解,约束单单保证了时序上这个是一个多时钟周期的加法器电路,但是这个加法器电路经过延时得到结果后,后面的C_reg采样的正确性,需要在RTL代码的设计上保证,需要加上相应的控制信号,保证DC能够综合出能够正确工作的多时钟周期的加法器。对于前面的加法器,可以需要加上相应的使能信号,因此电路设计如下所示:




(3)多时钟路径和普通路径同在一个设计中


前面的例子是单纯的多时钟周期设计,当电路里面同时存在多时钟周期路径和普通路径时,如下图所示:



该电路中,要求寄存器间的乘法运算为两个时钟周期,加法运算为默认的一个时钟周期,这时候,可以使用下面命令进行约束:


create_clock  -period  10  [get_ports  clk];#创建时钟

set_multicycle_path -setup 2 -from  FFA/CP -through Multiply/Out -to FFB/D  ;

set_multicycle_path -hold 1 -from  FFA/CP -through Multiply/Out -to FFB/D  ;


注意电路图中的from、through、to的对象


03        分频电路和多路时钟传输的时钟约束


下面的电路中包含了时钟分频电路和多路时钟传输电路:



(1)首先是多路时钟的传输问题:


对于上图中的电路,其多路时钟传输电路的模型如下所示:



其内部电路的时钟(Int_Clk)连接到多路输出电路的输出,如果我们不告诉DC要用Tst_Clk、Ext_Clk中的哪一个时钟,DC会自己选择一个,这就可能出现DC选择不同的时钟做建立和保持的分析,因此我们必须指定要用哪个时钟进行约束和分析。例如对于下面的多路时钟传输电路:



可以使用的下面命令进行约束:


create_clock  Ext_Clk  -period  10 (=create_clock  -period  10  Ext_Clk )

create_ clock  Test_Clk  -period  100

set_dont_touch_network  [get_clocks Ext_Clk]

set_dont_touch_network  [get_clocks Test_ Clk]

#Allow DesignTime to use Ext_ Clk  fortiming analysis

set_disable_timing  CLOCK_GEN/U1  -from a -to y


最后一行的命令(set_disable_timing)去掉了MUX从引脚a到引脚Y的时间弧((timing arc),这时DC认为它们没有时间关系,也就是,我们只指定使用Ext_ Clk这时钟进行分析建立时间和保持时间。set_disable_timing命令用起来很灵活,该命令有多个选项。我们可以用该命令使设计中用到的库单元的时间弧(timing arc)无效。


set_disable_timing命令使当前设计中的通过指定单元,引脚或端口的时间无效(相当于断开)。set_false_ path在这里不起作用。我们已经定义了Test_ Clk和Ext_ Clk为时钟,从引脚a和b到引脚Y是一条理想的时钟路径,不受约束,因此set_false_ path命令不起作用。


除了使用set_disable_timing 这条命令进行多路时钟传输的约束外,还有用模式分析特征(case analysis feature)进行约束,如下所示:


set_case_analysis 0 [get_pins U1/sel]


或者


set_case_analysis 0 [get_ports sel]


与命令set_disable_timing相比,命令set_case_analysis 会增加DC的运行时间,但使用模式分析命令较简单。


(2)接下来是分频电路:


Design Compiler不能推导出分频时钟的波形。时钟信号可以通过任何的组合电路,但中止于寄存器。DC并不知道寄存器的输出端为时钟信号或非时钟信号。如下图所示:



Int_Clk是Ext_Clk经过二分频后从寄存器U2的输出端口Q输出的时钟,但DC并不知道这是你的时钟信号,需要添加相应的约束,如下所示:


create_clock  -period 50 [get_ports  Ext_Clk] ;

create_generated_clock -name Int_Clk -source [get_pins CLOCK_GEN/U2/CP] -divide_by 2 [get_pins  CLOCK_GEN/U2/Q] ;

set_clock_latency  -source 1. 5 [get_clocks  Int_Clk] ;

set_clock_latency  0.5 [get_clocks  Int_Clk] ;


create_generated_clock这条命令会将时钟源(Ext_Clk)的任何变化自动反映在产生的时钟(Int_Clk)上。


做完版图后的设计已经加入了时钟树,连线的寄生参数也被反标(back-annotated)到时钟树上。这时候,DC用set_propagated_clock命令和时钟树的实际寄生参数自动地计算所有时钟引脚的延迟。我们不需用set_clock_latency命令为时钟建模。约束改成:


create_clock -period  50 [get_ports  Ext_Clk] ;

create_generated_clock  -name  Int_Clk  -source [get_pins CLOCK_GEN/U2/CP]   -divide_by 2 [get_pins  CLOCK_GEN/U2/Q] ;

set_propagated_clock [list [all_clocks] [get_generated_clock  *]]


(3)多时钟发送/接收


前面分别讲了多路时钟传输和分频的约束,也就把下面电路图中的阴影部分单独拿出来进行约束;将下来,将为下面的电路进行多时钟发送/接收问题(DES_B模块和DES_A模块之间存在数据的发送和接收)进行约束:



假设我们使用的Ext_Clk的时钟,其周期是50ns。模块B与模块A的时钟是有周期关系的,单单看模块A和模块B,就是多时钟同步设计的问题了,对于整个模块也就是(TOP_LEVEL),可以使用下面的约束:


create_clock  -period  50  -waveform  {0 25} Ext_Clk

create_clock  -period  100  -waveform  {0 50} Int Clk

set_clock_latency  -source 1. 5 [get_clocks  Int_Clk] ;

set_clock_latency  0.5 [get_clocks Int_Clk] ;


04        实战


这次的实战和以前的实战不一样,这次的实战不再是从RTL源文件开始,而是从一个被约束过的、综合过的文件,也就是经过映射后的.ddc文件,通过对编译后的设计进行合适的约束,使得设计满足设计要求。


我们先来看一下我们要进行约束的部分RTL原理图:



这个设计包含了纯组合逻辑、时序逻辑、多路选择器导致的伪路径。组合和逻辑和时序逻辑具有不同的约束,实验初始的约束不当,有设计违规;我们需要进行合适的约束,从而消除设计违规。


①启动DC,读入.ddc设计,进行读入设计后的检查


这步骤跟前面的章节类似,不再进行叙述,需要注意的是,因为需要读入.ddc设计,因此使用的命令是read_ddc


②查看综合后原始的违规情况:



可以知道有违规情况。


③进行合理地约束:


最初的约束不符合情况,因此在这里我们进行合适的约束(或者说重新进行约束)。


--->约束组合逻辑:


我们根据下面的原理图进行约束:



·对于组合逻辑,一方面,组合逻辑的具有6ns的最大延时;另一方面,由于组合逻辑没有时钟输入端口,因此需要创建虚拟时钟,因此第一步对组合逻辑的约束如下:


create_clock -name vclk -period 6

set in_ports [get_ports "coeff* adr_i*"]

set_input_delay  0 -clock vclk -add_delay $in_ports

set_output_delay 0 -clock vclk -add_delay [all_outputs]


·我们可以查看约束后的虚拟时钟的路径情况:



可以看到,设计依旧违规了,这是由于多路选择器的原因,clk和虚拟时钟vclk进行交叠了;因此我们要在逻辑路径上设置伪路径,禁止这些时钟进行时序分析:


set_clock_group -name false_grp1 -logically_exclusive -group clk -group vclk


设置完成之后,vclk不违规了。


·组合逻辑并没有约束完成,虚拟时钟vclk虽然不违规,但是clk违规了,对于组合逻辑,clk并没有起到作用,因此还需要禁止clk对组合逻辑的输入到输出进行时序分析:


set_false_path -from [get_clocks clk] -through $in_ports -through [all_outputs] -to [get_clocks clk]


注意,约束使用了两个“through”选项,把clk到clk的组合路径,从clk到clk的时序路径中分离出来;约束完成之后,我们可以查看一下对于组合逻辑的输入输出路径,clk的分析情况:


report_timing -from $in_ports -to [all_outputs]


结果是通过的。


--->约束多周期路径


约束完组合路径,我们就要进行约束时序逻辑路径了。时序逻辑路径是由clk控制的,我们先来看一下clk的时序路径报告:


report_timing -group clk


得到的结果是违规的,这是因为时序逻辑路径中存在多周期路径,在原理图上,mul_result_reg是多周期路径,因此需要进行设置多周期路径约束:


·建立时间的多周期约束:


set_multicycle_path  2  -setup  -to  mul_result_reg*/D


也就是设置这条路径是2个周期的路径;约束完成之后,我们可以查看是否正确约束:


report_timing -to mul_result_reg*/D


可以看到,建立时间的约束满足了,没有违规


·保持时间的多周期约束:


我们查看保持时间是否违规:


report_timing -to mul_result_reg*/D -delay min


可以看到,保持时间是违规的,因此我们要进行保持时间的多周期路径约束:


set_multicycle_path 1 -hold -to mul_result_reg*/D


再次查看之后,我们可以看到,保持时间没有违规了。


基于上面的原理图的各个约束都进行了合适的修改,主要是单独约束组合逻辑、设置虚假路径和设置(时序逻辑的)多周期路径这三个方面。


由于这是因为约束不当而引起综合后的违规,当设置了正当的约束之后,违规就消除了,我们也不必再进行综合了,实战步骤到这里就结束了。


本文转自:http://www.cnblogs.com/IClearner/ 

作者:IC_learner


本文内容仅代表作者观点,不代表平台观点。

如有任何异议,欢迎联系我们。

如有侵权,请联系删除。


往期精彩回顾




2021年的第一场雪!英特尔2020年Q4财报解读



高速 SerDes 技术浅析和前景展望


博文速递:Timing paths


CPU设计的新思路


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存