分为三个部分
1、静态时序分析和
2、基本时序路径约束
3、时序违例的优化方法
一、静态时序分析基础
建立时间,保持时间
为了确保寄存器在时钟沿稳定采集数据,那么必须要满足寄存器的建立,保持时间要求。
建立时间要求:在寄存器有效时钟沿之前至少Tsetup时间,数据必须到达且稳定。如下图所示。
保持时间要求:在数据采集有效时钟沿之后,数据必须维持最短Thold时间不变。如下图所示。
建立时间裕量计算
同步时序电路如下图所示。这里对后面一个寄存器进行建立时间裕量分析。
其中寄存器的输出延时为Tcq,即时钟有效沿之后延时Tcq时间,数据才到达寄存器Q端。第一个寄存器有效时钟沿之后Tcq时间,数据才到达Q1端,如下图所示。
再经过组合逻辑运算,得到数据C1,其中组合逻辑的延时为Tlogic。时序如下图。
从这里可以看到,如果clk2和clk1之间没有延时。那么对于后面的寄存器而言,数据提前于采样时钟沿之前Tcycle-(Tcq+Tlogic)时间到来,且稳定。其中Tcycle为时钟周期。
由于寄存器要求的建立时间为Tsetup,故电路必须满足 Tcycle -(Tcq+Tlogic)- Tsetup>0 。
建立时间裕量 Tset_slack = Tcycle -(Tcq+Tlogic)- Tsetup
如果clk1与clk2之间存在skew,如下图所示,如正skew。得建立时间裕量为
Tset_slack = Tcycle -(Tcq+Tlogic)- Tsetup + Tskew
这是对建立时间有益的。
保持时间裕量计算
在时钟没有skew的情况下。在后一个寄存器有效采样时钟沿之后,同时新的C1只有经过Tcq+Tlogic之后才会到达。故要满足保持时间要求,只需要满足Tcq+Tlogic>Thold。
保持时间裕量Thold_slack = Tcq+Tlogic-Thold
如果clk1与clk2之间存在skew。如下图所示(正skew)。
可以看到,C1_NEW在clk2时钟沿后,Tlogic+Tcq-Tskew就改变了。
此时保持时间裕量Thold_slack = Tcq+Tlogic-Thold - Tskew 。可以看到,正skew对保持时间是无益的。
总结
可以看到,必须满足建立时间要求和保持时间要求,级满足如下关系式。
Tset_slack = Tcycle -(Tcq+Tlogic)- Tsetup + Tskew>0
Thold_slack = Tcq+Tlogic-Thold - Tskew > 0
从中可以看出,建立时间与保持时间要求是一对矛盾的关系,在设计电路时,我们要折中考虑。
二、基本的同步时序路径约束
我们设计的同步时序电路示意图如下。
从上面的示意图可知,一个同步时序电路的时序路径无非就是四种:
(1)从输入端口到内部寄存器(从D_IN经过组合逻辑1,到第一个寄存器数据端口D)。
(2)从内部寄存器到内部寄存器(从第一个寄存器的Q端,经过组合逻辑2,到第二个寄存器的D端)。
(3)从内部寄存器到输出端口( 从第二个寄存器的Q端,经过组合逻辑3,到输出端口 D_O端)。
(4)从输入端口到输出端口(从D_IN经过组合逻辑4到达输出端口D_O)。
先看路径(2),从内部寄存器到内部寄存器。如前文时序逻辑电路的建立,保持时间裕量分析中的详细描述,要满足如下建立保持时间要求。
建立时间裕量:
tsetup_slack = tcycle-(tcq+tlogic) - tsetup+tclk_delay-tjitter>0
保持时间裕量 :
thold_slack = tcq+tlogic-thold-tclk_delay-tjitter>0
对于EDA来说,tsetup(寄存器建立时间要求),tcq(寄存器输出延时),thold(寄存器保持时间要求)它都是知道的。在忽略tjitter(时钟抖动)的情况下,我们需要告诉EDA我们的时钟周期,tcycle。如此EDA工具就会根据我们的给出的tcycle,去优化寄存器到寄存器之间的组合逻辑2的延时(tlogic)和tclk_delay,去满足建立保持时间裕量要求。EDA也会根据我们给出的tcycle,去计算建立保持时间裕量。
因此此时我们只需要对时钟进行约束,约束示例语句如下(在端口clk上创建的时钟,周期为10ns)。
create_clock -period 10 [get_ports clk]
对于路径(1),从输入端口到内部寄存器(从D_IN经过组合逻辑1,到达第一个寄存器的数据端口D),我们需要把上一级的电路示意图也画出来。大家就明白了。如下图所示,上一级的电路模型也可以等效为一个寄存器再通过一个组合逻辑电路。因此时序约束其实也就是变成了,从外部寄存器到内部寄存器之间的时序约束。
从图中可以看到tin_delay(既数据到输入端口的延时)其实等于上一级电路寄存器的输出延时(tcq)加上一级组合逻辑的延时。
此时我们需要满足的建立保持时间要求如下(tlogic1为组合逻辑1的延时)。
建立时间裕量
tsetup_slack = tcycle-tin_delay-tlogic1- tsetup+tclk_delay-tjitter>0
保持时间裕量
thold_slack = tin_delay+tlogic1-thold-tclk_delay-tjitter>0
同样在忽略tjitter的情况下,我们只需要告诉EDA工具tcycle,tin_delay,如此EDA就会根据我们的条件去约束组合逻辑1的延时以及tclk_delay,从而使得电路满足建立保持时间要求。
设置tcycle的方式,上面已经说过。设置输入延时(tin_delay)的约束命令示例如下(-clock用于指定时钟域,2表示设置输入延时为2ns):
set_input_delay -clock clk 2 [get_ports D_IN]
对于输入端口的完整约束示例如下:
create_clock -name clk -period 10 [get_ports clk]
set_input_delay -clock clk 2 [get_ports D_IN]
当然对于输入延时的定义也可以用 -max -min去分别定义一个最大值和最小值。在分析建立时间裕量时,EDA工具会用最大值去分析;在分析保持时间裕量时,EDA工具会用最小值去分析。定义示例如下:
create_clock -name clk -period 10 [get_ports clk]
set_input_delay -clock clk -max 4 [get_ports D_IN]
set_input_delay -clock clk -min 1 [get_ports D_IN]
对于路径(3),从内部寄存器到输出端口(从第二个寄存器的Q端经过组合逻辑3到输出端口D_O),同样我们把它的下一级电路示意图也画出来。其下一级电路也是通过组合逻辑送到寄存器这种结构。问题也就可以等效为寄存器到寄存器之间的时序约束。
同样在忽略时钟抖动的情况下,我们需要告诉EDA工具数据从输出端口到下一级电路寄存器的延时tout_delay和tcycle。此时EDA工具就会根据如下要求去优化组合逻辑3的延时tlogic3以及tclk_delay,以及计算静态时序裕量。
建立时间裕量
tsetup_slack = tcycle-tout_delay-tlogic3- tsetup+tclk_delay-tjitter>0
保持时间裕量
thold_slack = tout_delay+tlogic3-thold-tclk_delay-tjitter>0
约束输出延时(tout_delay)的示例如下(-clock 指定时钟域)。
create_clock -name clk -period 10 [get_ports clk]
set_output_delay -clock clk 6 [get_ports D_O]
同样,输出延时也可以用 -max -min指定一个最大值和一个最小值。
create_clock -name clk -period 10 [get_ports clk]
set_output_delay -clock clk -max 6 [get_ports D_O]
set_output_delay -clock clk -min 2 [get_ports D_O]
对于路径(4)(从输入端口经过组合逻辑4再到输出端口),这时候我们必须联合上下两级电路来考虑。我们要先明确从上一级电路获取数据的输入延时tin_delay,以及其送到下一级电路的tout_delay。如此EDA工具才知道如何去做组合逻辑4的时序优化与做静态时序计算。
此时需要满足的时序要求如下:
建立时间裕量
tsetup_slack = tcycle-tin_delay-tout_delay -tlogic4- tsetup+tclk_delay-tjitter
保持时间裕量
thold_slack = tin_delay+tout_delay+tlogic4-thold-tclk_delay-tjitter
在忽略时钟抖动的情况下,我们需要约束输入延时,输出延时。示例约束语句如下。
create_clock -name clk -period 10 [get_ports clk]
set_input_delay -clock clk 4 [get_ports D_IN]
set_output_delay -clock clk 1 [get_ports D_O]
三、时序违例的优化方法概述:
先读前文
《静态时序分析基础》
《基本的同步时序路径约束》
建立时间违例
从前文《静态时序分析基础》可以看出,如果建立时间裕量不满足要求有两种情况。
第一:
时钟频率定的太高,导致Tcycle太小,使得不满足建立时间要求。当然最简单的就是降低时钟频率,
但是一般一个电路架构定下来的时候为了满足速度与吞吐率的要求,频率一般不允许有太大的改动。
第二:
那就是工艺定的实在不合适,基本cell延时很大,可以换更先进的工艺。
其实上面两种可能性在实际真正的项目里面发生的可能不大,一般项目实际编码之前,架构师对工艺与频率都是评估过的。
那实际让我们工程师去解决的问题就是由于两级寄存器之间的组合逻辑延时太大造成的问题。
解决思路有如下。
前端设计:
1. 可以考虑关键路径上的逻辑并行化(重排部),减少链路延时。举个简单的例子,比如out = a+b+c+d。
将设计由下图
改成下图,资源不变,其延时由三个加法器延时变成了两个加法器的延时。
- 可以考虑有些功能电路的更优设计以降低延时,比如,大家都知道超前进位加法器比行波逐位进位链加法器的延时更短。
- 再就是卡诺图化简,较少门级资源同时也会对速度有所优化,但是一般综合工具可以做到。
- 如果上述都解决不了,建立时间违例比较严重,就需要考虑插入寄存器,形成流水线(pipline)。还拿上面的out = a+b+c+d为例,插入流水形成如下图所示电路。关于流水线设计示例,见文章《Verilog流水线设计》。流水线设计其实也就是降低两级寄存器之间的组合逻辑延时,从而使得主频可以跑的更高。
后端设计:
1. 后端设计可以通过调整关键路径的时钟SKEW来解决,但是一般只是针对小范围的违例。
2. 可以采用多阈值单元,从半导体器件原理大家都知道,mos管阈值越小,其延时越小,可以在关键路劲采用阈值小的单元。
3. 可以采用面积更小的门级单元,面积大容载大,自然延时大(当然面积大的单元其驱动能力强)。
其他:
1. 可以通过适当提高工作电压来解决,电路的延时本质就是充放电的延时,如果电压越高,充放电时间就会越快。
2. 这也是为什么CPU超频时需要更高的工作电压。因此也可以通过提高关键模块的工作电压,划分不同的工作电压域。
保持时间违例
保持时间裕量与建立时间裕量是一对互斥的关系,上述可以用于优化建立时间裕量的方法,都不能用于优化保持时间裕量,大家要注意。
保持时间违例可以通过如下方式解决:
1. 在组合逻辑中插入延时buffer,或者链路拉长,使得Tlogic变大。
2. 可以在后端调整时钟SKEW,使得违例寄存器的时钟SKEW变得更小(相对于正SKEW)