这一篇在干嘛?

功耗是三大物理特性之三。与同等功能的 ASIC 相比,FPGA 是”电老虎”,不适合超低功耗场景(厂商虽然有低功耗 CPLD,但规模和能力都有限)。本章从 CMOS 动态功耗的基本公式出发,讲清降功耗的两大抓手——时钟控制(别乱门控!)和输入控制(别让输入悬空!),外加核电压、双边沿触发器和端接电阻几个补充手段。

背景:动态功耗公式——一切的出发点

CMOS 技术中,动态功耗来自对门和金属走线上寄生电容的反复充放电。电容电流的基本公式:

其中 I 是总电流,V 是电压,C 是电容,f 是频率。要降电流,三个参数砍一个就行:

  • V:FPGA 设计里电压通常是固定的(3.3 节讨论特殊情况);
  • C:正比于任一时刻正在翻转的门数量和互连走线长度;
  • f:正比于时钟频率和数据翻转率。

所有降功耗手法,最终都是在削 C 或 f 这两项。

3.1 时钟控制(Clock Control)

同步数字电路里最有效、最常用的降动态功耗手法:在数据流中暂时不工作的区域,动态地关掉时钟。因为 FPGA 的大部分动态功耗直接和系统时钟翻转相关,让闲置区域停止翻转是最直接的省电方式。

推荐做法只有两种:

  1. 触发器的时钟使能引脚(clock enable)
  2. 全局时钟多路器(Xilinx 器件上是 BUFGMUX 元件)。

如果手头的器件这两样都没有,有些设计师会退而求其次去直接门控系统时钟——注意,FPGA 设计中不推荐这么做,下面几节专门讲它踩的坑。

核心结论

有时钟使能引脚或全局时钟 mux 就用它们,别用逻辑门直接门控时钟。

图:简单门控时钟——糟糕的设计实践,虚线框内电路仅在 Clock Enable=1 时活动

先看图 3.1 的反面教材:Main Clock 一旦活动,所有触发器和组合逻辑都在翻转;虚线框内的逻辑本意是只在 Clock Enable=1 时工作——设计师想按逻辑量(电容 C)和平均翻转率(频率 f)成比例地省电。想法正确,手段埋雷:

门控时钟为什么麻烦? 一旦你对时钟做了哪怕最简单的门控,那条驱动时钟引脚的新网络就被视为一个新的时钟域,它需要像源时钟一样有低偏斜(low-skew)路径连到域内所有触发器。ASIC 设计师可以定制时钟树解决;FPGA 设计师就没这么自由了——FPGA 的低偏斜时钟线数量有限、布局固定,根本没法给门控出来的时钟专门铺一张时钟树。而时钟规划在 FPGA 里是”神圣”的:EDA 工具的整个流程(综合、布局、静态时序分析)都以系统时钟为核心,时钟结构必须在设计前期就定好,越晚改越痛苦。

核心结论

门控时钟会引入新的时钟域,给 FPGA 设计师制造实现和时序分析上的困难。

3.1.1 时钟偏斜(Clock Skew)

理解门控时钟的危害,先要复习时钟偏斜(clock skew)——同一时钟沿到达不同触发器的时间差。这是时序逻辑设计中极其重要的概念。

图:时钟偏斜——第二、三级触发器之间时钟线延迟 dC

看图 3.2 的三级触发器链:

  • 第一级→第二级:假设时钟传播延迟为零。如果组合逻辑有正延迟,时序裕量由”时钟周期 vs(组合延迟 + 布线延迟 + 建立时间)“决定——这是常规时序分析。信号在每个时钟沿最多穿越一组触发器。
  • 第二级→第三级:情况不同了。时钟线上有延迟 dC,第三个触发器看到的有效时钟沿比第二个晚了 dC

如果穿过逻辑的延迟 dL 小于时钟线延迟 dC,就可能出大事:第二个触发器输出的信号在时钟有效沿到达之前就穿过了逻辑到达第三级,等时钟沿一来,同一个信号又被第三级放行——一个信号在同一个时钟沿连穿了两级触发器(“fly-through”)!这种场景会导致电路灾难性失效。

更可怕的是:时钟偏斜问题与时钟频率无关。无论你跑 10 MHz 还是 500 MHz,fly-through 都会一模一样地发生——降频救不了偏斜。

核心结论

时钟偏斜处理不当会造成 FPGA 的灾难性失效,而且降频无效。

3.1.2 偏斜的管理

FPGA 的全局低偏斜资源能保证时钟到达所有时钟引脚的时间差在皮秒量级。但如图 3.3,一旦往时钟网络里插了一个门(AND 门做门控),时钟线就必须离开低偏斜全局资源,绕道门控逻辑再回来——门延迟 dG 加上布线延迟完全可能大于数据路径逻辑延迟 dL,上一节的 fly-through 隐患就复活了。此时必须给工具一组精确的约束,把门控引入的偏斜问题消除并在实现后分析中正确验证。

