时序分析基本概念介绍——时钟(create_clock/create_generated_clock/set_clock_uncertainty/set_clock_groups)
目录
前言
任何sdc首先定义的都是时钟。Clock主要包含Waveform、Uncertainty和Clock group的定义。我们把它们称为时钟的三要素,当然创建任何时钟都要检查一下这三者有没有定义正确。
一、clock的属性
clock period
时钟周期为时钟频率的倒数,又称为振荡周期。

clock duty cycle
clock duty cycle指时钟高电平信号在一个周期内所占的时间比率,大部分时钟占空比为50%,即高/低电平各占0.5个周期。
在create_clock的-waveform中,第一个变量是上升沿出现的时刻,第二个变量是下降沿出现的时刻,如果上升沿出现在0ns,下降沿出现在5ns,周期为20的clock对应的波形图如下。

clock latency
Clock latency通俗意义上是指clock定义点到clock sink点(时序器件的clock pin)之间的这段delay。其分为两类,source latency和network latency。
source latency也称作insertion delay,通常是指clock source端到clock定义点之间的这段时间延迟。通常有两种情况,其一:clock 直接来自于芯片外部,如crystal clock,此时,source latency指的是芯片外部crystal出口到芯片PAD(假如clock定义在此处)之间的时间延迟;其二:clock 来自于芯片内部的PLL,此时,source latency指的是芯片内部PLL输出点到芯片内部某个第一个clock定义点之间的这段时间。
network latency 指的是clock定义点到clock sink点之间的这段delay。

这两种latency是每一个clock的固有属性,当CTS完成之后,每一个clock如果是在propagation状态下,其source latency和network latency都是确定的。当然,在前期(PR之前或者CTS之前),通常情况下clock都处于ideal状态,为了能够模拟真实的情况,我们可以通过指令set_clock_latency去指定每个clock的source latency或者network latency。
clock slew
时钟转换时间clock transition time ,也称为clock slew。通常是指电压从10%VDD上升到90%VDD所需要的时间,或者是从90%VDD下降到10%VDD所需要的时间,上升和下降时间过长意味着电路的速度很慢。如下图所示。

在sdc中,可以用set_max_transition 0.1 -clock_path[all_clocks]命令来限制clock slew大小。
clock skew
在CTS中,由于时钟到每个寄存器的路径延迟不一样,造成信号到达 clock pin 的时间也不一样,寄存器也不会同时翻转。时钟偏差(skew) 的定义就是最长路径延迟减去最短路径延迟的值。一直以来,Skew都是衡量时钟树性能的重要参数,CTS的目的就是为了减小skew。

clock jitter
所谓抖动(jitter)指的是在某一个给定的点上时钟周期发生短暂性的变化,使得时钟周期在不同的周期上可能加长或缩短。这是在时钟发生器内部产生的,和晶振或者PLL内部电路有关,布线对其没有影响。
二、create_clock
SoC的时钟一般是由PLL产生,然后经过时钟生成电路和分配网络,最终给具体的功能模块使用。一般地,第三方IP供应商都会提供比较成熟的SDC,SoC集成时只需稍作修改。对于自研的IP和SoC顶层,设计人员在提供RTL的同时,也需提供一份时钟结构图,一方面是方便撰写SDC,另一方面对后端P&R有针对性的进行CTS也非常有帮助。
create_clock命令比较简单易懂,格式如下:
create_clock [-name clock_name] \
-period period_value \
[-waveform edge_list] \
[-add] \
[source_objects]
其中,-waveform中的数值依次代表上升沿和下降沿的时刻,如果没有定义,默认为-waveform {0 period_value/2},即it has a rise edge of 0.0 and a fall edge of period_value/2.
另外,如果需要对已经定义过clock的source再多定义一个clock,则需要加上 - add,如果不加后面定义的clock会把之前定义的clock覆盖掉,即之前定义的clock就不存在了。
三、create_generated_clock
create_generated_clock 需要指定源时钟(-master_clock)的master_pin(-source),在CTS时,默认会去balance这两个时钟(即generated clock 和 master clock),让skew尽可能小。
create_generated_clock的格式如下:
create_generated_clock [-name clock_name] \
-source master_pin \
[-master_clock clock] \
[-edge edge_list] \
[-edge_shift shift_list] \
[-divide_by factor] \
[-multiply_by factor] \
[-duty_cycle percent] \
[-combinational]
[-invert] \
[-add] \
source_objects
其中,当master_pin有多个clocks时,需要通过-master_clock 指定是哪一个clock。另外,如果generated clock只经过组合逻辑时,一定要加上-combinational, 否则在分析timing的时候clock_path会穿过时序逻辑。
例如:下面为一个三分频电路。

