经过BUFGMUX的时钟该如何约束(更新)

作者:张海军:傅里叶的猫微信公众号

我们先看UG949中举的例子:

时序场景如下图所示,clk0和clk1两个时钟输入,经过BUFGMUX后,输出到后面的逻辑,但同时clk0和clk1还分别驱动了其他逻辑。

此时,如果路径A/B/C都不存在,其中A路径表示clk0与选择器输出的时钟之间的数据交互,B路径表示clk1与选择器输出的时钟之间的数据交互,C路径表示clk0和clk1之间的数据交互,那么使用下面的约束就可以了:

set_clock_groups -logically_exclusive -group clk0 -group clk1

如果clk0和clk1之间有数据交互,则需要使用下面的约束:

create_generated_clock -name clk0mux -divide_by 1 \
-source [get_pins mux/I0] [get_pins mux/O]
create_generated_clock -name clk1mux -divide_by 1 \
-add -master_clock clk1 \
-source [get_pins mux/I1] [get_pins mux/O]
set_clock_groups -physically_exclusive -group clk0mux -group clk1mux

这里我们解释一下logically_exclusive和physically_exclusive的区别:

-logical_exclusive

logical_exclusive is used for two clocks that are defined on different source roots.
Logically exclusive clocks do not have any functional paths between them, but might have coupling interactions with each other.
An example of logically exclusive clocks is multiple clocks, which are selected by a MUX but can still interact through coupling upstream of the MUX cell.
When there are physically existing but logically false paths between the two clocks, use "set_clock_groups -logical_exclusive".

-physical_exclusive

physical_exclusive is used for two clocks that are defined on the same source root by "create_clock -add".
Timing paths between these two clocks do not physically exist.
As a result you will need to use "set_clock_groups -physical_exclusive" to set them as false paths.

简而言之,logical_exclusive用于选择器的电路,两个时钟的source不一样;而physical_exclusive两个时钟的source是一样,比如在同一个时钟输入口,但可能会输入两个不同的时钟。

下面我们来看下为什么要这样约束。

我们先来复习一下set_clock_groups的用法,set_clock_groups后面可以加的参数有三个,除了logically_exclusive和physically_exclusive,还有我们最常用的-asynchronous,无论后面是哪个参数,set_clock_groups就是让工具不去分析我们后面约束的时钟组,只是这三个参数的应用场景略有不同。

在第一个场景中,clk0和clk1之间没有数据交互,因此工具不需要分析它们之间的路径,而且它们后面有时钟选择器,符合logical_exclusive的使用场景,因此约束是

set_clock_groups -logically_exclusive -group clk0 -group clk1

在第二个场景中,clk0和clk1之间是有数据交互的,就不能直接把这个时钟设置clock group,但经过MUX之后的时钟,只会有一个存在,这两个时钟之间肯定是不存在交互的,所以这两个时钟需要设置clock group,而这两个时钟有same source root,因此使用的参数是physical_exclusive。

有同学可能会问,对于第一个场景,MUX之后的时钟也是只存在一个,为什么不需要再分别generate clock,然后设置physical_exclusive呢?

我个人理解,这就跟时钟传播有关系,什么情况下时钟不向后传播:

The source latency paths do not flow through sequential element clock pins, transparent latch data pins, or source pins of other generated clocks.

选择器既不是sequential element,也不是latch,因此只要我们后面没有create generated clock,那么时序路径就可以继续向后传播,我们已经设置了前面的两个时钟的logically_exclusive,因此后面的电路,只要时钟路径没有断,那就都存在logically_exclusive。

需要注意一点:create_clock或者create_generated_clock之后,原来在当前点传播的clk不在向后传播

因此,针对上面的电路,假设clk0和clk1之间有数据交互,我们还可以用下面的方法约束:

在pinI0和pinI1处,我们create一个generated_clock,这样clk0和clk1就不再向mux传播,但FD0和FD1仍然是clk0和clk1所在的时钟路径。(下面默认clk0和clk1已经create)

create_generated_clock -name clk_I0 \
[get_pins mux/I0] \
-master_clock clk0 \
-divide_by 1 \
-source [get_ports pinclk0] \
-add
create_generated_clock -name clk_I1 \
[get_pins mux/I1] \
-master_clock clk1 \
-divide_by 1 \
-source [get_ports pinclk1] \
-add

set_clock_groups -logically_exclusive -group clk_I0 -group clk_I1

在网上还看到有个说法,而且已经经过了DC工具的验证:set_clock_groups的三个参数asynchronous、logically_exclusive和physically_exclusive的实际作用是一样的,都是设成异步,因此上面的约束中,这三个参数可以随便用。

但是既然工具给出了三种参数的使用场景,那我们就应该按照场景来使用这三个参数。