对时钟约束的补充;多个时钟同步电路;分频时钟;异步设计约束;多时钟周期约束
一:对timing时序的补充
1:占空比不为50%
**单沿触发,占空比对综合无影响;双沿触发,占空比对综合有影响。
(1)通过-wave_form改变占空比;例如 create_clock -period 2 -wave_form {0 0.6} [get_ports CLK]
(2)通过-wave_form改变初始相位,但是不推荐
create_clock -period 2 -wave_form {0.4 1.4} [get_ports CLK]
我们通常使用set_clock_latency来指定相位偏移。
(3)复杂时钟
create_clock -period 1.6 -wave_form {0 0.4 0.6 1.4} [get_ports CLK]
在求最大延时时,以两相邻最短上升沿为标准。
2:寄存器延迟(复杂时钟)
create_clock -period 1.6 -wave_form {0 0.4 0.6 1.4} [get_ports CLK]
Tff2_setup=0.03ns,则寄存器最大延迟为:Tmax<=0.6-0.03=0.57ns
3:输入时钟的其他约束
(1)输入时钟有不同沿触发
create_clock -period 2 [get_ports CLK]
set_input_delay -max 0.3 -clock CLK -clock_fall [get_ports A]
FF1由下降沿触发,FF2由上升沿触发,所以:
Tmax<=1ns-0.3ns-Tsetup
(2)输入路径有多个
create_clock -period 2 [get_ports CLK]
set_input_delay -max 0.3 -clock CLK -clock_fall [get_ports A]
set_input_delay -max 1.2 -clock CLK -add_delay [get_ports A];#一定要加上-add_delay,不然第二个延迟信息会覆盖第一个延迟信息
若Tsetup=0.14
Tmax1<=1-0.3-0.14=0.56 Tmax2<=2-1.2-0.14=0.66 DC
(3)driving cell 对输入路径的影响
set_input_delay -max 0.6 -clock CLK [get_ports A]
set_driving_cell -lib_cell NAND2_3 [get_ports A]
产生transition延迟
4:输出时钟的其他约束
create_clock -period 4 [get_ports CLK]
set_output_delay -max 2.5 CLK [get_ports B]
set_output_delay -max 0.7 CLK -clock_fall -add_delay [get_ports B]
T1max <= 4-2.5-0.1=2.4ns
T2max <= 2-0.7=1.3ns
DC会选择最小的Tmax来约束。
二:多个时钟同步电路
同步时钟:一个时钟源产生的时钟或者分频产生所有需要的时钟
下面我们来对多时钟同步设计的时序路径进行约束,多时钟电路的模型如下所示:
我们要综合的模块的时钟是CLKC,但是前后模块的时钟不一定是CLKC,但是前后模块的时钟跟CLKC是来源于同一个时钟的,比如说经过锁相环分频或者倍频,这里拿分频来举例,比如说CLKA、 CLKB、CLKC、CLKD、CLKE都是由同一个时钟CLK经过分频得来,如下图所示:
(虽然上面说是同步电路,但是在传统上看,上面的电路不算是同步时钟,因为他们的相位没有固定的关系;但是在这里,我们“假装”它们是同步时钟,因为理论上,是由同一个时钟分频得来的,在理想情况下,我们是可以知道它们的相位关系的)
在我们要综合的电路中,只有一个时钟端口CLKC,即只有CLKC时钟驱动要综合电路中的寄存器。其他的时钟CLKA,CLKB,CLKD和CLKE在我们要综合的电路中并没有对应的时钟端口。因此,它们并不驱动要综合电路中的任何寄存器。它们主要用于为输入/输出端口延时作约束,可能会出现一个端口有多个约束的情况。
下面我们根据上面的例子作多时钟的同步设计约束,也就是为下面的电路类型做约束:
CLKC在要综合的设计中有对应的输入端口,其定义与单时钟时一样,即:
create_clock -period 20 [get_ports CLKC]
由于CLKA,CLKD和CLKE在要综合的设计中没有对应的输入端口,因此需要使用虚拟(virtual)时钟。虚拟时钟在设计里并不驱动触发任何的寄存器,它主要用于说明相对于时钟的I/O端口延迟,DC将根据这些约束,决定设计中最严格的约束。建立虚拟时钟的格式如下:
上面定义了名字为VCLK的虚拟时钟,周期为20ns。因为虚拟时钟不驱动设计中的任何寄存器,设计中没有其对应的输入端口。所以定义中没有源端口或引脚。由于虚拟时钟没有对应的时钟端口,我们必须给它一个名字。与一般时钟一样,虚拟时钟是DC的内存里已定义的时钟物体(设计对象),它(们)不驱动(触发)当前设计中的任何寄存器。用作为输入/输出端口设置延迟。
1:输入延时时钟
对应的约束为:
DC会选择两个时钟上升沿相差最小的时间作为标准
Tmax<=T - 0.55 -Tsetup = 1-0.55-Tsetup
2:输出延时时钟
创建的虚拟时钟为:
create_clock -period [expr 1000/750.0] -name CLKD ;#
create_clock -period 1.0 -name CLKE
create_clock -period 2.0 [get_ports CLKC]
对应的约束为:
set_output_delay -max 0.1 -clock CLKD [get_ports OUT1]
set_output_delay -max 0.47 -clock CLKE [get_ports OUT1]
所以:Tcdmax <= T(最短上升沿差) - 0.1 = 0.67 - 0.1 =0.57
Tcemax <=T(最短上升沿差) - 0.47 = 1 - 0.47 = 0.53
DC会选择最小数Tcemax(最严格情况)为约束延时。
三:分频时钟约束
经过二分频后从寄存器FF2的输出端口Q输出的时钟,但DC并不知道这是你的时钟信号,需要添加相应的约束,如下所示:
create_generated_clock -divide_by 2 -name CLK -source [get_ports CLK] [get_pins FF1/Q] ;#第一个中括号代表分频的源时钟,第二个中括号代表输出分频的引脚。
四:异步设计路径和逻辑上不存在的路径的时序约束(时序例外)
(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)。可以用下面的拓扑图理解:
通过以下约束禁止对这两路信号进行优化
set_false_path -from [get_clocks A1] -to [get_clocks A2]
set_false_path -from [get_clocks B1] -to [get_clocks B2]
我们可以用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
五:多时钟周期的约束
当某个模块比较复杂,延迟时间远大于一个时钟周期
(1)关于建立时间
如下图所示加法器电路,时钟clk的周期定义为10ns,按设计规格,加法器的延迟约为6个时钟周期:
①默认的的建立时间约束
默认的时间建立时间约束将指示DC在10ns的时候对C_reg进行建立时间是否满足的分析;很显然,默认的时序约束会使寄存器的数据输入引脚C_reg/D信号变化,不满足建立(setup)的要求,将产生亚稳态,寄存器C_reg的输出为不定态。也就是一个时钟周期的约束不能满足约束要求。
②修改后的建立时间约束
对于多时钟周期的建立时间约束,可以使用下面命令进行修改:
create_clock -period 10 [get_ports CLK]
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能够综合出能够正确工作的多时钟周期的加法器。对于前面的加法器,可以需要加上相应的使能信号,因此电路设计如下所示: