ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

ATPG约束实战:C/T/O/DX四种模式选型与覆盖率优化

2026/10/6 15:39:38 拓冰建站 浏览量
ATPG约束实战:C/T/O/DX四种模式选型与覆盖率优化 1. ATPG约束到底在解决什么问题做数字芯片测试这行的朋友对ATPGAutomatic Test Pattern Generation自动测试向量生成应该都不陌生。简单说它的任务就是给芯片内部的逻辑电路自动生成一套输入激励让制造过程中可能出现的各种物理缺陷——比如金属线短路、通孔断路、晶体管卡死——都能在测试机上被观测到。但ATPG工具不是万能的它需要你告诉它哪些地方可以动哪些地方不能动这就是约束constraint存在的意义。add_cell_constraint这个命令在主流ATPG工具不管是TetraMAX、FastScan还是其他同类工具里都属于精细控制级别的操作。它不像add_input_constraint那样直接管住某个输入端口也不像add_output_constraint那样锁死某个输出而是直接作用在标准单元standard cell的引脚上。换句话说它管的是这个单元的这个脚在测试模式下应该被当成什么状态来处理。那C/T/O/DX这四个字母到底代表什么这是很多刚入行的测试工程师最容易搞混的地方。我先把结论摆出来C Constant强制该引脚为固定逻辑值0或1ATPG工具在生成向量时不会去翻转它。T Tie把引脚绑定到某个固定电平但和C的区别在于T通常用于处理那些物理上已经接死的引脚工具会把它当作已知常量处理但不会尝试去驱动它。O Off把引脚设为关闭状态通常用于三态门tri-state的输出使能控制让输出进入高阻态。DX Dont Care / X-tolerant告诉工具这个引脚的值可以是不确定的X在生成向量时不需要对它做任何约束工具可以自由处理。这四个模式看起来简单但实际项目里选错了轻则覆盖率上不去重则生成一堆无效向量测试机跑半天全是废pattern。下面我结合自己踩过的坑把这四种约束的实战用法掰开揉碎讲清楚。2. 四种约束模式的核心原理与选型逻辑2.1 C模式最直接但也最容易滥用的约束C模式Constant是四种里最直观的。你在add_cell_constraint里指定某个单元的某个引脚为C并给出0或1ATPG工具就会在整条pattern生成过程中把这个引脚当成恒定值。典型场景假设你有一个时钟门控单元clock gating cell它的enable端在扫描测试模式下需要被强制为1让时钟能正常穿过。这时候你就可以用C模式把这个enable脚锁成1。再比如某些工艺库里的标准单元带有测试专用引脚比如scan enable、test mode这些脚在shift阶段和capture阶段需要不同的值C模式配合add_cell_constraint -pin ... -value ...就能精确控制。但C模式有个大坑它会让工具完全放弃对这个引脚的故障检测。因为引脚被锁死了连到它上面的stuck-at故障自然就测不到了。我见过一个项目工程师为了图省事把某个模块里几十个单元的输入全设成C结果覆盖率直接掉了3个百分点。后来一查那些被锁的引脚上挂着的故障全成了untestable。注意用C模式之前先问自己一句——这个引脚上的故障我真的不需要测吗如果答案是需要测那就别用C。2.2 T模式处理物理接死引脚的专用手段T模式Tie和C模式经常被混用但它们的语义有本质区别。C是逻辑上强制T是物理上已经接死。什么意思比如某个单元的某个输入脚在版图上直接连到了VDD或VSS那它在物理上就不可能被驱动成其他值。这时候你用T模式告诉工具这个脚已经接死了你别费劲去驱动它也别指望能测它上面的故障。为什么不能直接用C代替T因为在某些工具里C模式会尝试去驱动这个引脚如果这个引脚物理上接死了工具可能会报冲突或者生成无效向量。而T模式明确告诉工具这个脚不需要驱动工具就会跳过它。实操建议拿到网表之后先跑一遍check_cell_constraint或者类似的检查命令看看有没有引脚在版图上被tie high/tie low但你没加约束的。这些脚如果不处理ATPG工具可能会生成一堆试图翻转它们的向量结果在测试机上跑出来全是X。2.3 O模式三态门控制的关键O模式Off主要用在三态门tri-state buffer上。三态门的输出使能OE脚如果被激活输出就是正常逻辑值如果被关闭输出就是高阻态Z。在扫描测试里如果多个三态门的输出连到同一条总线上你必须保证同一时刻只有一个三态门是打开的否则总线上的值会冲突轻则产生X重则烧片。O模式就是用来干这个的把某些三态门的OE脚设成O让它们的输出进入高阻态从而避免总线冲突。典型场景一个SoC里有多个master通过三态总线访问同一个slave。在测试某个master的时候你需要把其他master的三态门全部关掉。这时候就用add_cell_constraint -pin OE -mode O把这些门关掉。踩坑记录有一次我忘了给一个三态门加O约束结果ATPG生成的向量在测试机上跑的时候那条总线上的值一直在X和0/1之间跳测试机直接报了一堆mismatch。后来加了O约束问题立刻消失。所以记住一句话只要你的设计里有三态总线就一定要检查O约束。2.4 DX模式X容忍与覆盖率之间的平衡DX模式Dont Care / X-tolerant是最微妙的一个。它的作用是告诉ATPG工具这个引脚的值我不关心你可以随便处理。听起来很美好但实际上DX模式是一把双刃剑。好处当某个引脚的值在仿真里就是X比如来自未初始化的寄存器、模拟模块的输出、或者多驱动冲突你用DX模式可以让工具不去管它从而避免生成无效向量。这在处理复杂SoC时特别有用因为SoC里总有一些模块在测试模式下行为不确定。坏处DX模式会让工具放弃对这个引脚相关逻辑的故障检测。如果你滥用DX覆盖率会悄悄往下掉而且你还不容易发现——因为工具不会报错它只是默默地少测了一些故障。选型逻辑我个人的原则是——能用C/T/O解决的绝不用DX。只有当某个引脚的值确实无法确定比如来自模拟IP的输出或者确定它不影响你要测的逻辑时才用DX。而且用了DX之后一定要跑一遍覆盖率分析看看有没有意外的覆盖率损失。3. add_cell_constraint实战操作全流程3.1 约束文件的基本结构在大多数ATPG工具里add_cell_constraint通常写在Dofile或者约束文件里。一个典型的约束文件结构是这样的# 设置当前设计 read_netlist ./netlist/top.v set_top_module top # 加载库 read_verilog ./lib/standard_cells.v # 添加单元约束 add_cell_constraint -cell CLKGATE_X1 -pin EN -mode C -value 1 add_cell_constraint -cell TIE_HIGH_CELL -pin Z -mode T add_cell_constraint -cell TRISTATE_BUF -pin OE -mode O add_cell_constraint -cell ANALOG_IP -pin DOUT -mode DX # 检查约束 check_cell_constraint -verbose # 运行ATPG run_atpg -auto这个结构看起来简单但每一步都有讲究。比如-cell后面跟的是单元名字不是实例名字。如果你写成了实例名工具会报错。再比如-pin后面跟的是引脚名大小写敏感写错了工具可能不报错但约束不生效。3.2 约束的优先级与冲突处理实际项目里你可能会遇到多个约束作用在同一个引脚上的情况。比如你先加了一个C约束后来又加了一个DX约束。这时候工具怎么处理答案是后加的覆盖先加的。但不同工具的行为可能不一样有的工具会报warning有的会直接覆盖。我的建议是在约束文件里按模块分组每个模块的约束写在一起避免同一个引脚被多次约束。如果确实需要覆盖就在注释里写清楚为什么。另外add_cell_constraint和add_input_constraint、add_output_constraint之间也可能冲突。比如你给某个输入端口加了C约束但这个端口连到了一个被C约束的单元引脚上。这时候工具会怎么处理一般来说端口级约束优先级更高但具体行为要看工具文档。提示加完所有约束后一定要跑check_cell_constraint或者report_constraint之类的命令把冲突和warning全部清理干净。我见过太多项目因为约束冲突导致覆盖率异常排查半天最后发现是约束写重了。3.3 分阶段约束策略ATPG的pattern生成通常分两个阶段shift阶段和capture阶段。这两个阶段对引脚的要求可能完全不同。比如scan enable脚在shift阶段需要是1让扫描链移位在capture阶段需要是0让功能逻辑捕获响应。这时候你就不能用简单的C约束把它锁死而需要用add_cell_constraint的-shift和-capture选项分别指定。# shift阶段scan enable为1 add_cell_constraint -cell SCAN_CTRL -pin SE -mode C -value 1 -shift # capture阶段scan enable为0 add_cell_constraint -cell SCAN_CTRL -pin SE -mode C -value 0 -capture这种分阶段约束在复杂设计里非常常见。如果你只写了一个不分阶段的C约束工具可能会在某个阶段生成错误的向量导致测试失败。3.4 约束与覆盖率的关系约束加得好不好最终体现在覆盖率上。我一般会做这样一个对比实验约束方案测试覆盖率向量数量测试时间无约束95.2%12000较长全C约束91.8%8000短精细C/T/O/DX98.5%15000中等滥用DX93.1%9000短从这张表能看出来全C约束虽然向量少、测试时间短但覆盖率损失严重滥用DX同样会掉覆盖率只有精细化的C/T/O/DX组合才能既保证覆盖率又控制向量数量。4. 常见问题与排查技巧实录4.1 约束不生效的几种原因原因一单元名或引脚名写错。这是最常见的。工具通常不会报错只是默默忽略。排查方法用report_cell_constraint看看实际生效的约束有哪些。原因二约束被后续命令覆盖。比如你在Dofile里先加了C约束后来又跑了一个脚本把约束全清了。排查方法在ATPG运行前打印约束列表。原因三工具版本差异。不同版本的ATPG工具对add_cell_constraint的支持可能不一样。比如老版本可能不支持-shift和-capture选项。排查方法查工具文档或者用help add_cell_constraint看支持哪些选项。4.2 覆盖率突然下降的排查思路如果你发现加了某个约束之后覆盖率掉了按这个顺序排查确认约束是否真的生效用report_cell_constraint看。确认掉的是哪些故障用report_faults -untested看。判断这些故障是否真的不需要测如果不需要测那覆盖率下降是正常的如果需要测那就得改约束。尝试用更精细的约束替代比如把C改成DX或者把全局约束改成条件约束。4.3 三态总线冲突的典型表现三态总线冲突在ATPG阶段可能不会报错但到了测试机上就会出问题。典型表现是测试机跑出来的fail pattern集中在某几条总线上而且fail的类型是X或者mismatch。解决方法在ATPG阶段用add_cell_constraint -mode O把所有不需要同时打开的三态门关掉。如果总线上的三态门很多可以考虑用脚本自动生成约束。4.4 DX模式的隐藏风险DX模式最大的风险是它会让工具静默地放弃一些故障检测。你加了DX约束工具不会报错覆盖率可能只掉一点点但那一小部分故障可能正好是关键路径上的。我的做法每次加完DX约束都跑一遍report_faults -untested把新增的untested故障列出来逐个确认是否真的不需要测。如果发现有关键故障被漏掉了就改用其他约束模式。5. 约束策略的进阶技巧与经验总结5.1 用脚本自动化约束生成大型SoC里手动加约束是不现实的。我一般会写一个脚本从网表里提取所有需要约束的单元和引脚然后自动生成约束文件。比如# 伪代码从网表提取tie cell并生成约束 import re def extract_tie_cells(netlist_file): tie_cells [] with open(netlist_file, r) as f: for line in f: if TIE_HIGH in line or TIE_LOW in line: # 解析单元名和引脚 tie_cells.append(parse_cell_info(line)) return tie_cells def generate_constraints(tie_cells): with open(cell_constraints.tcl, w) as f: for cell in tie_cells: f.write(fadd_cell_constraint -cell {cell.name} -pin {cell.pin} -mode T\n)这个脚本能省掉大量手工劳动而且不容易出错。5.2 约束的版本管理约束文件一定要纳入版本管理。我见过一个项目两个工程师同时改约束文件结果合并的时候冲突了谁也没发现最后ATPG跑出来的覆盖率比预期低了5个百分点。后来查了一整天才发现是约束文件被覆盖了。建议约束文件按模块拆分每个模块一个文件用source命令加载。这样合并冲突的概率会小很多。5.3 约束与DFT规则的配合add_cell_constraint不是孤立的它需要和DFT规则检查DRC配合。比如你给某个单元加了C约束但DRC检查发现这个单元的某个引脚违反了设计规则那你就得先修DRC再加约束。我的一般流程是先跑DRC修完所有violation再加约束再跑ATPG。这个顺序不能乱否则约束可能加了个寂寞。5.4 不同工艺节点的约束差异先进工艺节点比如7nm、5nm的标准单元库通常更复杂单元引脚更多约束也更精细。比如FinFET工艺里的某些单元带有back-bias引脚这些引脚在测试模式下需要特别处理。而成熟工艺节点比如40nm、28nm的单元库相对简单约束也少一些。经验换工艺节点的时候一定要重新审视约束文件。我见过一个项目从40nm迁移到16nm约束文件直接复用结果覆盖率掉了8个百分点。后来发现是新工艺库里多了一些测试专用引脚没加约束。6. 从约束到覆盖率一个完整的实战案例6.1 案例背景假设我们有一个中等规模的SoC包含CPU核、DSP核、若干外设和一条三态总线。ATPG初始覆盖率只有92%目标是98%以上。6.2 排查过程第一步跑DRC。发现三态总线上的多个三态门没有O约束导致总线冲突。第二步加O约束。用脚本自动提取所有三态门生成O约束。覆盖率提升到94%。第三步检查tie cell。发现网表里有大量tie high/tie low单元没有T约束。加上T约束后覆盖率提升到96%。第四步检查clock gating cell。发现部分clock gating cell的enable脚没有C约束导致时钟在capture阶段被意外关断。加上C约束后覆盖率提升到97.5%。第五步处理模拟IP。模拟IP的输出在数字ATPG里是X用DX约束处理。覆盖率提升到98.2%。第六步精细调整。对部分DX约束改用C约束对部分C约束改用DX约束反复迭代。最终覆盖率稳定在98.5%。6.3 关键数据步骤操作覆盖率向量数初始无约束92.0%100001加O约束94.0%110002加T约束96.0%125003加C约束97.5%140004加DX约束98.2%145005精细调整98.5%15000这个案例说明一个道理约束不是越多越好也不是越少越好而是要恰到好处。每一种约束都有它的适用场景用对了提升覆盖率用错了掉覆盖率。6.4 约束优化的迭代方法约束优化不是一次性的工作而是一个迭代过程。我的做法是先加必须加的约束比如三态门的O约束、tie cell的T约束。跑ATPG看覆盖率。分析untested故障判断哪些是约束导致的。调整约束再跑ATPG。重复3-4直到覆盖率达标。这个迭代过程可能需要跑好几轮但每一轮都能让你更了解设计的测试特性。7. 一些容易忽略的细节7.1 约束的顺序问题add_cell_constraint的顺序有时候会影响结果。比如你先加了一个全局的C约束后来又加了一个针对特定引脚的DX约束。如果工具是按顺序处理的那DX会覆盖C如果工具是按优先级处理的那可能C优先级更高。不同工具行为不一样最稳妥的做法是避免冲突而不是依赖工具的覆盖规则。7.2 约束与测试模式的对应有些设计有多个测试模式比如scan mode、mbist mode、boundary scan mode。不同模式下同一个引脚的约束可能不同。这时候你需要用-mode选项或者分文件管理约束。7.3 约束的文档化约束文件一定要写注释。我见过一个项目约束文件里几百行add_cell_constraint一行注释都没有。后来原工程师离职了接手的人完全看不懂为什么某个引脚要加DX约束。结果新人把DX改成了C覆盖率直接掉了2个百分点。建议每条约束后面都写清楚为什么加。比如# CLKGATE_X1的EN脚在scan模式下必须为1否则时钟无法穿过 add_cell_constraint -cell CLKGATE_X1 -pin EN -mode C -value 17.4 约束与低功耗设计的交互如果设计里有power gating或者clock gating约束会更复杂。比如power gating的isolation cell在测试模式下需要被使能否则信号无法穿过。这时候你需要用C约束把isolation enable脚锁成有效值。8. 写在最后add_cell_constraint这个命令看起来简单但真正用好需要你对设计、对工艺库、对ATPG工具都有深入理解。C/T/O/DX四种模式各有各的适用场景选错了轻则覆盖率上不去重则测试机跑废pattern。我个人的经验是先理解设计再理解约束最后才是写约束。不要一上来就抄别人的约束文件因为每个设计的测试需求都不一样。多跑实验多看报告多分析untested故障慢慢就能找到最适合你项目的约束策略。另外约束文件一定要纳入版本管理一定要写注释一定要跑DRC之后再加约束。这几个习惯能帮你省掉大量排查时间。芯片测试这行细节决定成败约束就是细节中的细节。