create_clock -name SYSCLK -period 2.2 [get_ports SYSCLK]
create_generated_clock -name DIV3B \
-source [get_ports SYSCLK] \
-edges { 3 5 9 } \
[get_pins U3/Q]
create_generated_clock -name DIV3C \
-source [get_ports SYSCLK] \
-edges { 3 5 9 } \
-edge_shift {2.2 2.2 2.2} \
[get_pins U4/QN]
一般我们把时钟的源头会定义成create_clock,而分频时钟则会定义为create_generated_clock。两者的主要区别在于CTS步骤,generated clock并不会产生新的clock domain, 而且定义generated clock后,clock path的起点始终位于master clock, 这样source latency并不会重新的计算。
在工具中report_timing的时候,如果想要将master clock的部分也展开, 则可以通过添加选项 -path_type full_clock_expanded。
report_timing -path_type full_clock_expanded
四、set_clock_uncertainty
在pre-CTS的时候,我们将时钟的不确定性设定为skew和jitter值之和来模拟真实的时钟;而post-CTS之后,时钟树propagate delay已经确定,skew真实存在,所以uncertainty就是时钟的真实抖动值。
set_clock _uncertainty主要定义了clock信号到时序单元的clock端可能早到或晚到的时间。主要是用来降低jitter对有效时钟周期的影响。
五、set_clock_groups
定义完时钟后,我们也需要通过设置clock group来确认各个时钟之间的关系。这是很重要的一步,因为通常我们还需要做cross domain check,如果clock group设错了,会导致整个STA检查错误。
没有设置clock groups前,工具是把所有的clock作为同步来处理,增加set_clock_groups是在原来同步的基础上增加异步描述,不在描述中的还保持同步关系。
一般有三个选项 :asynchronous,physically_exclusive和logically_exclusive。
asynchronous代表两个异步的clock group;
physically_exclusive代表两个clock group在物理意义上相互排斥,比如在一个source pin上定义了两个时钟;
logically_exclusive代表两个clock group在逻辑上相互排斥,比如两个clock经过MUX选择器。
set_clock_groups只有一个-group
当set_clock_groups只有一个-group,表示-group里面的clocks和-group外面的clocks是异步的。
set_clock_groups -asynchronous -name async_group -group [list clk_a clk_b]
set_clock_groups -physically_exclusive -name async_xxx1_group -group [list clk_a clk_b]
set_clock_groups -logically_exclusive -name async_group -group [list clk_a clk_b]
上面的命令表明 clk_a和除 clk_b以外的clocks都是异步的;clk_b和除 clk_a以外的clocks都是异步的; 其余任意两个clocks都是同步的。
set_clock_groups有多个-group
当set_clock_groups有多个-group,表示-group和-group之间是异步的。
set_clock_groups -asynchronous -name async_group \
-group [list clk_a clk_b] \
-group [list clk_c clk_d]
set_clock_groups -logically_exclusive -name async_group \
-group [list clk_a clk_b] \
-group [list clk_c clk_d]
set_clock_groups -physically_exclusive -name async_group \
-group [list clk_a clk_b] \
-group [list clk_c clk_d]
上面的命令表明 {clk_a clk_b}和{clk_c and clk_d}是异步, 即clk_a和clk_c异步,clk_a和clk_d异步, clk_b和clk_c异步, clk_b和clk_d异步, 其余任意两个clocks都是同步的。
多个 set_clock_groups
当 set_clock_groups 命令中有多个 -group,同一个时钟不能出现在不同的 -group 中,但是可以存在于多个 set_clock_groups 命令。
例如: 设计认为clk_a和clk_b是同步,clk_a和clk_d也同步,但是clk_b和clk_d异步,且clk_c和 clk_a/b/d异步,根据字面表达我们先写出下面的约束:
set_clock_groups -asynchronous \
-group {clk_a clk_b} \
-group {clk_c} \
-group {clk_a clk_d}
但是上面这种写法是错的,因为工具无法实现clk_a自身clock domain内不check timing。
但是要怎么实现clk_b和clk_d之间不check timing呢?
实现方法如下,即把它们关系拆开来写:
set_clock_groups -asynchronous \
-group {clk_a clk_b} \
-group {clk_c}
set_clock_groups -asynchronous \
-group {clk_a clk_d} \
-group {clk_c}
set_clock_groups -asynchronous \
-group {clk_b} \
-group {clk_d}
三个参数的实际作用是一样的,是否可以混用?既然工具区分了这三种应用场景,最好是按场景使用。以便于理解。
更多推荐
所有评论(0)