本文作者:AMD 工程师 Alan Schuler
传统上,使用门控时钟是 ASIC 设计中降低系统功耗的常见方法。通过门控时钟,可在非必要时阻止整组寄存器的状态转换。
图 1:使用与门进行时钟门控
在图 1 中,当“gate”信号设为低电平时,所有寄存器均关闭且不消耗动态功耗。
此类编码风格并非总能有效适配 FPGA。原因在于 FPGA 具有先进的专用时钟资源,其设计旨在将时钟结构的时序设为最佳设置以避免时钟偏差。在该结构中插入门电路可能干扰这些资源。此外,这些时钟资源并非无限,因此不同门控时钟的数量过多可能导致 FPGA 设计出现问题。
图 2:时钟结构内的 LUT
解决这些问题的方法之一是重写 RTL 代码以移除门电路。但这涉及大量工作,且在 FPGA 中进行原型设计时,大多数情况下不允许更改 RTL 代码。另一种解决方案是让综合工具转换这些门电路,使时钟直接驱动寄存器时钟管脚,而门控逻辑则转至时钟使能管脚。AMD Vivado™ Design Tool 支持此功能。
图 3:相同电路完成门控时钟转换后的结果
有必要提醒设计者,执行此项转换虽有助于工具利用专用时钟资源,但现在也会改用不同的时钟使能信号。这意味着设计中将包含更多控制集,从而可能引发其他影响。
此外,仿真结果也可能受到影响。以图 2 和图 3 为例。在此示例中,时钟和门控信号均为低电平,随后门控信号在时钟保持低电平期间产生高低脉冲。在图 3 中这计为一次时钟脉冲,但在图 4 中则忽略此次脉冲。 应谨慎处理,避免此类情况。
控制门控时钟
门控时钟转换的控制是通过以下三项组合来完成的。XDC 文件中的时钟约束、GATED_CLOCK 综合属性,以及 gated_clock_conversion 综合设置。XDC 文件中的时钟约束会将设计中时钟的运行频率需求告知工具。 其形式如下:
create_clock -period 5 [get_ports clk]
通过使用约束,该工具即可识别哪些信号可以转换为直接时钟。
GATED_CLOCK 属性允许用户直接告诉工具,门控逻辑中的哪个时钟应驱动寄存器的时钟输入。 该属性会被写于 RTL 文件内。
(* gated_clock = "yes" *) input clk;
gated_clock_conversion 选项用于对综合执行门控时钟转换的方式加以控制。若设为“off”,则永不转换门控时钟。若设为“on”,那么它将在具有 GATED_CLOCK 属性的信号上执行门控时钟转换。
若设为“auto”,那么当该工具通过 XDC 文件识别出哪些信号是设计中的真实时钟时,它将执行转换。此外,若有多个可转换的时钟,则可使用 GATED_CLOCK 属性将应使用的特定时钟告知工具。
当该工具能检测到门控时钟并开启转换功能时,它会尝试将该时钟与门电路中的逻辑其余部分分离。若能完成此操作,那么该时钟将直接驱动寄存器的 C 管脚,其余部分将被分配给寄存器的时钟使能逻辑。
执行门控时钟转换时需考虑的重点之一是层级。转换门控时钟时,该工具会将时钟与逻辑其余部分分离,并创建新时钟和时钟使能。若门控时钟与新时钟驱动的寄存器在相同层级内处于不同层次,且存在保持整个层级静态的约束(如 DONT_TOUCH、KEEP_HIERARCHY 等),工具将无法转换时钟。
图 4:层级内不同层次的时钟门控电路
基础门电路
最常见的门控时钟形式之一是通过基础门电路(例如,与门)实现的时钟门控。
RTL 代码示例:
assign my_clk = clk1 & gate1 & gate2;
此代码通过两个不同使能信号对时钟进行门控,细化视图如下:
图 5:含与门的时钟门控
综合时,如果开启了门控时钟转换,并将 gated_clock_conversion 设置为 auto(自动),clk1 占一个时钟周期,或在 clk1 上将 GATED_CLOCK 属性置位,那么该工具将把 clk1 信号连接到寄存器的 C 输入,并把 gate1 和 gate2 信号连接到触发器的 CE 输入。
图 6:前一电路的综合后结果
或门转换同样适用。
图 7:在时钟电路中使用或门
上述电路转换后如下所示:
图8:或门转换结果
Vivado 综合工具还可转换比与门及或门更复杂的门电路。
寄存的门电路
Vivado 还可转换已寄存的门电路。 例如,以下编码风格将创建一个寄存器,供另一个寄存器用作时钟:
若首个 clk 信号有适当约束,那么该工具亦可转换此类门电路。 例如:
create_clock -period 5 [get_ports clk]
图 9:用作时钟的寄存器的细化视图
转换后如下所示:
图 10:寄存的门电
时钟分频器(1 位)
Vivado 还可处理更复杂的门电路,例如,时钟分频器。
此时钟的代码如下所示:
该模块会将输入时钟“clk_in”分频,得到一个新时钟“clk_out_div_2”,速度减半。
这两个时钟均被指定为模块输出。设计其余部分会使用这两个时钟来驱动设计中的时序元件。
图 11:时钟分频器
由于此类时钟频率不同,因此需使用生成时钟约束。
这些约束会基于输入 clk_in 创建另一个名为 clk_in 的时钟,其周期为 2.5 ns。
随后,它会创建另一个新时钟,其频率为 clk_in 一半,其时钟源为 div_2_reg 触发器的 Q 管脚。
若不转换时钟而直接综合并检查时序,会发现由 div_2_reg 时钟驱动的寄存器路径的周期均为 5 ns。
命令示例:
report_timing -name timing -to out1_2_reg/D
该工具将返回:
图 12:无时钟门控的 2 分频时钟的时序报告
若以时钟门控来运行相同的设计,会引发问题。
新网表如下所示:
图 13:时钟分频器上的门控时钟转换
如您所见,所有寄存器现在均由原始时钟驱动,但若在新寄存器上执行 report_timing,那么其周期会从 5 ns 变为 2.5 ns。原因在于 div_2_reg/Q 的时钟路径不再驱动寄存器时钟管脚,导致生成时钟命令不再影响时序分析。
为修复此问题,Vivado 综合工具为您提供了锚点以创建新的生成时钟约束。 在上图中,请注意时钟线产生分叉,并穿过一个新的层次,该层次只驱动完成时钟转换的寄存器。 此外,综合 log 日志文件将为您提供该锚点名称以及需置于 XDC 文件内的新命令,以确保输出的时序正确无误。
图 14:时钟分频器的日志文件
时钟分频器(多个位使用同一计数器)
除时钟分频器外,计数器也可用作时钟。 例如,一个 4 位计数器可生成 4 个不同时钟。 即,2 分频、4 分频、8 分频和 16 分频。
这些计数器可用于创建时钟,具体用法如下:
图 15:使用计数器作为时钟生成器
开启门控时钟转换后的运行结果如下:
图 16:含计数器的门控时钟转换
请注意,这样会为每个新时钟创建馈通锚点。
在 log 日志中也提供了相关报告以供后续运行使用。
图 17:计数器充当门控时钟的日志文件