LJgibbs · 2023年07月19日 · 北京市

[译文] 在综合中约束生成时钟和异步时钟

image.png

原文地址:https://vlsitutorials.com/constraining-generated-clocks-and-asynchronous-clocks-in-synthesis/
后附英文原文

本文是 how to define Synthesis timing constraint 系列文章的第四篇。

Generated Clocks // 生成时钟

image.png
Figure 1: Generated clock in a design //图 1:设计中的生成时钟示例

图 1 中,CLK 在驱动 flop 2 之前,通过了一个时钟二分频触发器 flop 1。这样的设计在时序检查中存在一个问题:定义在端口上的时钟信号 CLK 不会通过时序元件(即 flop 1)传播,也就无法将时钟及其时钟属性,比如不确定度(uncertainty),通过 flop 1 触发器,传递到 flop 2。因此,flop 2 将没有时钟约束。为了解决这个问题,我们需要在 flop 1 的输出端定义一个新的时钟。

实现这点的推荐做法是在 flop 1 实例的输出端创建一个生成时钟(Generated clock),这个生成时钟基于原始端口上的时钟 CLK 创建(CLK 也就成为了新时钟的主时钟 Master clock)。使用生成时钟约束的好处是可以在生成时钟及其主时钟(Master clock)之间建立联系。

create_clock -period 2 [get_ports CLK]

set_clock_uncertainty -setup 0.25 [get_clocks CLK]

create_generated_clock -divide_by 2 -name -CLK_SLW -source [get_ports CLK] [get_pins div2flop/out]

set_clock_uncertainty -setup 0.4 [get_clocks CLK_SLW]

以上是我们约束两个时钟的语句,需要注意的是,生成时钟创建时加上的 divide_by 选项指的是对频率分频,而不是时钟周期。所以在本例中,我们将时钟二分频,也就是将时钟周期从 2ns 扩展成 4ns。然后,我们为新生成的时钟指定了一个名字 CLK_SLW,并指定其源头时钟为 CLK。最后,我们将新时钟创建在 flop 1 的输出管脚 div2flop/out 上。因为我们将新时钟的源时钟定义为 CLK,因此当源时钟周期发生变化时,生成时钟周期也会随之更新(二分频)。同时其他时钟约束,比如 uncertainty,也会被添加到生成时钟时,并且数值也会随源时钟变化而变化。

示例中,我们假设我们已经在 RTL 中例化了 flop 1,因此我们能把时钟创建在 flop 1 的 out 管脚上。但如果我们没有在 RTL 中例化 flop 1,而是通过如下的 Verilog 语句实现的二分频功能,这样该在何处创建时钟?

always@(posedge CLK) begin DIV_CLK <= ~DIV_CLK; end

此时,在创建约束时,我们不得而知待约束的实例名和管脚名。因此,对于 RTL 语句实现的 flop 添加约束时,我们可以借助 gtech(Generic technology) 所定义的实例名或者管脚名。一般,flop 的名字总是输出信号的名字加上 _reg 后缀。

本例中,flop 输出信号的名字时 DIV_CLK,因此对应的 flop 实例名会被成为 DIV_CLK_reg。gtech 中的输出管脚名字永远为 Q。因此,本例中我们需要将生成时钟定义到 DIV_CLK_reg/Q

create_generated_clock -divide_by 2 -name -CLK_SLW -source [get_ports CLK] [get_pins DIV_CLK_reg/Q]

在综合之后,这个 gtech 触发器会被库中的实际触发器单元取代,约束中的定义点也会随之更新为实际触发器的输出管脚。

Asynchronous Clocks // 异步时钟

image.png
Figure 2: Asynchronous clocks in a design //图2:设计中的异步时钟

image.png
Figure 3: Asynchronous clocks 图 3:异步时钟

图 2 的设计中,flop 1 被 500MHz 的 CLKB 驱动,flop 2 被 333.3MHz 的 CLKA 驱动,如图 3 所示,两个时钟产生自不同的晶振,它们是两个不同源的时钟,所以它们之间互为异步时钟。为了接收来自异步时钟域的数据,flop 2 的输入之前有一个双触发器组成的同步电路。

当我们分别为两个时钟通过 create_clock 命令创建时钟时,综合工具会默认认为两者是同步的。这意味着 flop 1 和 flop 2 之间的时序路径会使用最严的延迟来约束,这里的延迟是发送端 CLKA 上升沿和接收端 CLKB 上升沿之间的最小间隔 。但实际上两者是异步时钟,我们根本不需要在 CLKA 和 CLKB 之间进行任何时序检查。

我们可以通过以下命令将两个异步时钟域分开,从而不进行不必要的 CLKA-CLKB 时序检查

create_clock -period 3 [get_ports CLKA]

create_clock -period 2 [get_ports CLKB]

set_clock_groups -asynchronous -group CLKA -group CLKB

最后一行是真正将两个时钟域设置为异步的命令,对于上述这样一个异步设计,设计者必须在两个时钟域之间添加同步电路(比如双触发器同步电路,等等),以防止两个时钟域之间出现亚稳态(metastability)这一跨时钟域问题。在约束上,我们首先分别约束两个时钟域,使工具检查它们各自的同步路径,然后关闭两个异步时钟域之间的时序检查和优化,以防止综合器将努力浪费在这些非关键路径上。(优化努力浪费在异步路径上可能导致综合器忽略真正的关键路径的优化,因为那些异步路径的时序缺口往往会非常大)

注意:

Case – 1: 如果设计中存在多个时钟,只有一个时钟和其他时钟互为异步(CLKX),那么使用下述约束

