clock gate介绍
参考链接:
门控时钟的概念
info
门控时钟有两种方案:一种直接针对寄存器的时钟进行门控,一种对模块级别的时钟进行门控。相比之下,直接对寄存器的时钟进行门控更为灵活。因为在很多时候,我们不能保证刚好将不需要门控的寄存器与需要门控的寄存器分配在不同的模块。因此我们主要介绍寄存器级的门控时钟
下图是门控时钟的一个简单电路图:

上述电路图中,将控制信号(EN)直接与时钟信号(CLK)进行与操作,以完成门控。门控后的时钟信号GCLK送到寄存器阵列中。这样,当EN为0时,该时钟被关掉。相应的波形如下所示:

attention
可以看出,如果EN信号不加控制,会导致门控时钟信号出现毛刺。时钟上的信号出现毛刺是非常危险的。所以在进行门控时,为了使门控时钟不产生毛刺,使能信号必须满足条件:它是寄存器的输出,该寄存器的时钟信号与要门控的时钟信号是相同的。由于上述原因,虽然采用这种门控方式最直接,但在实际中很少采用。(这个条件过于严格,实际设计中很难保证所有 EN 信号都满足。所以纯 AND 门控虽然最简单,实际中很少直接用。)
为了解决这种问题,引入基于锁存器的门控时钟方案,如下图所示:

对应的时序图如下所示:

可以看到,这种方式消除了EN与CLK组合产生的毛刺对门控时钟的影响。该方法的原理在于:锁存器在CLK为低时透明。这样,EN 信号上的毛刺仅出现在CLK的低电平处,EN1与CLK进行与操作,可以将这部分毛刺消除掉。这样,GCLK上就没有毛刺了。
attention
不过需要注意的是,如果在电路中,锁存器与与门相隔很远,到达锁存器的时钟与到达与门的时钟有较大的延迟差别,则仍会出现毛刺,下面就来分析一下:

上述的右上图中,B点的时钟比A时钟迟到,并且Skew > delay,这种情况下,产生了毛刺。为了消除毛刺,要控制Clock Skew,使它满足Skew < Latch delay(也就是锁存器的clk-q的延时)。上述的右下图中,B点的时钟比A时钟早到,并且|Skew| > ENsetup - (D->Q),这种情况下,也产生了毛刺。为了消除毛刺,要控制Clock Skew,使它满足|Skew|< ENsetup - (D->Q)。
info
常见的是第一种毛刺,不过我们可以将这个逻辑做成一个单元,这样就基本上能消除上面的那两种毛刺了

通常情况下,时钟树由大量的缓冲器和反相器组成,时钟信号为设计中翻转率最高的信号,时钟树的功耗可能高达整个设计功耗30%。加入门控时钟电路后,由于减少了时钟树的开关行为,节省了开关功耗。同时,由于减少了时钟引脚的开关行为,寄存器的内部功耗也减少了。采用门控时钟,可以非常有效地降低设计的功耗,一般情况下能够节省20%~60%的功耗。
此外,由于门控时钟不需要用到MUX单元,加入门控时钟电路后,设计的面积也减少了。门控时钟电路的扇出越大,减低功耗和面积的效能越好。当然,扇出太大了,又会产生时序等的问题。
门控时钟电路非常容易实现,用工具自动插入门控时钟,不需要修改RTL代码,门控时钟与工艺无关。
补充1: 减少MUX单元面积
!!!attention
为什么使用时钟门控不需要使用到MUX单元,加入门控时钟电路之后,设计的面积也较少了?
主要从下面图来进行阐述,对于未加入门控电路,当寄存器不需要更新数据时,传统做法是在每个寄存器的 D 端加一个 MUX,每个寄存器都需要一个 MUX,N 个寄存器就需要 N 个 MUX。

对于有时钟门控的电路,1个 ICG 替代了 N 个 MUX,所以面积减少

