ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

DCG下Multi-bit FF物理优化全解析:降低时钟功耗的实战指南

DCG下Multi-bit FF物理优化全解析:降低时钟功耗的实战指南 去年做一颗28nm视频编解码SoC的后端收敛时我们被功耗指标卡了整整两周。时钟树功耗差不多占了芯片动态功耗的25%DCT拓扑综合出来的网表一进入APR时序余量就开始全面恶化前端觉得是后端CTS没做好后端觉得是综合阶段完全没考虑物理信息。最后真正把DCT/DCG里的Multi-bit FF优化链路完整打通时钟网络功耗降了20%左右CTS阶段buffer用量也肉眼可见地少了一批。这篇文章不绕弯子直接讲DCG下Multi-bit FF物理优化的完整逻辑、具体做法以及我们在一套叫SPG的流程里反复踩过的坑。适合正在搭DCG综合flow、或者被时钟功耗和拥塞来回折腾的工程师参考。1. 为什么一个“合并触发器”的动作能省出整块时钟功耗Multi-bit FF这个名字听起来像是把几个触发器简单拼在一起但真正做物理优化的人都知道这一步动的其实是时钟网络这根大动脉。要理解它的价值得先从触发器是怎么在芯片里“偷电”的看起。1.1 触发器在时钟网络里到底是怎么“偷”电的动态功耗的公式大家都会背P C × V² × f。在芯片里时钟网络是全世界扇出最大、翻转频率最高、物理距离最长的网络。从时钟源出来要经过一级又一级的buffer最后到达每一个触发器的clock pin。这条链条上每一级反相器或buffer的输入电容加上每颗触发器clock pin的输入电容全部累加在一起构成了时钟树的总负载电容。触发器的内部并不是只有时钟pin这一个电容它通常还有一级内部反相器把外部进来的时钟翻转为互补时钟给锁存级用。这颗内部反相器的输入电容也全部反映在时钟树的负载上。也就是说一颗普通DFF在时钟网络上贡献的电容远不止你在Lib里看到那一个clock pin的电容值。如果一万颗触发器都这么接时钟树上的容性负载就是一个非常可观的数字。Multi-bit FF的思路就是让多颗触发器的内部时钟反相器共用。原来四颗触发器需要四套内部反相电路现在四bit的MBFF只需要一两套时钟pin数量减少内部充放电节点减少时钟树要驱动的总电容自然就降下来了。1.2 多bit单元来了之后内部结构发生了什么变化从单元内部结构看MBFF并不是把四个DFF并排放进同一个cell这么简单。以最常见的MB2、MB4单元为例它通常有一组共享的时钟输入引脚以及可能共享的异步复位/置位引脚数据端还是独立的D0、D1、D2、D3输出端也是独立的Q0、Q1、Q2、Q3。共享的是一些控制类引脚和内部时钟电路数据路径基本保持独立。这带来的第一个好处是标准单元数量变少。同样实现四个D触发器原来需要四个DFF cell现在只需要一个MB4 cell。单元数量减少意味着布局对象变少后端处理起来更干净面积也通常能缩小一些。第二个好处是时钟树的sink节点变少每个sink的电容更大但总数更少CTS阶段要处理的skew group更少时钟树深度可以压得更浅。但这种压缩是有条件的并不是任意四颗DFF都能无脑合并。工具能合并的触发器必须在时钟域、异步控制信号、扫描链连接方式上都保持一致。举例来说如果四颗触发器里有两颗的复位信号是同一个另外两颗是另一个那就大概率没法合并成一颗MB4。扫描链如果有的在链上、有的不在也不能直接合并。所以你会发现网表里MBFF的出现位置往往天然就是那些“控制信号整齐”的寄存器阵列比如状态寄存器、配置寄存器、数据通路里的流水寄存器。1.3 这块“蛋糕”并不是白吃的面积、时序和可布线性的三角关系很多人一听MBFF能省功耗、省面积就想把整个设计全部打开这个开关。实际项目里这么干大概率会翻车。先看可布线性。MBFF单元通常比普通单元要宽有些库里4bit单元的高度是标准单元的两倍。布局阶段如果一行标准单元里塞进一个MB4剩下的空隙可能小到无法再放其他单元形成碎片化空隙。更麻烦的是一旦行里放不下工具会尝试把MBFF移到附近行进而带动一串cell的连锁legalize最终可能造成局部拥塞不降反升。再看时序。合并之后四个bit在版图上是有物理位置的它们可能分散在单元内部的不同区域。如果D端到Q端的路径和原来单bit单元一样短那没问题但如果某个bit的数据输入来自单元另一侧的寄存器数据路径可能被迫绕更长时序反而变差。最后还有dynamic IR drop。多bit单元内部几个bit同时翻转时瞬时电流明显大于单bit单元。特别是4bit或8bit的单元在低电源电压下很容易在电源轨上打出明显的局部压降。这也是为什么在很多项目里2bit和4bit单元混用、8bit单元被dont_use掉的原因。2. DCG里的Multi-bit FF优化从库的准备到果实的确认标题里的DCT/DCG本质上是Design Compiler在不同阶段的形态。DCT走的是拓扑模式在综合时用抽象布局信息来估算net长度和拥塞DCG则是把图形化物理环境和综合结合得更紧密。到了当前主流版本这套能力基本统一在DCG里但物理优化逻辑一脉相承。2.1 没有多bit库单元所有开关都是空谈这是最容易被忽略的前置条件。Multi-bit FF优化必须由标准单元库里真实存在的多bit触发器单元来承接。Foundry的标准单元库通常会有MB2、MB4甚至MB8系列比如mb2_dffq_xxxx、mb4_dffqn_xxxx这类命名。但如果你用的是内部定制库、IP周边单元或者某些老工艺库很可能库里根本没有多bit触发器。或者在.lib里虽然有cell但Power Model、时序弧、功能视图都只按单bit单元写工具识别不出来优化结果也是零。所以在启用任何开关之前我先用下面的方式确认库里的MBFF家底get_lib_cells */*mb* get_lib_cells */*mb*dff*能搜出来多少决定了后面可以做到什么程度。如果只有2bit单元那4bit合并就别想了如果完全没有就得回头跟库供应商要带多bit建模的版本或者自己去评估老库手工编辑.lib的风险——我建议不要手工改很容易在时序验证里埋雷。2.2 compile_ultra里的寄存器优化开关怎么开DCG里做Multi-bit FF的核心开关在compile_ultra的寄存器优化路径上。我最常用的配置是这样set_app_options -name compile.ultra.optimize_register -value true set_app_options -name compile.ultra.multi_bit_register_optimization -value true compile_ultra -optimize_register这里compile_ultra -optimize_register会让DC在综合阶段做寄存器优化包括合并、重组等操作。multi_bit_register_optimization进一步放开多bit合并的空间。需要提醒一点compile_ultra -optimize_register打开后工具不只是做多bit合并还可能做寄存器重定时、寄存器复制等其他优化。这些优化会改变寄存器拓扑后端做formal时如果准备不充分很容易在compare point上出现意外。所以有些团队会先只开multi_bit_register_optimization用更保守的选项尝试确认formal没问题后再逐步放开。2.3 怎么确认优化真的发生了而不是纸面数字综合跑完后不能只看report_qor里的面积数字变小就直接信。我一般会用两条命令交叉确认优化效果get_cells -hier -filter ref_name ~ *mb* report_register_optimization -verbose第一条命令可以统计网表里实际例化的MBFF单元数量。把数量记下来再对照RTL里原本的DFF总量就能估算出合并比例。第二条命令可以看到工具报告里的寄存器优化细节比如哪些register被merge成了一个多bit单元哪些因为条件不满足被保留。另外一个更“物理”的判断方式是直接导出APR前的时钟网络功耗估算。把MBFF优化前后的两个网表分别跑一遍同样的功耗check看clock_network那一栏的变化。我们当时的数据是优化前时钟网络功耗约占总功耗24.7%优化后降到19.8%而这个变化主要就是MBFF贡献的。2.4 控制合并粒度不是所有寄存器都适合被合进去DC往往倾向于把能合并的寄存器尽量合并但物理工程师得学会给这个“热情”踩刹车。我常用的做法是把设计里几个最关心的关键路径模块的寄存器设置为不可合并区域set_dont_touch [get_cells ctrl_top/reg_array_reg*] true同时在flow上设置一个开关专门用来控制哪些模块允许MBFF。比如高频数据通路和锁相环附近的模拟敏感模块通常不建议合并。因为高频路径上多bit单元带来的额外内部距离可能正好把本来能收敛的路径拖挂。还要注意单元选择。有些库的MB4物理尺寸特别大在标准单元行里合法化后经常造成空洞。我的经验是如果库里同时提供MB2和MB4就先放开MB2让工具优先用2bit单元只对寄存器密度低、布线资源充裕的模块放开4bit。8bit单元除非你确认后端能处理否则建议直接设为dont_use。3. 物理优化联动DCG怎么同时看“地图”和“电表”综合阶段只看逻辑和物理实现阶段只看版图都会造成决策短视。DCG的价值在于它能把物理信息前置到综合阶段让MBFF这类同时影响逻辑和物理的优化动作有据可依。3.1 DCT、DCG到底差在哪抽象线负载和真实布局的距离老一代综合工具估算时序靠的是wireload model通过统计平均线长来猜net delay。这种方式在工艺尺寸还比较大的年代够用但到了28nm以下net delay受具体布局位置影响太大同一根net放在左上角和右下角延迟可能差出一个数量级。DCT的拓扑模式已经引入了简化的物理引擎可以粗略预估走线长度和拥塞。DCG则更进一步它能把floorplan、macro位置、电源规划这些信息真正纳入综合过程。做MBFF合并时DCG看的不是“这两颗DFF在逻辑上相邻”而是在抽象版图上距离够不够近、合并后会不会造成新的拥塞。这就好比原来你只是按通讯录给邻居组队现在你手里拿到了小区地图知道哪些人真的住隔壁。3.2 把floorplan信息喂给DCGMBFF才能“看上眼”要让DCG在Merge寄存器时参考物理距离前提是它得先看到物理信息。我习惯在综合的最早期先拿到APR同学给出的一版初始floorplan哪些区域放memory、哪些区域放标准单元、哪些地方有hard blockage。把这些信息转成DCG能理解的约束文件和SDC一起喂进去。这一步的输入质量直接决定MBFF优化质量。如果floorplan里macro位置和实际后端最终位置差得很远DCG认为可以合并的两颗寄存器在后端实际布局里可能隔着一条大bus合并后的MB4放不下反而引发连锁移动。后面第4章会详细讲这个坑。喂入floorplan后DCG会在合并MBFF的同时做一些简单的物理-aware的重叠检查避免把不可物理实现的优化结果吐出来。这一步不像APR的legalize那么精确但足以过滤掉大量“纸面上好看、实际上没法floorplan”的方案。3.3 从DCG到APR交接的不只是网表还有“队形”很多人以为DCG做完输出一个干净网表给APR就结束了。但实际上MBFF优化后的网表对后端来说有一些隐形的“队形要求”。比如合并后的多bit单元数量变多、单bit单元变少后端工具在legalize时如果没有意识到这些大单元的存在可能会把它们拆开重新打散让DCG的优化成果白白流失。所以交接时我会在SDC或guidance里明确保留MBFF相关的约束比如对已经合好的多bit单元加dont_touch除非后端在legalize时真的发现无可避免的拥塞问题才允许拆开重做。CTS阶段也要提醒后端MBFF会让时钟树的sink数量变少skew spec可以适度收紧但要注意多bit单元内部各bit之间的延迟差异不要让工具只盯着外部net delay而忽略单元内部的不匹配。内部时序失配在STA里会反映为multibit cell内部的min/max delay问题但很多新手会误以为是外部时钟树skew没修好。4. SPG流程避坑指南我在这套流程里踩过的五个深坑先说明一下SPG这个名字。在Synopsys官方文档里你可能找不到一个标准的“SPG流程”叫法它更像我们团队对“Structural-to-Physical Guidance”这套流程的简称核心思路是把综合阶段的逻辑结构优化和后端物理实现的物理引导文件串在一起保证MBFF这些优化能一路走到版图。下面这些坑都是我们在实际项目里真金白银踩出来的。4.1 坑一dont_use误伤MBFF单元工具悄悄“放弃治疗”最典型的情况出现在功耗优化脚本里。很多flow会统一对高阈值单元做控制比如为了低功耗大量使用HVT单元但同时会在脚本里写类似这样的语句set_dont_use [get_lib_cells */*HVT*] set_dont_use [get_lib_cells */*svt*]如果库里的MBFF单元命名里恰巧包含这些描述或者你的dont_use写得太强势比如对某个子库的所有cell都加了dont_use那MBFF单元即使存在DCG也一个都别想用。更坑的是这种问题通常不会报error工具只在log里低调地打一条warning然后默默输出一个完全没做MBFF优化的网表。我当时排查这个问题整整花了一天。先查RTL里有没有可合并的寄存器再查compile的log最后才想起去查dont_use列表。从那以后我在flow里加了一个checker综合结束后立刻统计网表里MBFF数量如果数量为0且库里有MBFF单元自动报fatal error而不是warning。这个checker后来救过好几轮项目。4.2 坑二MBFF库建模不完整时序报告一片混乱Multi-bit FF的Lib模型比普通单bit单元复杂得多。一个MB4单元里四个bit虽然共享时钟端口但各自的时序弧、内部寄生、翻转功耗都不一样。如果Lib建模时把四个bit的data-to-Q延迟写成完全一样或者内部电容没有按bit的实际物理位置设置综合和STA看到的时序就跟真实芯片对不上。最明显的问题是DCG在优化时通常选择“看起来最悲观”的bit来评估这个MBFF单元的时序。如果Lib里有个bit的时序弧缺失工具可能直接把它当0延迟处理报出过度乐观的余量到了后端APR跑真实RC抽取后这个bit的delay现出原形时序一下就翻红了。遇到这种情况光在后端修是修不回来的。我的建议是在采用新库的MBFF单元之前一定要让库团队对多bit单元做一次Liberty-to-SPICE的比对确认每个bit的时序弧特别是内部时钟到各bit输出的延迟差异都被正确建模。不要嫌麻烦这一步能省掉后续三个月的floorplan返工。4.3 坑三DCG和后端用的floorplan版本不一致SPG流程里最需要紧绷神经的就是版本一致性。我们曾经有一版floorplan为了评估一个memory替换方案临时移动过几个macro位置。DCG拿着这版floorplan做了MBFF合并但综合网表出来后后端说memory方案被否了已经切回旧版布局。结果就是DCG按新位置想的“邻居”在后端旧位置里变成了“天涯海角”。最终体现的问题是后端legalize时大量MB4单元找不到合法位置工具被迫把它们拆成单bit单元或四处移动拥塞从3%直接拉到9%原本Clock tree的一大半收益也丢了。后来我们立了一条规矩进入SPG流程后floorplan冻结。前端、后端各留一份带版本号的checkpoint所有参与方只认这一版。凌晨改方案可以但改完必须重新跑综合不能拿旧网表配新floorplan交代。这个规矩听起来笨但真的避免了大量无效加班。4.4 坑四Formality把多bit合并当成“设计变更”单bit DFF被合并成MBFF后形式上RTL里是四颗D触发器网表里变成了一颗MB4。Formality这类等价性检查工具必须能识别出这种“结构不同但逻辑等价”的变化才可能在compare phase把它们对应起来。问题往往出在库的functional model上。如果MBFF单元的functional model没有正确描述内部各bit的独立性或者在RTL的某些控制信号比如异步复位、scan enable上处理不当Formality可能在compare point匹配阶段就把多bit单元判成不等价或者需要用户手动设置才能通过。我在SPG流程里加了固定动作跑Formality之前先确认两个库里多bit单元的verification model都加载到位并且把set_constant这类约束和后端脚本保持完全一致。一旦出现multi-bit相关的unmatched point优先查Lib的function定义而不是急着改RTL。4.5 坑五clock gating和MBFF缠在一起CTS直接懵圈RTL里常见的if (enable)寄存逻辑综合工具往往会推断出ICG单元或者用普通触发器加EN引脚实现。但当MBFF和ICG共存时很容易出现一种尴尬局面工具想把一组由ICG控制时钟的寄存器合并成MBFF但库里的MBFF单元根本没有集成clock gating的能力或者ICG和多bit单元的组合建模有问题。于是DCG可能会做出一颗内部部分bit带gate、部分bit不带gate的“缝合怪”单元或者把ICG放在MBFF前面、导致时钟门控检查的时序路径变得特别长。CTS阶段碰到这种cell经常出现clock gating check大量违例修timing变得异常痛苦。我的建议是在综合脚本里明确控制ICG与MBFF的配合方式。如果库里没有专门的multi-bit ICG那就让综合器优先用单个ICG去驱动一组DFF而不是把ICG和MBFF深绑在一起。时序和功耗的权衡上宁可牺牲一点点动态功耗也要保住CTS阶段的可控性。5. 一套可以直接抄走的启用手册和收益预期写到最后把整个流程沉淀成一份可执行的手册方便你直接对着操作。5.1 推荐的总流程Step 1确认库里有可用的MBFF单元。用get_lib_cells */*mb*检查把MB2、MB4、MB8分别列出来在脚本里记录可用单元清单。Step 2检查现有dont_use和dont_touch列表确保MBFF单元没有被误伤。特别是功耗优化脚本里对HVT/SVT单元的过滤逻辑要单独确认。Step 3把初始floorplan信息整理成DCG可读的物理约束和SDC一并读入。与后端确认这版floorplan会冻结使用不随意变更。Step 4在DCG脚本里打开compile_ultra -optimize_register并开启multi_bit相关选项。先放开MB2视拥塞情况再决定是否放开MB4。Step 5综合完成后立刻统计MBFF数量如果为0或明显偏少先查log里的warning和dont_use而不是直接进APR。Step 6交网表给后端时附带SPG guidance文件明确哪些MBFF单元需要保持完整、哪些区域允许后端在高拥塞情况下拆分。Step 7后端的formal阶段单独确认multi-bit点的匹配情况有问题先查库模型。Step 8跑到APR后的第一版版图马上生成拥塞图和IR drop图对比MBFF优化前后的变化决定是否要回调规模和合并策略。5.2 关键参数速查参数/动作推荐值备注compile.ultra.optimize_registertrue核心总开关compile.ultra.multi_bit_register_optimizationtrue多bit合并使能可用MBFF粒度优先MB2按需MB48bit慎用MBFF验证检查综合后数量0防止dont_use误伤floorplan版本冻结一个checkpoint防止前后端失配后端dont_touch按区域选择性加防legalize拆分IR drop检查在APR后第一版立刻做防多bit同时翻转打穿电源5.3 收益预期和风险预期以我们这颗视频SoC模块的数据为例设计里有约12万颗可用于合并的寄存器启用MBFF优化后时钟网络功耗下降约20%标准单元总面积减少约3.5%CTS阶段的buffer数量减少了约15%。代价也客观存在局部拥塞指数从2.1%升到5.8%动态IR drop热点多了3处后段ECO时需要拆开MBFF单元才能改单bit逻辑的操作复杂度明显增加。所以这不是一个“全开就完事”的选项而是一个需要前后端一起做trade-off的物理优化手段。最后再分享一个小技巧在所有模块里优先让“控制逻辑多、寄存器排列整齐、翻转率不高但数量巨大”的模块使用MBFF收益最稳定反而是流水线数据通路上翻转率高、时序紧张强行合并容易得不偿失。先挑软柿子捏跑通一版完整流程后再逐步扩大范围比一次性全开要稳得多。
返回列表