图:门控给时钟引入偏斜——糟糕的设计实践

看一个用门控时钟的具体模块:

// Poor design practice
module clockgating(
    output dataout,
    input clk, datain,
    input clockgate1);
    reg ff0, ff1, ff2;
    wire clk1;
 
    // clocks are disabled when gate is low
    assign clk1 = clk & clockgate1;
    assign dataout = ff2;
 
    always @(posedge clk)
    ff0 <= datain;
 
    always @(posedge clk)
    ff1 <= ff0;
 
    always @(posedge clk1)
    ff2 <= ff1;
endmodule

点评(结构见图 3.4):

  • assign clk1 = clk & clockgate1; 就是门控——数据路径上没有逻辑,时钟路径上却有逻辑
  • ff0→ff1 之间数据路径零延迟,而 ff1→ff2 的时钟被门拖慢了近 2 ns,数据 1 ns 内就到——数据比时钟早到约 1 ns,保持时间(hold time)违例

图:时钟偏斜成为主导延迟——数据比时钟先到

不同工具的处理方式不同:Synplify 这类工具默认会直接把门控移除,生成纯同步设计;另一些工具在时钟不加约束时会无视偏斜问题,正确约束后才会补上人工延迟。还有一点背景知识:与 ASIC 不同,FPGA 因为逻辑块和布线资源自带延迟,保持时间违例本来很罕见——而时钟线上过大的延迟恰恰是能打破这个保护的少数情形之一。加时钟约束有时能修,实现后分析里也可能(取决于工艺)看到工具往数据路径上加了人工布线延迟来救保持时间——能不能救、救得好不好,都不保证。

核心结论

门控时钟会引起保持时间违例,工具能不能修复要打问号——永远优先用厂商的时钟使能资源。

3.2 输入控制(Input Control)

一个常被忽视的降功耗角度:输入信号的压摆率(slew rate,边沿的陡峭程度)。CMOS 输入缓冲器在高侧、低侧晶体管同时导通时会抽取过大的电流。

要理解这一点,需要 CMOS 晶体管的一阶模型(图 3.5 给出了 Ids 对 Vds 的曲线),三个工作区:

工作区条件
截止区(Cutoff)V_gs < V_th
线性区(电阻区)0 < V_ds < V_gs − V_th
饱和区(Saturation)0 < V_gs − V_th < V_ds

其中 V_gs 是栅源电压,V_th 是阈值电压,V_ds 是漏源电压。

图:CMOS 晶体管的简化 I/V 曲线

理想开关是什么样?门输入从截止区瞬间切到线性区,互补管在同一瞬间反方向切换——任何时刻两只管子(NMOS 和 PMOS,即 N 沟道/P 沟道 MOSFET)至少有一只处于截止,电源到地之间就没有导通路径,没有直通电流。

真实系统里必须考虑过渡过程。以反相器输入从 0 V 升到 VDD 为例:

  1. 输入一过阈值 V_th,NMOS 离开截止区进入饱和区
  2. 此时 PMOS 还在线性区——VDD 到地之间开始直通电流
  3. 输入继续升高、输出下降,NMOS 漏极电压低于栅压阈值后进入线性区,PMOS 依次退到饱和、截止,电流消失。

结论一目了然:直通电流存在于两只管子同时导通的过渡期内。要把输入器件的功耗降到最低,就要压缩过渡期时间

核心结论

最小化驱动输入信号的上升/下降时间(让边沿尽量陡),可以最小化输入器件的功耗。

从上面的模型还能推出第二个结论:如果驱动信号在稳态(门不切换时)电平距离 0 或 V_dd 还差一个阈值电压以上,原本截止的管子会进入饱和区,持续漏一小股电流。这在”小信号摆幅驱动高电压域输入”的系统里尤其成问题。

悬空输入(floating input)是比欠驱动更糟的极端情形:悬空本质上是欠驱动,但你还不知道它”欠”到什么程度——它可能恰好停在一个亚稳态点,两只管子都泡在饱和区,功耗表现将是灾难性的;而且这种问题不可复现,调试时时有时无。好在大多数 FPGA 都为未用输入提供了电阻端接选项,所以:

核心结论

永远给未使用的输入缓冲器定义一个确定的逻辑状态(端接),绝不让 FPGA 输入悬空。

3.3 降低供电电压(Reducing the Voltage Supply)

降供电电压通常不是首选,但效果太惊人,值得单独一提:电阻上的功耗随电压的平方下降。把 FPGA 的核电压降到规格允许的最小值附近,能拿到可观的省电收益。

但代价是性能:电压降低,电路速度也会下降。如果走这条路,务必让时序分析按供电轨道的最低可能电压做最坏情况(worst-case)时序校验。另外 FPGA 核电压的规格本身允许 ±5%~10% 的偏差,系统设计时要格外小心。