set_clock_groups -asynchronous -group CLKX

这条命令也表示除此之外其他时钟之间为同步关系。

Case – 2: 如果设计中有五个时钟 (CLKA, CLKB, CLKC, CLKD & CLKE) ,CLKA 和 CLKB 之间互为同步时钟,但是和其他时钟互为异步时钟,那么使用下述约束

set_clock_groups -asynchronous -group {CLKA CLKB} 

同样地,这条约束表示 CLKC, CLKD & CLKE 之间互为同步时钟。(CLKA 和 CLK 互为同步,但和 CLKC CLKD CLKE 之间为异步时钟关系)

原文

Generated Clocks

image.png
Figure 1: Generated clock in a design

Consider the example shown in Figure 1, the clock goes through a divide-by-2 flip-flop (or flop-1) before driving another flip-flop (or flop-2). The problem is the clock definition on the clock port along with other definitions related to clock, like uncertainty, don’t propagate through the sequential logic; in this case don’t propagate to the output of divide-by-2 flip-flop (or flop-1). Therefore, for flop-2 to be constrained by a clock, a new clock definition needs to be applied at the output of flop-1’s instance.

The recommended way of doing this is to create a generated clock at the output of flop1’s instance, along with the clock definition on the clock port. The benefit of a generated clock is that it can establish a relationship between it and its master clock.

create_clock -period 2 [get_ports CLK]

set_clock_uncertainty -setup 0.25 [get_clocks CLK]

create_generated_clock -divide_by 2 -name -CLK_SLW -source [get_ports CLK] [get_pins div2flop/out]

set_clock_uncertainty -setup 0.4 [get_clocks CLK_SLW]

Notice that the divide_by option is applied to the frequency, not the time period, so actually we are doubling the time period of 2ns and making it 4ns in this example. We are then giving the generated clock a name, CLK_SLW and we specify the source as the port called CLK. Finally, we apply the generated clock on a pin called div2flop/out. Since we specify the source clock as the port CLK, if the source clock period changes, the generated clock period will automatically be updated as well. And then we can apply other constraints like, uncertainty to clock CLK_SLW as well.

In this example it was assumed that flop-1 was instantiated in our RTL code, therefore we knew the name of the flop-1’s instance and the name of the output pin ‘out’.

But if the flop is not instantiated in the RTL but coded in the RTL using the Verilog construct –

always@(posedge CLK) begin DIV_CLK <= ~DIV_CLK; end

then we don’t know what instance & pin name to use for constraining. Therefore, with RTL coding registers, we need to apply constraints to the flop using the gtech (generic technology) cell or pin name. By definition, the cell name of the flop will always be its output signal name followed by _reg.

In our example, the output signal name is called DIV_CLK, so the cell name of the flop will be called DIV_CELL_reg. The gtech output pin of the flop will always be called Q, so in the example below we apply the generated clock to the pin called DIV_CLK_reg/Q –

create_generated_clock -divide_by 2 -name -CLK_SLW -source [get_ports CLK] [get_pins DIV_CLK_reg/Q]

After synthesis, when this generic register is replaced with an actual register from library, the constraint will automatically be updated with the actual pin from the library cell.

Asynchronous Clocks

image.png
Figure 2: Asynchronous clocks in a design

image.png
Figure 3: Asynchronous clocks

Consider the example shown in Figure 2, the flop-1 is clocked by CLKB, 500 MHz clock and the flop-2 is clocked by CLKA, a 333.3 MHz clock. But as shown in Figure 3, CLKA and CLKB are derived from different crystal oscillators; since these two clocks come from different sources, they are asynchronous to each other. To handle the clock domain crossing data, there is a double synchronizer at the input of flop-2. When we constrain our design using two create_clock commands for CLKA and CLKB, the synthesis tool by default considers the two clocks as synchronous. This means the timing path between flop-1 and flop-2 will be constrained by the worst-case timing between the launching clock CLKA and the capturing clock CLKB within the base period of two clock periods. However, since these two clocks are asynchronous, we don’t want any timing constraints applied to the CLKA and CLKB interfaces.

We can disable the timing between asynchronous clock domains by defining the clock groups as asynchronous as shown below –

create_clock -period 3 [get_ports CLKA]

create_clock -period 2 [get_ports CLKB]

set_clock_groups -asynchronous -group CLKA -group CLKB

The bottom line is, if we have a design with asynchronous clocks, then it is our responsibility to design the logic in order to prevent metastability at the interfaces (using double synchronizer, etc). We next need to create clocks to constrain the paths within each clock domain for synchronous timing and then finally we need to disable timing optimization along the paths between the asynchronous clock domains to prevent synthesis tool from wasting run time on non-critical timing paths (optimizing timing across these non-critical paths may lead to ignorance of optimization of actual timing critical paths by the synthesis tool).

NOTE:

Case – 1: If we have a design with multiple clocks, and there is a clock (named CLKX) which is asynchronous to all other clocks, then we can constrain the same using –

set_clock_groups -asynchronous -group CLKX

Also, this implies all other clocks are synchronous to each other

Case – 2: If we have five clocks in our design (CLKA, CLKB, CLKC, CLKD & CLKE) and CLKA & CLKB are synchronous to each other but asynchronous to all other clocks, then we can constrain the same using –

set_clock_groups -asynchronous -group {CLKA CLKB}

Also, this implies CLKC, CLKD & CLKE are synchronous to each other

原文:知乎
作者:LogicJitterGibbs

相关文章推荐

更多FPGA干货请关注FPGA的逻辑技术专栏。欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。
推荐阅读
关注数
10576
内容数
550
FPGA Logic 二三事
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息