原标题:PT 说我的 cell "功能不等价",但我确信它等价——一次 NED-005 排查记
前几天在 PT 里做手动 ECO:把一只 latch 型 clock gating cell 从 X2 换成 X4。同一个库、同一个系列、pin 一个不差,就是驱动不同。结果 PT 直接拒绝:
Error: Could not size 'xxx/latch' ('lib/TLATNCA_X2') with 'lib/TLATNCA_X4':
Cells not functionally equivalent. (NED-005)
第一反应是:X2 和 X4 功能还能不一样?是不是哪个设置把工具带偏了?
工具没偏,是我对"功能等价"的理解和它不一样。
翻 size_cell 的文档,PT 判功能等价看四样:输入 pin 数、输出 pin 数、逻辑功能,外加 enabled timing arc 的数量、类型和 sense。前三个好理解,第四个平时真不太注意。另外,如果 lib cell 上带着 Library Compiler 生成的 function_id、mog_func_id、user_function_class 这几个属性,两边也得一致。
clock gating latch 是典型的复杂时序 cell,LC 经常生成不了标准的 function_id,得靠 user_function_class 标注。不同 drive 的 cell,arc 建模差一点、或者这个属性标得不一样,PT 就判"不等价"。功能上确实一样,但四件套有一条不过,门就是关的。
想确认卡在哪条,两个命令。get_alternative_lib_cells 返回 PT 认可的等价 cell 列表,和 size_cell 是同一套判定:
get_alternative_lib_cells [get_cells xxx/latch]
列表是空的、或者没有你要的 X4,就是过不了(实测空列表会带 NED-002 warning)。再对比两个 lib cell 的属性:
get_attribute [get_lib_cells lib/TLATNCA_X2] function_id
get_attribute [get_lib_cells lib/TLATNCA_X2] user_function_class
到这儿其实还是纸上谈兵。我手里没有现成的库能复现,就在跑工具的那台 Linux 服务器上造了个最小 case:两个 latch cell,逻辑功能一模一样,只有 timing arc 集不同,看 PT 到底怎么判。造库的过程本身也踩了几个小坑——边沿弧类型、when 和 sdf_cond 要配对、constraint 表要带模板变量——不过那是另一个话题。结果复现是复现了,报的文案跟我项目里那句不一样:
Error: Could not size 'u1' ('demo_icg/TLATNCA_X1_LVT') with 'demo_icg/TLATNCA_X4_LVT':
Mismatch in the number of enabled library cell arcs
Library cells are incompatible. (NED-005)
同一个 NED-005,拒绝理由有好几种措辞。项目里是 "Cells not functionally equivalent",复现出来是 "Mismatch in the number of enabled library cell arcs",还有一种 "Cells must have same connections"。排查的时候先看清手上是哪一种,别拿着 A 的解法去套 B。
如果只是 arc 集有差异、逻辑功能确实一致,PT 留了个放行的口子:
set eco_strict_lib_arc_equivalence false
这个变量默认 true,卡的就是 arc 的数量、from/to pin、sense、when 条件四项。设成 false 之后,get_alternative_lib_cells 立刻列出 X4,size 也过了,但会给一个 NED-082 warning:"Sizing ... relaxing library arc check"。这个 warning 不能当没看见,放宽掉的那几条 arc 差异里有没有关键的 setup/hold,得人工核一遍。
但放行变量不是万能的。卡在 user_function_class 不匹配上,它管不着——它只管 arc。还有一种我实测踩到的:cell 的某个功能输入 pin 在目标 cell 里一条时序弧都没有,PT 报 "Cells must have same connections",这种连 arc 放松都救不回来,PT 认为连接关系本身就不一样。
这种情况只能上强制通道 swap_cell:
swap_cell [get_cells xxx/latch] [get_lib_cells lib/TLATNCA_X4]
swap_cell 只查一件事:换出 cell 的每个边界 pin,在换入 cell 里要有同名 pin,反过来也一样。功能等价?它不看。arc 变量是 true 还是 false?也不管。文档里倒是写了一句"只是换尺寸应该用 size_cell,它更高效",言下之意:size_cell 管不了的场景,才轮到它。
两个实测才知道的细节。第一,swap_in 直接写裸 cell 名会匹配不到(SEL-003),要写 library/cell 全名,或者干脆 get_lib_cells。第二,swap 成功的瞬间 PT 打印 PTE-018:"Abandoning fast timing updates. Reset incremental engine."——文档说"时序更新开销更大"不是客气话,它直接把增量时序引擎重置了,代价实打实。
swap 之后有两条要注意。第一,别显式跑 link_design——swap 只做了局部 relink,显式 link 会把 swap 撤销,PT 不保存 swap 信息。第二,既然绕过了等价检查,事后必须用 FM 之类的手段把等价性坐实,尤其 clock gating 路径上的 cell,万一真不等价就是功能事故,不是 timing 问题。
到这儿以为完了?最大的坑在交接。
ECO 做完要写 change list 给实现侧。PT 的 write_changes 支持好几种格式,给 ICC2 用 icctcl:
write_changes -format icctcl -output eco_icc2.tcl
写的时候 PT 当场报了一条:
Error: This netlist editing command ('swap_cell') is not supported in IC
Compiler. (NED-051)
打开生成的文件一看,size_cell 那条改动好好地写在脚本里,swap_cell 这条变成了三行注释:
# ERROR: Note that swap_cell is not supported by IC Compiler.
# The following comment shows what PrimeTime did:
# swap_cell [get_cells {u2}] demo_icg/TLATNCA_X4_LVT
也就是说,PT 其实喊了,但只喊在 write_changes 的 log 里,脚本本身照常生成。要是像平时一样写完就扔给 ICC2 source,不看 log 不打开文件,这条改动就神不知鬼不觉地没了。文档里其实白纸黑字写了 swap_cell 不写入 icctcl 和 dctcl 脚本,但不踩一次,谁注意得到那行字?
所以正确做法是写两份:icctcl 给 ICC2 跑其余改动,text 格式留一份核对清单,然后手工把 swap 翻译成 ICC2 命令补进脚本。ICC2 侧对应的是 change_link,真机 help 确认过存在:
change_link xxx/latch TLATNCA_X4
要求和 PT 的 swap_cell 一个标准:port 数量、名字、方向一致即可,不查功能等价——正好语义对应。跑完记得 link 一下让绑定生效。当然也可以先试 ICC2 自己的 size_cell——ICC2 和 PT 的等价判定是各自独立的,PT 判不等价不代表 ICC2 也判不过,能过的话用 size_cell 最干净。还有个细节:PT 写进 icctcl 脚本的 size_cell 不带库前缀,最终绑定到哪个库由 ICC2 的 link library 设置决定,跑完务必 report_cell 确认 ref 换对了。
最后跑 FM,把 X2 换 X4 的等价性正式坐实,这条 ECO 才算闭环。
回头看这次排查,印象最深的不是 NED-005 本身,而是"工具的判定"和"我以为的判定"之间的 gap:四件套加 LC 属性,少一样都不行;每层检查都有绕过的口子——arc 差异有 eco_strict_lib_arc_equivalence,属性差异有 swap_cell——但每绕开一层,验证责任就往你身上多压一层,swap_cell 连增量时序引擎都给你重置了。以及交接时那个最不起眼的坑:icctcl 里的 swap_cell 只剩注释,NED-051 喊是喊了,听不见就等于没有。
你在 ECO 流程里还踩过哪些"改动写了但没生效"的坑?欢迎评论区聊聊。
172