核心结论

动态功耗随核电压的平方下降,但降压会拖累性能——通常用其他手法省电、把核电压保持在规格区间内更稳妥。

3.4 双边沿触发器(Dual-Edge Triggered Flip-Flops)

动态功耗正比于信号翻转频率,那么对高扇出(fan-out,一个信号驱动的负载数)网络就应该让每一次翻转都干最多的活。扇出最高的网络几乎总是系统时钟——任何降低时钟频率的手段都能显著省电。

双边沿触发器在时钟的上升沿和下降沿都传数据,于是达到同样功能/性能所需的时钟频率可以减半,时钟网络上的动态功耗直接砍半。

编码上非常简单,下面是一个移位寄存器的例子:

module dualedge(
    output reg dataout,
    input clk, datain);
    reg ff0, ff1;
 
always @(posedge clk)
    ff0 <= datain;
 
always @(posedge clk or negedge clk) begin
    ff1 <= ff0;
    dataout <= ff1;
    end
 
endmodule

点评

  • 输入 datain 仍由上升沿捕获(ff0 是普通单边沿触发器),然后才送入双边沿级;
  • always @(posedge clk or negedge clk) 就是双边沿逻辑——两个沿都触发赋值;
  • 风险提示:如果目标器件没有双边沿触发器原语,综合器会用冗余触发器加门控去”模拟”,这完全可能抵消双边沿策略的省电初衷。好的综合工具至少会报警告。实现之后一定要回头分析资源报告。

核心结论

只有当器件以原语(primitive)形式提供双边沿触发器时才使用它。

一个工程实例:Xilinx CoolRunner-II 家族的 CoolClock 特性——先把外部时钟二分频,再把触发器切换成双边沿器件。从外部看行为与单边沿系统完全一致,但全局时钟线上的动态功耗只剩一半。

3.5 修改端接(Modifying Terminations)

输出引脚接电阻性负载的场景很常见:总线信号、开漏输出、需要端接的传输线。这些情况下 FPGA 输出驱动器的 CMOS 管都要持续地灌入或吸收电流。几条实用准则:

  • 上拉电阻:按可接受的最小上升时间来定值,让电阻尽量大(电阻越小静态电流越大);
  • 总线竞争:如果同时有高侧和低侧驱动器,确保任何条件下都不发生总线竞争(bus contention)——哪怕每次只抢几个纳秒,也会抽取大电流;
  • 并联端接改串联端接:负载端并联端接(shunt termination)的传输线,如果系统要求允许,可以改用串联端接(series termination)。如图 3.6 所示,串联端接没有稳态电流损耗——电流只在信号跳变时短暂流动。

图:端接类型对比——串联端接无稳态电流

串联端接的缺点:

  • 负载到端接电阻之间会先出现一次初始反射;
  • 跳变期间串联电阻带来少量衰减。

如果这些性能损失对系统可接受,串联端接就能消除端接电阻上的静态功耗

3.6 本章要点速查

  • 有时钟使能引脚或全局时钟 mux(BUFGMUX)就用它们,别直接门控时钟。
  • 门控时钟省电直接,但引入新时钟域,制造实现与时序分析困难。
  • 时钟偏斜处理不当会灾难性失效,且与时钟频率无关;门控还可能引起保持违例,工具未必能修。
  • 输入功耗:压缩输入信号的上升/下降时间;未用输入必须端接,绝不悬空。
  • 动态功耗随核电压平方下降,但降压影响性能,需按最低电压做最坏时序分析。
  • 双边沿触发器只在器件有原语时用(如 CoolRunner-II 的 CoolClock:时钟减半、功耗减半)。
  • 串联端接没有稳态电流损耗,条件允许时优先于并联端接。

常见坑

实战中最大的坑是”用 clk & enable 的写法偷懒做门控”——仿真结果完全正确,上板却出现偶发数据错乱。原因就是 3.1 节的组合:门控时钟形成新时钟域、产生偏斜,触发保持时间违例,而且降频也救不了(偏斜问题与频率无关),问题还可能不可复现。正确姿势:数据通路用触发器的 clock enable 引脚停翻,时钟树本身永远不动;如果确实需要结构性关断(如多域切换),用 BUFGMUX 这类专用时钟资源。

通关标准:

学完本篇你应该能做到:

  1. 用 I = V·C·f 分析任意一个降功耗手段到底在削哪个参数;
  2. 说清门控时钟的完整危害链:新时钟域 → 低偏斜资源不可用 → 偏斜 → 保持违例,并给出正确替代方案(clock enable / BUFGMUX);
  3. 解释为什么未用输入必须端接:悬空可能停在双管饱和的亚稳态点,功耗大增且不可复现;
  4. 判断何时能用双边沿触发器,以及工具模拟实现时的风险。