最近项目上用了不少大驱动的 buffer,signal EM 这项检查又一直排在很靠后的位置——等它跑出来的时候,离 TO 已经不远了:一批 buffer 直出的 net,在报告上挂了一长串违例。
这个时间点是最难受的。timing 刚签完,版图刚收敛,每一条违例对应的"标准修法"都让人头皮发麻:驱动换小?netlist 动了,timing 重签;插 buffer 分段?重新布局布线,DRC 重来;加宽拉远?手工改十几条 net,改完还得祈祷别引入新问题。离 TO 越近,每一步大动作的代价越像是拆东墙补西墙。
所以问题只剩一个:有没有一种影响足够小、又确实有效的修法?工具里躺着的 fix_signal_em,听名字就是干这个的。man page 拢共三行:读违例、修违例、完事。
一键修复,听着很美。但它到底干什么?是给你换小驱动、插 buffer,还是动线?修完会不会把 timing 搞崩?影响范围到底多小?问了一圈没人说得清,文档也不写。那就自己拆开看。
先把答案放这:它既不动 netlist,也不动 cell,干的事就一件——把违例的线加宽,然后局部重绕。这正好踩在"影响小"的点上:不改驱动、不动时序路径上的逻辑,只把几段线的宽度抬上去。但真正值得说的是后半句:它只修某一类违例,对另一类基本装死。而这两类怎么区分,直接决定你拿到违例报告之后该怎么干活。
实验环境交代一下:一个已经完成布线的小设计(开源的 picorv32,五千多条 net),某 40nm 工艺,工具是我手上的当前版本。EM 规则用原厂格式的 iRCX 文件,-format IRCX 读进去。顺手说一句:读完规则,花十秒钟看一眼报告里的 Required 列,有数值才算规则真绑定上了;层名对不上的层会报 SIGEM-006 被静默忽略。这个小检查能防住"规则没吃上、违例假干净"的乌龙。
规则吃上了,轮到主角登场。
先跑一遍修复前报告:16 条 net、34 个布线段的 PEAK 型违例,全在 M2/M3/M4 上。然后 fix_signal_em,盯 log。
它的动作分三步,log 里写得明明白白:先对违例段生成一套加宽用的非默认布线规则(NDR,名字就叫 sigem_rule_w1、w2 这样的),然后调 route_eco 做增量重布线,最后重新分析一遍。全程不碰 netlist——不会把你的 X20 换成 X8,也不插 buffer。迭代一轮就结束。
但第一轮的结果很尴尬:修完再分析,16 条 net 一条没少,几何 diff 是零。log 里一行小字暴露了原因:它生成的 NDR"与默认规则等价"——等于没加宽,白跑一趟。
为什么装死?注意这批违例的两个特征:全是 PEAK 型,全部位于顶层端口直连的 net 上。后面四轮对照实验,就是围着这两个特征做的。
那它什么时候真修?我把限值收紧,逼它出手。
端口 net 的 PEAK 违例有个特点:电流是端口理想激励打出来的(端口给的是标准激励模型,不是真实 cell 在驱动),跟内部驱动强度无关。我把规则里的 RMS 限值收紧约 4.5 倍,让 RMS 型违例冒出来,总数涨到 30 条 net、48 个段,再跑 fix_signal_em。
这次它真修了:修完只剩 2 条 net、3 个段。28 条 net 修复成功,route_eco 一共更新了 104 条 net。
拿其中一条 mem_rdata[31] 做修前修后的几何对比,动作看得清清楚楚:靠近驱动端的 M2/M3/M4 主干,线宽从 0.07 μm 加到 0.14 μm,整整一倍;局部拓扑重绕,多出新的叠孔和一小段 M5 跳线;离驱动端远的段,一动不动。
![mem_rdata[31] 修前(左)修后(右)整网对比,注意主干位置和新增的过孔](https://public.fangzhenxiu.com/fixComment/commentContent/imgs/1786381663328_3s3yco.jpg?imageView2/0)
放大到端口附近看,加宽一目了然——左边修前,右边修后,黄色 M2、橙色 M3、紫色 M4 全都粗了一倍:

原理就这么朴素:电流密度 = 电流 / 截面积,加宽一倍,限值跟着翻倍,违例消失。它不改电流,只抬限值。
四轮对照实验,测出了它的边界。
第一轮已经说了:全是 PEAK 型、全是端口 net,它零动作。第二轮我把活动率拉高 4 倍,想看看能不能逼出更多违例——结果一条新的都没有。PEAK 电流由驱动强度决定,跟 toggle rate 无关,这条对以后排查很有用:PEAK 违例别去折腾活动率,去查驱动。
第三轮把限值收紧 10 倍,违例还是只长在端口 net 上。第四轮换 AVG 型收紧 50 倍,AVG 违例依然是零——小设计上 AVG 电流比限值低两个量级,基本不可能违例。第五轮就是上面说的,RMS 收紧,它修了 28 条。
修完后剩下的 2 条 net 值得一看:一条 RMS、一条 PEAK,都在 die 边缘的端口直连 net 上——这种位置它尽力了也没全修掉。但更有意思的是对照:修前 16 条带 PEAK 违例的 net,有 15 条的 PEAK 跟着 RMS 一起被修掉了。所以准确的说法是:工具不是修不了 PEAK,而是不会为纯 PEAK 违例启动修复(第一、三轮,零动作);一旦有 RMS 违例触发加宽,PEAK 违例大多被顺带清掉。
顺带清掉这事在原理上完全讲得通:PEAK 限值和 RMS 一样,是线宽的线性函数(原厂模型里就是 C1·w/√r 这种形式),报告里违例段的 Required 列会直接告诉你加到多宽能过(我这个实验里就是 0.07 加到 0.09)。加宽降不了 PEAK 电流本身(电流由驱动强度和波形决定),但 EM 判定是电流对限值,抬限值和降电流是等效的两条路——一次加宽,整条限值曲线都抬上去了,RMS、PEAK 一起受益。
那纯 PEAK 场景它为什么不动手?说实话,我这组数据分不开两个变量:那批纯 PEAK 违例恰好全在 die 边缘的端口直连 net 上,是 PEAK 类型本身不修,还是端口 net 位置特殊(理想激励算出来的电流本来就保守,工具可能选择不碰),不能下定论。能下定论的是现象:它给那批违例生成的 NDR 退化成了默认规则,零动作。另外 block 内部、锁定的 shape、pin 内部的违例,它会直接标 unfixable,这些要在 block 级处理。
所以回到开头的问题:你项目里那批大 buffer 的 EM 违例,它能修吗?
看违例类型。报告里每一行都标了 AVG / RMS / PEAK:
AVG 和 RMS 型,放心交给它。这正是快 TO 时最想要的那类修复:不动 netlist、不动 cell、不把版图打回重布,只是把几十段线的宽度抬一档、局部重绕几根 via——timing 上的影响就是这几段线的电容略增,动过哪几段线、影响多大,都摆得清清楚楚,风险和换驱动、大 ECO 完全不是一个量级。当然修完该做的确认不能省:report_signal_em -violated 复查一遍,timing 快速过一眼,确认没有新伤。
PEAK 型要分两种情况看。如果同一条 net 上同时挂着 RMS(或 AVG)违例,不用你操心——修 RMS 的加宽会把 PEAK 限值一起抬上去,PEAK 违例顺带就清了。我第五轮实验里,16 条带 PEAK 违例的 net 有 15 条就是这么被捎带修掉的。
真正麻烦的是纯 PEAK 违例:实测这个版本不会为它们启动修复(NDR 退化成默认规则)。但注意,这不是说加宽对 PEAK 没用——上面说了,PEAK 限值同样随线宽线性涨。这里有个实测有效的变通:把 RMS 限值收紧,让这批 net 冒出 RMS 违例,修复器就肯动手了——加宽一上,PEAK 限值跟着抬;再配 -nets 定点,只修你点名的 net。我实测指定 2 根全修干净,同样挂着违例但没点名的旁观网一根线没动。修完记得换回正式规则,复查一遍 PEAK 确认真过。实在不想折腾规则的,也可以按 Required 列的目标宽度手工建 NDR 再 route_eco(这条我没实测,用之前先验证)。真正需要从驱动侧下手(压驱动强度、buffer 分段)的,是加宽没布线空间、或者差得太多加不满的情况。
顺手把可直接用的命令序列放这,注意前两步不做,分析根本不生效:
# 1. 开 signal EM(默认是关的!)
set_scenario_status <你的scenario> -signal_em true
# 2. 活动率铺满,否则大量 net 被 zero-toggle 跳过
set_switching_activity -static_probability 0.2 -toggle_rate 0.1 [get_nets -hier *]
# 3. 读规则,iRCX 格式;读完好先验证 Required 列
read_signal_em_constraints -format IRCX <原厂规则.ircx>
report_signal_em -nets [get_nets <挑一根 clk>] -verbose
# 4. 修前基线
report_signal_em -violated -verbose
# 5. 修;也可以 -nets 只修指定的 net,层次化结构里很有用
fix_signal_em
# fix_signal_em -nets [get_nets {mem_rdata*}]
# 6. 修后确认
report_signal_em -violated -verbose
三个实操提醒。一是它内部的 route_eco 会清掉 undo 历史,跑 fix 之前先 save_block 或者把几何 dump 出来,万一修砸了能回退,而且修前修后对比也靠这份备份。二是 -nets 只是范围过滤器,不是强制开关:实测把三条 FC 自己判定无违例的 net 喂进去,log 直接一句"There is no fixable signal EM violations",一根线都不动。所以如果你的违例清单来自 RedHawk 这类 signoff 工具,拿给 FC 修之前,先确认 FC 自己的分析也能看到这些违例——两边规则、活动率、corner 没对齐的话,它是不认账的。三是 signoff 级的 EM 结论还是以 RedHawk 这类专门工具为准,fix_signal_em 是 in-design 的修复手段,不是签收依据。
最后留个问题:你们项目的 signal EM 违例,是 AVG/RMS 型多还是 PEAK 型多?如果也是 PEAK 型扎堆,你们是靠什么手段过的评审——按 Required 手工加宽、压驱动、分段,还是跟 foundry 要寿命模型重新算?评论区聊聊。