前言

任何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会穿过时序逻辑。
例如:下面为一个三分频电路。
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/84f19eb9d7974cf6947800503326b702.png

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}

三个参数的实际作用是一样的,是否可以混用?既然工具区分了这三种应用场景,最好是按场景使用。以便于理解。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