综合库中的门控时钟模型
前面我们说了,门控时钟可以以三种方式实现:一个与门(即不带锁存的门控时钟)、分散的锁存器+与门、集成的锁存器+与门。在综合库中,与门、锁存器是基本逻辑单元,因此可以构成门控时钟。此外,综合库中还专门提供了集成的门控单元。一般情况下,我们使用的是集成的门控单元,因为这个门控单元是对Skew作了控制,不存在前面描述的毛刺问题。
一个示例的综合库中的时钟门控单元描述如下所示:该综合库模型中,E为门控信号;CK为时钟信号;ENL是锁存器输出;ECK为对输出门控后的时钟信号;statetable描述了该门控单元中内部锁存器的功能。
1 | cell (TLATNCAX12) { |
门控时钟实现
rtl代码风格
我们要实现门控时钟,首先就得从RTL代码进行设置。在RTL代码中将需要门控的寄存器写成“载入-使能”形式,如下所示:
1 | always @(posedge clk or negedge rstn) begin |
上述代码中,如果EN有效,则寄存器在时钟上升沿采样数据,否则保持原值,一般情况下,综合会得到的对比电路如下所示。

上图的典型综合结果中(即不使用门控时钟的情况),在每个受EN使能控制的寄存器之前加入了一个MUX,当EN信号有效时,寄存器锁存输入信号D;否则保持原值。这种方法也能减少寄存器上的翻转,因而节省翻转功耗。然而,这种“载入一使能”结构中,每个寄存器都有一个MUX,假设MUX面积为4,则8位寄存器需要增加的面积为32。面积越大,意味着芯片成本越高,而且整体的功耗也会增加。另外,这种方式不能消除时钟树上的功耗。
对于右下角的门控时钟形式的综合电路,假设一个门控逻辑的面积为10,一个门控时钟信号可以驱动8位寄存器,则在门控时钟电路中,对每8个寄存器需增加一个门控逻辑,增加的面积为10。由此可以看到,门控时钟的电路比普通综合结果的面积更小、功耗更低。
dc相关
鉴于门控时钟的优点,我们需要把普通的综合结果“转换”为门控时钟的结果,我们主要是通过DC的power compiler来自动实现的。我们主要通过命令来设置门控时钟的风格和通过命令“启动”插入门控时钟。综合工具根据我们所设置的时钟门控的风格,插入相应的门控逻辑。因此,门控时钟的实现主要有两步,一步是设置门控时钟的风格,通过命令set_clock_gating_stale及其选项来实现;另一步就是在网表中加入门控时钟,通过命令insert_clock_gating来实现。下面我们就来介绍一下这两个设置,由于命令在不同版本的DC中有所不同,命令的具体选项就可能不一样,这里就只介绍一些常用或者说是可能用到的选项
在执行insert_clock_gating命令前,我们一般先使用set_clock_gating_style命令来指定要插入门控时钟电路的结构(或者说是插入门控时钟的风格)。下面我们就来介绍一下使用这个set_clock_gating_style命令可以进行插入哪些门控时钟电路结构。
set_clock_gating_style
介绍下面这些option
-
-sequential_cell:选项设置是否基于锁存器风格。因为我们的时钟门控有三种形式(不使用锁存器与门,基于锁存器+离散与门,集成锁存器+与门),因此就要指定一种形式,一般推荐集成门控这种方式-sequential_cell latch:基于锁存器的离散门控单元是默认值-sequential_cell none:不使用锁存器的门控单元- 使用集成的门控单元则不需要使用这个-sequential_cell来设置了,因为-sequential_cell 选项设置是否采用基于锁存器的风格。使用集成的门控单元直接设置参数就可以了,例如可以通过下面的命令来设置使用集成的门控单元:
set_clock_gating_style "integrated"
-
-positive_edg_logic:(简写为-positive或-pos)设置在RTL代码中用上升沿锁存的寄存器(也就是上升沿沿触发的寄存器)采用何种门控逻辑 -
-negative_edg_logic:(简写为-negative或-neg)设置在RTL代码中用下降沿锁存的寄存器(也就是下降沿触发的寄存器)采用何种门控逻辑
info
例如设置了不使用锁存器的风格,然后对于上升沿触发的寄存器,其门控单元使用或门逻辑构成
set_clock_gating_style -sequential_cell none -pos "or"
在RTL代码中用下降沿锁存的寄存器(也就是下降沿触发的寄存器)使用集成门控时钟单元
set_clock_gating_style -neg "integrated" -control_point before
设置RTL代码中,无论你的寄存器是上升沿触发还是下降沿触发,控制该寄存器的时钟单元都是使用集成门控时钟单元
set_clock_gating_style -positive "integrated" -negative "integrated" -control_point before
-minimum_bitwidth:设置进行时钟门控的寄存器阵列最小宽度。对于宽度小于该设置的寄存器阵列,不进行时钟门控;然而当电路有公共使能时,会对电路进行分解进行集体门控,如下所示
1 | set_clock_gating_style -minimum_bitwidth 4 |

attention
上述命令意味着一个时钟门控至少要触发4个寄存器,左图每组只有三个寄存器,不能满足每组至少4个寄存器的要求。因此,对于每个组的寄存器,不能用时钟门控。然而,所有的3个寄存器组,都有1个公共的使能信号”a”,我们可以把它分解出来作为控制时钟的门控信号。这样一来,信号“a”控制9个寄存器,它满足最少要触发4个寄存器的要求。因此将上面的命令约束上面左边的电路时,综合得到结果就会成为右边有门控时钟的电路。
-num_stages:选项用于设置一个多级门控的级数。在有些设计中,顶层的门控信号会分解成不同的子门控信号。在缺省情况下,仅对跟寄存器阵列相连的门控制信号生成门控逻辑。例如对于下面的电路图:

在这个例子中,全局门控信号EN分别跟a,b,c信号组合,然后驱动不同的寄存器阵列。缺省情形下(set_clock_gating_style命令的默认设置为“num_stages”等于“1",缺省时也为1),跟寄存器阵列相连的门控信号由门控单元给出。
由于所有的3个寄存器组都有1个公共使能“a",它可以被分解出来产生1个额外(级)的门控时钟单元。在set_clock_gating_style命令加选项-num_stages 2,就可以产生下图所示的两级门控时钟:

使用多级门控时钟,时钟综合器可以尽量地摆放门控时钟单元,使它靠近时钟源,从而最大限度地降低时钟树的功耗。
report_clock_gating -style ;# 显示当前 style 配置
-control_point与-control_signal:选项跟DFT有关,用于设置该门控单元在DFT时是否可控,DFT控制信号是scan-enable还是test-mode,以及DFT控制信号与EN信号的组合逻辑是放在门逻辑中的锁存器之前还是之后。通常,将DFT控制信号与EN信号进行或操作,这样在DFT时,可以控制该门控逻辑。例如下面的命令约束:
1 | set_clock_gating_style -control_point before -control_signal test_mode |
设置得到下面的电路结构:

上图给出了在门控逻辑中插入控制点的示例。在这个例子中,DFT控制信号为test_mode,控制点位于锁存器之前,如果设置为after,那么插在锁存器之后
-observation_point:选项跟DFT有关,用于设置是否要插入观测逻辑,以便在DFT时能看到门控逻辑内部的信号
1 | set_clock_gating_style -observation_point true |

info
除了上述选项外,该命令还有一些其他的选项设置,比如-setup选项设置建立时间约束。-hold选项设置保持时间约束。-observation_logic_depth选项用于设置观察电路中异或门的数目。-max_fanout选项设置一个门控单元所驱动的最大负载数目,定义CG单元最大扇出的一个目的是减少CG后面的时钟延迟,门控时钟单元的扇出越大,它到达寄存器的延迟越长;此外,还有用来约束重新平衡(后面会有对重新平衡进行介绍)。"set_clock_gating_style"命令有很多选项,我们可以在Power Compiler用"man set_clock_gating_style"命令来查看其详细的使用方法。
1 | set_clock_gating_style \ |
insert_clock_gating
info
insert_clock_gating 是 Power Compiler 中专门用于在已综合的网表上自动识别可门控的寄存器组、并插入 ICG(Integrated Clock Gating)单元的命令。它是动态功耗优化最常用的手段之一,可以显著降低寄存器翻转带来的时钟树和数据路径功耗
对于没有加-global选项,得到的电路如下

上述电路中,有两个模块都有门控时钟,都是同一个控制信号。那么我们就可以使用insert_clock_gating -global选项,让门控时钟可以穿越层次结构,插入到设计中。这样一来,既可以省门控时钟,又可以省面积。使用该选项后,综合得到的带门控时钟的电路如下所示

attention
因此使用insert_clock_gating加选项“-global",可以使门控时钟穿越层次结构。如果不用选项“-global",在每个模块里有一个门控时钟单元。
实现门控时钟的方法就如前面所示,主要是设置门控时钟的风格和加入门控时钟这两个命令以及他们的一些选项。
门控时钟的处理
我们在门级网表中加入门控时钟之后,有时候需要对门控时钟进行修修改改,比如说删除一些门控时钟之类的。下面我们就来介绍一下常见的一些门控时钟处理
重新连接门控时钟

上面的左边图中,寄存器A由CG1触发(也就是原来由上面的门控单元CG1进行控制)。由于寄存器A距离门控时钟单元CG2更接近,我们更想让寄存器A与门控单元CG2进行连接来减少连线的长度,因此我们需要进行重新连接。重新连接后,寄存器A由CG2触发,如上面右边的图所示。上面重新连接所使用的命令如下所示:
1 | rewire_clock_gating -gating_cell CG2 -gated_objects {reg_A} |
此外,我们可以使用rewire_clock_gating的-proximity选项,使用这个选项后,Power Compiler会自动重新连接寄存器,使时钟门控单元CG到寄存器的连线最短:
1 | rewire_clock_gating -proximity |
重新平衡门控时钟的扇出

左图是原来的设计。当我们对电路进行优化时(比如使用compiler_utral -retiming 或者optimize_registers命令),设计中的寄存器可能被移动或删除,如中图所示。
寄存器优化后,门控时钟的扇出不平衡。而门控时钟有最小和最大扇出的约束,对于每一个单独的CG单元(如中图所示)最小扇出的条件不能满足。Power Compiler就需要相关的命令重新平衡门控时钟的扇出,使用的命令如下所示:
1 | rewire_clock_gating -balance_fanout |
使用上述命令后,Power Compiler将CG单元合并,以满足最小/最大扇出的约束。重新平衡后的设计如右图所示。
合并门控时钟
1 | merge_clock_gating_cells |
如果两个或以上的门控时钟单元的输人逻辑相等,它们可以被合并。合并只能在一个层次内部进行。合并后,冗余的逻辑被删除。如下图所示:

删除门控时钟
有时候,我们需要删除某些门控时钟,这个时候我可以使用remove_clock_gating命令。该命令即一些选项如下所示:
1 | remove_clock_gating \ |

- -gated_registers这个选项,将原来的门控单元删除,换成“使能-载入”模式
- -gating_cells这个选项,原来的一个门控时钟删除
因此我们可以通过指定门控时钟单元或通过指定寄存器删除门控时钟
- 如果在使用删除门控时钟命令时用了开关选项“-all",当前设计中的所有门控时钟都会被删除
手动插入门控时钟
1 | assign Gated_Clock = Clock & Enable ; |
attention
对于手工门控时钟,Power Compiler将不插入时钟门控单元,也不能对它进行操作(比如重新平衡之类的)
