目录
1.set_clock_groups
1.1 有多个 -group
1.2 有单个 -group
1.3 多级使用set_clock_groups
1.4 asynchronous/logically_exclusive/physically_exclusive 三个参数区别
1.4.1 总结
1.5实例分析
方法一:
方法二:
补充说明:
在硬件设计中,没有设置clock groups前,综合工具是把所有的clk作为同步clk来处理,具体的表现是工具会分析所有任意两两clk的timing。所以应该理解为:增加group 是在原来同步的基础上增加异步描述,不在描述中的还保持同步关系【当然也可能是clk之间没有path】
set_clock_groups 命令有三个选项:“-asynchronous”,“-logically_exclusive”,“-physically_exclusive”
上面三个选项其实是为了不同场景下设置clock groups更容易理解,其实实际的作用是一样的。也就是让不同的clk groups之间不进行timing check。
假设一个设计中有clk_a, clk_b, clk_c, clk_d, clk_e, clk_f共六个时钟。set_clock_groups有以下写法:
set_clock_groups -asynchronous -name async_xxx0_group \
-group [list clk_a clk_b] \
-group [list clk_c clk_d]
set_clock_groups -logically_exclusive -name async_xxx1_group \
-group [list clk_a clk_b] \
-group [list clk_c clk_d]
set_clock_groups -physically_exclusive -name async_xxx1_group \
-group [list clk_a clk_b] \
-group [list clk_c clk_d]
上面三条语句其实都是一个效果:
from clk_a to clk_c/clk_d不check timing
from clk_b to clk_c/clk_d不check timing
from clk_c to clk_a/clk_b不check timing
from clk_d to clk_a/clk_b不check timing
其他clk之间都check timing【包括不在分组之内的clk_e和clk_f】
套用同异步的概念,六个时钟,只有 clk_a and clk_b和clk_c and clk_d是异步的其他两两之间都是同步时钟。
从上面的效果来说,又可以等价为以下的语句
set_false_path -from [get_clocks [list clk_a clk_b]] -to \
[get_clocks [list clk_c clk_d]]
set_false_path -from [get_clocks [list clk_c clk_d]] -to \
[get_clocks [list clk_a clk_b]]
虽然set_clock_groups的三种形式和set_false_path的作用效果是一样的 但是这些命令是各自用在不同的场景下,比如全部用set_false_path就体现不出clk group及同异步的概念。后续章节也会介绍set_clock_groups的三种形式的各自场景。
set_clock_groups -asynchronous -name async_xxx0_group \
-group [list clk_a clk_b]
set_clock_groups -logically_exclusive -name async_xxx1_group \
-group [list clk_a clk_b]
set_clock_groups -physically_exclusive -name async_xxx1_group \
-group [list clk_a clk_b]
这种只有单-group的含义是
clk_a和clk_c, clk_d, clk_e, clk_f都不需要check timing
clk_b和clk_c, clk_d, clk_e, clk_f都不需要check timing
clk_a和clk_b需要check timing
clk_c, clk_d, clk_e, clk_f 相互之间需要check timing
或者套用同异步说法 clk_a和clk_b同步和其他clk都是异步
在介绍“-asynchronous”,“-logically_exclusive”,“-physically_exclusive”三个参数区别之前,本节只用“-asynchronous”来举例,其他两个参数也是相同的用法。
当 set_clock_groups 命令中多个 groups 被指定时,同一个时钟不能出现在不同的 group 中,但是可以存在于多次 set_clock_groups 命令使用。
例如:设计认为clk_a和clk_b是同步clk,clk_a和clk_d也同步,但是clk_b和clk_d异步,我们先写出下面的约束:
set_clock_groups -asynchronous \
-group {Clk_a Clk_b} \
-group {Clk_c} \
-group {Clk_a Clk_d}
结果运行发现上面这种写法就是错的,这是因为工具无法实现clk_a自身clk 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}
多个时钟之间相位关系不确定,就可以将这两个(或多个)时钟是asynchronous,一般而言当时钟来自于不同的PLL或者晶振时,时钟之间的相位是不固定的。此时就用asynchronous来设置异步时钟分组。
如果一个电路中有两个 clock, 但是有一个选择信号控制这两个 clock,那么在这个mux之后会存在两个clk,这两个clk就可以设置为logically_exclusive.
设logically_exclusive一定要满足这两个clk在传播路径上没有相互的path,为了保证这一点,就需要在mux的两个输入端generated 新的clk,设新generated 的clk之间是logically_exclusive,那么路径上寄存器就不会检查这两个新的generated clk之间的timing。
如上图可以在pin_2和pin_3 generated clk并设为logically_exclusive,而不能将pin_0和pin_1上的clk设为logically_exclusive。pin0clk和pin1clk是有path的,而且不是异步电路 是需要收timing的。
需要注意的是上文中所说的mux是一种准静态或静态选择,在电路工作时只能选pin2clk或pin3clk。假如是个动态选择,比如上一拍选择pin2clk,下一拍选择pin3clk,这时就会出现B0寄存器用pin2clk launch ,B1寄存器用pin3clk capture的情况,这时是需要check timing的。
如果两个 clock 定义在同一个端口上,那么这两个 clock 在物理层面就是不可能同时存在的,此时就需要声明成 physical exclusive.
还是参考上图,pin4会流过两个clk,一个是clk0一个是clk0的二分频。这两个频率是准静态或静态切换的。那么可以在pin4上分别generated pin4clk0和pin4clk0_d2,把这两个clk设为physically_exclusive。
还有一种情况某一个clk pin上在function mode是funClk在testMode是testCk,而且后端flow要求funMode和testMode一起收timing【大部分情况下是单独收timing】,那么funclk和testCk就可以在这个pin上设为physically_exclusive。
总结起来:
asynchronous:就用在设置异步时钟分组
logically_exclusive:就是两个时钟同时存在,且有一个选择端控制这两个信号,后续clkpath在工作时只选择一个clk
physically_exclusive:两个 clock 不可能同时出现在电路中(比如定义在同一个点上)
有前文说明 这三个参数的实际作用是一样的,我们不考虑asynchronous,因为这个场景很明确。logically_exclusive和physically_exclusive是否可以混用呢?
答案是肯定的 【经过在dc工具上验证的结论】上图中我们可以把pin2clk和pin3clk 设为physically_exclusive。同样也可以把pin4clk0和pin4clk0_d2设为logically_exclusive。或者设计中我们只用physically_exclusive或只用logically_exclusive,更有甚者我们把pin2clk和pin3clk 设为asynchronous,把pin4clk0和pin4clk0_d2设为asynchronous,这些都没问题。
但是既然工具区分了这三种应用场景,最好是按场景使用。以便于理解。
还是采用和1.4节相同的电路图:
时钟mux是静态或准静态切换,A0--->AC0, B1--->BA0,B1--->BC0都是同步电路,需要check timing,那么我们该如何下sdc的约束呢?
create_clock -name clk_0 -period ${CLK_PERIOD_XXX} [get_ports pin_0]
create_generated_clock -name clk_0_d2 \
[get_pins div2_reg/D] \ #//pin_1
-master_clock clk_0 \
-divide_by 2 \
-source [get_ports pin_0] \
-add
create_generated_clock -name clk_0_pin_2 \
[get_pins pin_2] \
-master_clock clk_0 \
-divide_by 1 \
-source [get_ports pin_0] \
-add
create_generated_clock -name clk_0_d2_pin_3 \
[get_pins pin_3] \
-master_clock clk_0 \
-divide_by 1 \
-source [get_ports div2_reg/D] \ #//pin_1
-add
set_clock_groups -logically_exclusive -name yyyy \
-group [list clk_0_pin_2] \
-group [list clk_0_d2_pin_3]
#set_clock_groups -physically_exclusive -name yyyy \
# -group [list clk_0_pin_2] \
# -group [list clk_0_d2_pin_3]
其中line30--32的作用效果和line26---line28是一样的;但是line30--32写法不正规,也不容易理解。
设logically_exclusive必须按照上面的约束,分别在pin_2和pin_3上generated clk,因为我们的目标是不检查B0和B1寄存器上传播的clk_0_d2_pin_3和clk_0_pin_2之间的timing,如果设置clk_0和clk_0_d2为logically_exclusive,那么BA0,BC0,AC0寄存器上clk_0和clk_0_d2就不会check timing,显然是不符合要求的。
create_clock -name clk_0 -period ${CLK_PERIOD_XXX} [get_ports pin_0]
create_generated_clock -name clk_0_d2 \
[get_pins div2_reg/D] \ #//pin_1
-master_clock clk_0 \
-divide_by 2 \
-source [get_ports pin_0] \
-add
create_generated_clock -name clk_pin_4_0 \
[get_pins pin_4] \
-master_clock clk_0_pin2 \
-divide_by 1 \
-source [get_ports pin_2] \
-add
create_generated_clock -name clk_pin_4_1 \
[get_pins pin_4] \
-master_clock clk_0_d2_pin3 \
-divide_by 1 \
-source [get_ports pin_3] \
-add
#create_generated_clock -name clk_0_pin_2 \
# [get_pins pin_2] \
# -master_clock clk_0 \
# -divide_by 1 \
# -source [get_ports pin_0] \
# -add
#
#
#create_generated_clock -name clk_0_d2_pin_3 \
# [get_pins pin_3] \
# -master_clock clk_0_d2 \
# -divide_by 1 \
# -source [get_pins div2_reg/D] \ #//pin_1
# -add
#
#create_generated_clock -name clk_pin_4_0 \
# [get_pins pin_4] \
# -master_clock clk_0_pin2 \
# -divide_by 1 \
# -source [get_pins pin_2] \
# -add
#
#create_generated_clock -name clk_pin_4_1 \
# [get_pins pin_4] \
# -master_clock clk_0_d2_pin3 \
# -divide_by 1 \
# -source [get_pins pin_3] \
# -add
set_clock_groups -physically_exclusive -name xxxx \
-group [list clk_pin_4_0] \
-group [list clk_pin_4_1]
#set_clock_groups -logically_exclusive -name xxxx \
# -group [list clk_pin_4_0] \
# -group [list clk_pin_4_1]
其中line61---line63和line57---line59作用效果一样。但是line61---line63写法不正规,也不容易理解。
无论采用line28---line55的方式generated clk_pin_4_0和clk_pin_4_1还是采用line12---line24的方式generated clk_pin_4_0和clk_pin_4_1结果对于check timing来说都是一样的。
比如说在pin_2点没有generated clk_0_pin_2之前,该点的clk属性时clk_0,generated clk_0_pin_2之后,该点及后面只有generated clk_0_pin_2在propagation而没有clk_0.
同理在没有generated clk_pin_4_0和clk_pin_4_1之前 pin_4上传播的clk是clk_0_pin_2和clk_0_d2_pin_3,创建之后只有clk_pin_4_0和clk_pin_4_1。假如我在pin_4只创建了clk_pin_4_0,那么pin_4及以后clkTree就只有clk_pin_4_0.
假如在pin_4 generated clk_pin_4_0和clk_pin_4_1时没有加-add,那么最终pin_4上只有clk_pin_4_1。
create和generated clk相当于同时执行了set_sense -type clock -stop_propagation命令,比如在pin_2点,相当于同时执行:
set_sense -type clock -stop_propagation \
-clocks [get_clocks clk_0] \
get_pins pin_2
create_generated_clock -name clk_0_pin_2 \
[get_pins pin_2] \
-master_clock clk_0 \
-divide_by 1 \
-source [get_ports pin_0] \
-add