
数字IC后端设计里density和congestion这一对指标几乎是从floorplan一路跟到signoff的老冤家。我在实际项目里见过太多这样的情况placement跑完报出来的cell density只有0.72看着挺舒服结果trial route一跑某些区域congestion map红得像烙铁也见过反过来为了压congestion把density一路往下调最后面积超标、时序收不回来不得不回头重做floorplan。ICC2和Innovus这两套工具控制density和congestion的旋钮各有各的叫法社区里零零散散的帖子很多但很少有人把为什么这么调和调完会带来什么副作用讲清楚。这篇东西想干的事很具体把density和congestion的物理含义拆开把ICC2和Innovus里真正管用的那批参数列出来再结合我自己跑过的几颗芯片讲讲从floorplan到placement再到route每个阶段该看什么指标、该动哪个旋钮、动完预期能改善多少。适合已经跑过一两轮PR流程、但对着congestion map还是有点懵的人看刚入门的朋友也能从中拿到一些可以直接照着改的命令序列。1. 先搞清楚density和congestion到底在说什么很多人一上来就问density调到多少合适这个问题本身就问偏了。density不是单一指标congestion也不是单一成因两个东西在不同阶段、不同工具里代表的意思并不一样。不把概念对齐后面调参基本就是瞎猜。1.1 三种density混着用必然出错工程里说的density至少要分成三种它们在报告里长得像含义差得远。Cell density单元密度标准单元总面积除以可布单元区域的面积。注意分母是可布单元区域也就是core面积减掉macro、减掉hard blockage、减掉keepout之后剩下的那块。ICC2的report_utilization和Innovus的density map默认给的都是这个口径。Pin density引脚密度单位面积内的引脚数量。这是congestion最直接的驱动因素之一。一个区域cell density只有0.6但里面全是200pin以上的复杂单元照样会堵得厉害。Track utilization / routing density布线轨道利用率把可用布线轨道数当分母实际走线需求当分子。这个才是congestion的近亲。PR工具里global route之后算出来的overflow本质就是在算这个东西。我在项目里判断一个block能不能收敛习惯是三张图一起看density map、pin density map、还有第一次trial route的congestion map。只看density map就拍板十次里有七次会被坑。还有一种容易被忽略的情况同一个block里不同module的density差异极大。比如一个DSP模块density到了0.85旁边一个控制逻辑模块只有0.5全局平均值看着很漂亮但那个0.85的区域在route阶段必炸。所以后面讲的局部density控制比全局参数更重要。1.2 Congestion的物理成因比你想的要杂Congestion的表现是overflow也就是某个global routing cellGRC里走线需求大于供给。但造成需求大于供给的原因有很多种对应的解法完全不同。第一类是总量型整个区域cell塞太多走线需求普遍偏高。这种靠降全局density、加面积就能解决。第二类是通道型macro之间留的channel太窄或者macro和core boundary之间只有两三条track的缝隙。走线不可能凭空穿过石头所有需求都挤在有限的通道里。这种靠降density几乎没用必须回去挪macro或者加soft blockage。第三类是引脚集中型某些单元或IP的pin挤在一条边上或者某个macro的pin全朝一个方向。这时候即使面积富裕局部pin density也会爆。第四类是层分配型低层金属被power mesh吃掉了大半信号只能往高层挤结果高层局部溢出。这种要在floorplan阶段就把power plan和signal layer的分配算清楚。我见过最典型的一次一个block的congestion一直收不掉反复降density从0.75降到0.6都没明显改善。最后发现是某个SRAM的halo设得太小标准单元紧贴着它摆而SRAM一侧的pin又特别密。加了两个GRC宽的keepout之后congestion直接掉了一半。所以遇到congestion先别急着动density参数先看地图上红的地方长得像什么形状——是整片红、条带红、还是点状红形状直接告诉你病因。1.3 为什么这两个指标总是在互相牵制道理其实很朴素density高单元挤得紧单元之间的平均连线长度短时序好、面积省但走线需求集中在更小的面积里congestion容易爆density低分散了走线需求摊开congestion缓解但线变长、时序变差、面积浪费还可能因为分散导致更多长线反而引入新的拥堵。所以density和congestion不是调一个另一个就好的关系中间存在一个最优点而这个最优点随设计变化。高pin密度的设计最优点偏向低density线长敏感的设计偏向高density。工具里的congestion effort参数本质就是让placer在塞紧和摊开之间做取舍。设成highplacer会主动把单元推开一点、给高连接度的cell留空间代价是runtime变长、线长变长。设成lowplacer只求塞进去runtime短但congestion风险高。这个取舍想明白了后面看参数就不容易犯迷糊。2. 工具侧参数全景ICC2和Innovus的旋钮对照两套工具的参数体系不一样但功能上基本一一对应。我整理了一份自己常用的对照先说清楚不同版本参数名和默认值会有差异动手之前一定先用工具自带的查询命令确认一遍ICC2用report_app_options *keyword*Innovus直接man或者help对应命令。2.1 全局density控制参数ICC2这边的入口主要是app options核心是place.coarse.max_density。这个选项限制placement阶段单个区域能达到的最大cell density默认值各版本不同常见在0.6到0.75之间。对于新手来说把它显式设成0.7到0.75是比较稳的起点。ICC2还有set_congestion_options -max_utilization这个命令能做区域级的density限制后面第5章会细讲。Innovus这边的入口是setPlaceMode -place_global_max_density值域0到1常用0.7到0.85。另外setPlaceMode -place_global_uniform_density true可以让placer主动把密度做得更均匀这个选项在全局密度不高但局部不均的设计上效果非常明显我几乎每个项目都会开。还有一个常被忽略的place_opt.flow.enable_ccdICC2和对应的时钟数据并发优化。它本身不是density参数但开启后placer会同时考虑时钟树和数据路径placement结果会因为时钟单元的预留位置而变化间接影响density分布。功能ICC2Innovus常用值全局最大单元密度place.coarse.max_densitysetPlaceMode -place_global_max_density0.70 ~ 0.78密度均匀化placement congestion effortsetPlaceMode -place_global_uniform_density truetrue局部利用率上限set_congestion_options -max_utilizationcreatePlaceBlockage -type partial区域而定单元额外间距set_placement_spacing_label/ spacing rulespecifyInstPad/ cell padding0 ~ 2 site2.2 congestion effort这一类参数ICC2里跟congestion相关的app options是*congestion*这一族用report_app_options *congestion*能列出一串。实际项目里最常调的是placement阶段的congestion effort值一般是low/medium/high。设high之后placer会在初始placement时就考虑布线资源分布代价是runtime明显变长我实测在大block上能到1.5到2倍。Innovus这边是setPlaceMode -place_global_cong_effort low|medium|high|auto。auto让工具根据设计规模自己判断我的习惯是先把auto跑一遍看结果如果congestion还不行再手动上high。这个参数对结果的影响比density参数更立体因为它不只是限制总量还会改变单元的摆放形态。global route阶段ICC2用route.global.timing_driven和route.global.congestion_effort这类选项Innovus用setRouteMode -earlyGlobalMaxRouteLayer配合trial route的参数。层数限制对congestion的影响经常被低估如果你允许global route用满所有层工具会找到解但detail route阶段一旦因为DRC或者via密度问题被封掉几层之前算好的解立刻崩掉。所以我一般会在floorplan阶段就定死信号可用层范围让congestion评估从一开始就在真实约束下做。2.3 两套工具命令对照速查实际工作中切换工具最痛苦的就是命令名对不上。下面这张对照表是我自己攒的放在手边随时查。动作ICC2Innovus报告利用率report_utilizationcheckPlace density map报告拥堵report_congestionreportCongestion -overflow热点定位report_congestion -grc_basedreportCongestion -hotSpot创建placement阻挡create_placement_blockagecreatePlaceBlockage设置halo/keepoutcreate_keepout_marginaddHaloToBlock单元加间隙spacing rule labelspecifyInstPad区域利用率限制set_congestion_optionspartial blockage全局布线试跑route_globaladdTrialRoute/routeDesign -global3. Floorplan阶段就要把density预算做对我个人的判断是一个block能不能收敛七成在floorplan阶段就定了。placement和route阶段能做的修补很有限大部分时候只是把already存在的问题挪个位置。所以与其在placement阶段死磕density参数不如在floorplan阶段把预算算准。3.1 目标utilization怎么算出来先把公式摆清楚因为很多人算的时候分母搞错了。cell_utilization 标准单元总面积 / (core面积 - macro面积 - hard blockage面积 - keepout面积)这个分母才是真正能放标准单元的面积。如果分母里忘了扣keepout和blockage算出来的utilization会虚低你以为还有空间其实已经满了。经验值方面我自己的取值习惯是普通逻辑为主的block目标0.72到0.78。低于0.70会浪费面积高于0.80在route阶段大概率要回来降。高pin密度设计大量复杂标准单元0.62到0.70。因为引脚集中允许的密度必须更低。含大量memory channel的设计0.55到0.65。macro通道会吃掉大量布线资源。顶层或者有大量长线的block0.65到0.72。还有一个容易被忘掉的项spare cell和decap的预留。有些流程要求预留3%到5%的面积给spare cell这部分面积在实际placement时会被填上单元但floorplan阶段评估时经常漏算导致最后density比预期高出一截。3.2 macro摆放对congestion的隐性影响macro的位置对congestion影响巨大而且很多时候是看不见的——因为density map上看不出问题只有route完才知道。几个我踩出来经验第一macro的pin面尽量朝向core内部的开阔区域。如果两个macro的pin面相对中间通道再窄那里必堵。宁可牺牲一点面积把pin面错开。第二不要把macro摆成阶梯状或者L形把core切成细长条。通道一旦窄于某个阈值我一般按10到15条track估global route会显示绿色但detail route会大量绕线最后还是堵。第三macro周围一定要留halo。ICC2用create_keepout_marginInnovus用addHaloToBlock。halo宽度按macro的pin密度给我一般起点是2到3个GRCpin密的加到4个。第四memory阵列之间要留出高速公路。经验做法是在macro群之间保留一条宽度至少能跑20到30条track的通道专门给跨模块的长线用。3.3 blockage和halo的实操配置blockage不是随便加就有效的加错了比不加更糟。ICC2里创建placement阻挡# 硬阻挡完全不允许放标准单元 create_placement_blockage -type hard -boundary {{100 100} {200 200}} -name hard_blk_1 # 软阻挡placer尽量避开但必要时可以放 create_placement_blockage -type soft -boundary {{300 100} {400 200}} -name soft_blk_1 # 部分阻挡允许放到指定密度 create_placement_blockage -type partial -boundary {{500 100} {600 200}} \ -utilization_threshold 0.5 -name partial_blk_1Innovus对应createPlaceBlockage -box {100 100 200 200} -type hard -name hard_blk_1 createPlaceBlockage -box {300 100 400 200} -type soft -name soft_blk_1 createPlaceBlockage -box {500 100 600 200} -type partial -name partial_blk_1实操心得soft blockage是我用得最多的一种。在macro上方或者通道附近放soft blockageplacer会倾向于避开但如果实在塞不下还是允许放进去这样既缓解了congestion又不会让placement失败。而hard blockage一旦设得太大会把单元逼到别处造成局部密度飙升反而制造新热点。注意hard blockage的区域不会计入utilization计算的可布面积所以设完之后要重新评估目标density否则分母变了你之前的65%实际变成了75%。另外blockage是有代价的——它会让线长变长、时序变差。我一般只会对确认有问题的区域加加完之后一定会对比一下WNS和TNS的变化如果时序掉了超过5%就要重新评估是否值得。4. Placement阶段控制density的实操流程进到placement阶段能做的调整其实是在既定floorplan下的优化。这时候的目标不是改布局而是精细分配。4.1 用什么指标判断density是否合理跑完第一次placement我会按顺序看这几项全局cell density直接看报告。超出目标值3个点以上就要查原因。局部density分布看density map的直方图不只看平均值。如果某个区域超过全局值10个点就是潜在热点。pin density分布这个指标在Innovus里可以通过GUI的density视图切换查看ICC2里用report出来的pin count分布估算。第一次trial route的overflow这是最硬的证据。global route后report_congestion或reportCongestion -overflow看overflow的GRC数量占比和最大值。我的经验阈值overflow的GRC占比超过1%或者单个GRC的overflow超过该GRC容量的30%就必须处理。低于这个数可以先放着因为detail route阶段还有调整空间。一个容易忽略的点runtime和overflow之间不是线性关系。有时候你把effort从medium提到highoverflow只降了5%但runtime翻倍。这种情况下不如回到floorplan改一下macro位置收益大得多。4.2 ICC2的实操命令序列下面是我在ICC2里常用的一套顺序从placement到检查# 1. 设定全局密度上限 set_app_options -name place.coarse.max_density -value 0.74 # 2. 提高placement阶段的拥堵优化力度 set_app_options -name place_opt.place.congestion_effort -value high # 3. 对已知的高密度区域做局部利用率限制 set_congestion_options -max_utilization 0.62 \ -coordinate {1200 800 1800 1400} -name congest_zone_1 # 4. 运行placement place_opt # 5. 检查利用率 report_utilization -hierarchical ./rpt/util_hier.rpt report_utilization ./rpt/util.rpt # 6. 跑全局布线评估拥堵 route_global report_congestion -grc_based ./rpt/congestion.rpt关于第2条里的app option路径我提醒一句ICC2的选项层级在不同版本之间改过有时候是place_opt.flow.*有时候是place_opt.place.*。最稳的做法是report_app_options *congestion*先看工具里到底有哪些然后挑placement阶段那个改。不要照抄网上的路径抄错路径工具不会报错只会静默用默认值那种明明设了却没效果的坑八成都是路径写错了。set_congestion_options这个命令值得多说两句。它支持按坐标区域设最大利用率也支持按module名设定。对于已知的、floorplan阶段就判断会有问题的区域提前设一个更低的利用率上限比等到placement之后再补blockage效果好。我一般会在跑第一次placement之前就把两三个高风险区域设好。4.3 Innovus的实操命令序列Innovus这边的顺序类似命令名不同# 1. 全局密度与均匀化 setPlaceMode -place_global_max_density 0.74 setPlaceMode -place_global_uniform_density true # 2. 拥堵优化力度 setPlaceMode -place_global_cong_effort high # 3. 对个别高连接度单元加间距 specifyInstPad instName_1 1 specifyInstPad instName_2 2 # 4. 执行placement placeDesign -inPlaceOpt # 或者分步place_opt_design checkPlace # 5. 早全局布线评估 setRouteMode -earlyGlobalMaxRouteLayer 5 addTrialRoute reportCongestion -overflow ./rpt/congestion_overflow.rpt reportCongestion -hotSpot ./rpt/congestion_hotspot.rptspecifyInstPad这个命令用得好的话非常有效。它给指定实例周围加间距placer会自动避让。适用场景是那些扇出特别大、或者引脚特别多的单元——比如时钟分频器、大型多路选择器、高扇出的缓冲器。给它们周围加一到两个site的间距能显著缓解局部pin density而且代价很小。注意specifyInstPad是对实例级的不是对cell type的。如果某个类型的单元在设计中出现几百次逐个指定不现实。这种情况更适合用全局的spacing规则或者干脆在floorplan阶段就规划好。setPlaceMode -place_global_uniform_density true我几乎必开。它做的事情是让placer主动把密度做得更均匀代价是稍微牺牲一点线长。在大部分设计上这个交换是划算的——因为线长增加5%congestion可能降15%。5. Congestion分层治理从全局到局部congestion的解决思路我总结成一句话先看形状再找病因最后分层下药。不同层级的拥堵用的手段完全不一样。5.1 怎么读congestion map和报告看到congestion map第一件事是判断形状。整片均匀泛红典型的全局密度过高。解法是降全局density参数或者扩core面积。条带状红通常沿macro边缘分布是通道太窄。解法是挪macro或者加soft blockage。点状集中红某个具体单元或IP造成的。解法是给那个实例加padding或者局部blockage。边界红core boundary附近高密度常见原因是IO或者pin约束把单元往那边挤。解法是在边界区域加partial blockage。随层变化的红如果低层红高层绿说明信号都往上跑了要检查power plan是否吃掉了太多低层资源。报告里的数字我会重点看两个overflow的GRC数量和最大overflow值。前者告诉你影响面后者告诉你严重程度。影响面大但程度轻的用全局参数解决影响面小但程度重的用局部手段点对点处理。我一般会把改动前的congestion报告存一份改完之后对比。因为congestion优化经常是这里好了那里坏了不对比很容易以为自己在进步实际总量没变。5.2 全局层级的四类解法第一类降density上限。最直接效果也最明显。但代价是面积和线长我在前面说过一次不要降超过3个点降太多会连带时序一起崩。降完一定要重跑时序。第二类提高congestion effort。效果比降density更聪明因为它不靠牺牲全局密度而是靠更聪明的摆放。代价是runtime。我的习惯是先提efforteffort解决不了再降density。第三类调整layer assignment。给global route更大的层范围或者调整power plan让出更多低层资源。这一类的收益经常被低估——我遇到过一次只是把power mesh的striping间距从30改到45congestion直接降了20%因为释放出来的低层track刚好够信号走。第四类cell padding与spacing规则。对整类单元加间距。ICC2里用set_placement_spacing_label配合set_placement_spacing_ruleInnovus里对实例用specifyInstPad。这一类的代价最小但只对pin density型拥堵有效。5.3 局部热点的手工干预局部热点是place-and-route里最费时间的部分因为工具自动优化对局部热点的效果有限。我的处理流程是这样的第一步定位。用reportCongestion -hotSpot或者ICC2的report_congestion -grc_based拿到具体坐标和module名。第二步判断成因。把这个区域单独放大看看是单元太密、macro太近、还是某个单元pin太多。第三步下药# ICC2对该区域设更低的利用率上限 set_congestion_options -max_utilization 0.55 \ -coordinate {1550 1200 1750 1400} -name hotspot_fix_1 # Innovus加soft blockage把单元推出去 createPlaceBlockage -box {1550 1200 1750 1400} -type soft -name hotspot_fix_1第四步验证。重跑placement和trial route确认热点消失的同时没有制造新热点。这里有个很重要的经验局部干预要一次改一个区域。我早期犯过的错误是一次性加五六个blockage结果单元全被挤到剩下的地方形成更大的热点反而更难收拾。一次改一个看效果再改下一个。注意blockage加多了会让placement的结果非常人工后续如果设计有改动比如功能ECO加了逻辑这些人工约束会变成负担。所以能靠参数解决的尽量别靠blockage。5.4 timing和congestion的取舍这是placement阶段最需要判断力的一件事。congestion努力调高、density调低都会让单元分散、线变长时序变差。反过来为了时序把单元挤紧congestion又会爆。我的做法是设两条线congestion红线overflow的GRC占比不超过1.5%。超过这条线无论时序多好都要处理因为route阶段过不去等于一切白做。时序红线WNS不超过目标值的负向10%。比如目标是-100ps那placement后不能低于-110ps。两条线都守住说明placement是健康的。如果守不住一条优先保congestion因为时序在后面的CTS和route阶段还有修复空间而congestion一旦固化到placement里后面很难逆转。这是我做了几个项目之后形成的判断早期我总是先保时序结果route阶段反复返工总时间反而更长。另外timing-driven和congestion-driven这两个目标在工具里是可以调权重的。ICC2和Innovus都允许你在placement时指定两者的优先级。我的默认配置是相等权重跑第一轮看哪边差得更多然后第二轮调整权重。6. 常见问题排查速查与踩坑记录前面讲的都是应该怎么做这一章讲做不对的时候怎么查。6.1 症状与病因对照表症状可能病因优先处理手段density正常但overflow高pin density集中cell padding、局部blockage整片密度超标floorplan面积估算错误扩core或降目标利用率特定区域反复出现热点macro channel太窄挪macro、加halo低层红高层绿power plan占用低层过多调整power mesh间距placement后正常route后爆层分配假设不真实提前定死layer范围改完一处坏另一处干预过猛单元被挤走一次只改一个区域runtime暴涨但效果一般effort设太高回到floorplan层面解决placement失败报密度超限hard blockage太多部分改soft blockage这张表里的每一条我都实际遇到过尤其最后一条是新手最容易踩的为了让某块区域不堵设了一大片hard blockage结果placer没地方放单元直接报拥塞失败还得回头一点点缩小blockage。6.2 几个真实的坑坑一只调参数不动floorplan。我见过有同事把density从0.8一直降到0.55congestion还是红的最后发现是两颗macro贴得太近。降density在这里完全没有用因为问题不在总量而在通道。所以我现在的原则是第一次优化无效就立刻怀疑floorplan不要在同一层级反复调参。坑二忽略power plan的影响。在一颗设计上我们把所有placement参数都调了一遍congestion纹丝不动。后来发现power mesh的宽度设得太大低层金属被吃掉将近四成信号只能挤在剩下那几层。改了power stripe宽度和间距之后问题立刻缓解。这个教训是congestion评估一定要在最终的power plan确定之后做用临时power plan跑出来的结果没有参考价值。坑三spare cell和decap事后填。有些流程为了赶进度先不填spare cellplacement跑完觉得没问题最后填spare的时候直接填出了新的congestion。我的做法是在placement阶段就把spare cell按最终密度一起放进去宁可多花一点时间也不要最后翻车。坑四跨工具对比参数值。ICC2的density 0.75和Innovus的-place_global_max_density 0.75语义不完全一样因为两者对可布区域的定义和计算方式有差异。换工具的时候不要直接照搬数值而是要照着overflow的实测结果去标定。坑五congestion报告和实际detail route结果差距大。global route算出来的拥塞只是估算它假设走线可以任意绕。实际detail route受DRC、via规则、pin access限制结果会比global route差。所以我一般会在global route的overflow上留20%到30%的余量报告显示0.8%以内才认为安全。6.3 关于选中指定名字的PG term这类细活最后一个话题说说怎么处理那种看起来很小但很费时间的操作。带body bias的工艺里标准单元上会有额外的PG term比如名为biasnw的n-well偏置端口。做PG连接或者做检查的时候经常需要把设计里所有带这个名字的PG term选中。手动在GUI里点不现实标准单元可能有几十万个实例。思路是用数据库查询加批量选择。Innovus里比较通用的做法# 先清空当前选择 deselectAll # 用dbGet查询所有cell的pgTerm里名字匹配的项 set bias_pins [dbGet -e top.insts.cell.pgTerms.name biasnw] # 看看查出来多少个确认数量合理再往下走 puts matched pg terms: [llength $bias_pins] # 批量选中 select_obj $bias_pins这里-e这个选项很关键它的作用是让dbGet把嵌套的属性展开成对象列表而不是字符串列表不加的话选中会失败。这个细节我在第一次用的时候琢磨了很久因为不加-e的时候命令不报错只是选不中任何东西非常容易误判成名字写错了。如果需要按这个PG term做网络连接Innovus里的命令是globalNetConnect biasnw -type pgpin -pin biasnw -inst * -override-type pgpin指定连的是电源地引脚-pin指定引脚名-inst *表示所有实例。如果只是想在GUI里目视检查比敲命令更快的方式是用选择菜单里的按属性筛选功能输入PG term名字即可。但批量操作、或者需要写进脚本里重复执行时还是dbGet加select_obj这套更靠谱。注意查询出来的pg term数量一定要和预期对一下。如果工艺库里同一个名字的PG term出现在多种cell上而你只想处理其中一部分那就要在dbGet的条件里再加cell类型的过滤否则会误选。这类选择范围的问题出错了不会有任何报错提示只会在后面某个环节冒出莫名其妙的结果。还有一点经验这类批量选择的操作建议先在设计的副本上跑一遍确认选中数量和范围符合预期再在主流程里执行。因为select_obj之后如果接着做删除或者修改操作误选会直接破坏数据库而且很难回滚。我个人在实际操作中的体会是density和congestion这件事越是急着调参数越容易在原地打转。真正解决问题的那几次都是回到floorplan图纸上用笔把macro位置重新画一遍或者拿着congestion map的形状反推物理原因。工具参数是加速器不是发动机。如果非要给一条可以马上用起来的建议那就是每次优化congestion之前先把改动的预期收益写下来把report存下来改完对比。我早期是凭感觉调改动十几个参数之后完全说不清哪个有效后来养成记账的习惯几颗芯片下来手里就攒出了一份属于自己的参数-收益对应表比任何文档都好用。