1. 从一次流片前的时序惊魂说起
如果你正在做DFT(Design for Test)相关的后端或验证工作,看到“Tessent MBIST SDC”这几个词,大概率是遇到了下面这个场景:芯片功能逻辑的时序已经收敛得差不多了,结果一跑MBIST(Memory Built-In Self-Test,存储器内建自测试)的时序,满屏的setup/hold violation,或者更隐蔽的——功能模式下没问题,一切到MBIST测试模式,时钟路径就崩了。我见过不止一个项目,在tapeout前两周才发现MBIST的SDC约束根本没写对,最后靠加班加点重新约束、重新跑STA才勉强赶上进度。
这篇文章就是围绕Tessent MBIST SDC这个主题,把MBIST测试模式下的SDC约束到底该怎么写、为什么这么写、哪些地方最容易踩坑,从头到尾讲清楚。适合正在用Tessent工具做MBIST插入的DFT工程师、负责测试模式时序收敛的后端工程师,以及需要理解MBIST时钟架构的验证人员。不管你是刚接触MBIST约束的新手,还是已经写过几轮SDC但总觉得哪里不对的老手,下面这些内容应该都能帮你省下不少debug时间。
核心关键词先摆出来:Tessent是业界主流的DFT工具套件,MBIST是存储器自测试的行业标准方法,SDC(Synopsys Design Constraints)则是时序约束的通用语言。三者交汇的地方,就是MBIST测试模式下的时序约束——一个看起来简单、实际上暗坑无数的领域。
2. MBIST测试模式的时钟架构与约束逻辑
2.1 为什么MBIST需要独立的SDC约束
功能模式下的SDC约束,描述的是芯片在正常工作时的时序关系:时钟频率、输入输出延迟、时钟域交叉、多周期路径等等。但MBIST测试模式完全是另一套游戏规则。测试模式下,芯片的时钟往往来自ATE(自动测试设备)直接灌入的慢速时钟,PLL可能被旁路,功能时钟可能被mux掉,取而代之的是测试时钟。更关键的是,MBIST控制器会生成自己的时钟和地址信号去访问memory,这些路径在功能模式下根本不存在。
所以,功能SDC直接套用到MBIST模式,必然出问题。要么是约束过紧——把本来不需要满足功能频率的测试路径约束到了功能频率,导致大量假violation;要么是约束过松——该检查的测试路径没检查到,硅片上跑MBIST的时候直接fail。这两种情况我都遇到过,前者浪费大量时间在假问题上,后者更危险,可能直接导致芯片报废。
Tessent工具在插入MBIST逻辑的时候,会生成一套测试模式下的时钟架构。这套架构的核心是:MBIST控制器时钟、memory时钟、扫描链时钟,以及它们之间的切换逻辑。SDC约束要做的,就是准确描述这套架构下的时序关系。
2.2 MBIST时钟域的三个层次
理解MBIST的SDC约束,首先要理解它的时钟域层次。我把它分为三层:
第一层是测试时钟源。这是从芯片外部(ATE)直接灌入的时钟,通常频率很低,比如10MHz到50MHz。这个时钟在SDC里要定义为create_clock,周期根据实际测试频率来设。注意,这个时钟的端口通常是功能复用的,所以要用set_case_analysis或者模式选择信号来区分。
第二层是MBIST控制器时钟。Tessent插入的MBIST控制器通常有自己的时钟域,这个时钟可能直接来自测试时钟源,也可能经过一个分频器。如果是分频器产生的,SDC里要用create_generated_clock来描述,并且要正确设置分频比。
第三层是memory接口时钟。这是MBIST控制器输出到memory的时钟,通常和控制器时钟同源,但可能经过时钟门控或者mux。这一层的约束最容易出问题,因为memory的时序要求(setup/hold)在测试模式下和功能模式下可能不同。
这三层时钟域之间的关系,决定了SDC约束的基本框架。我通常的做法是:先画出MBIST模式的时钟架构图,标注每个时钟的来源、频率、分频关系,然后再写约束。这一步看起来费时间,但能避免后面大量的返工。
2.3 模式选择与case analysis的设置
MBIST测试模式和功能模式的切换,通常通过一个或多个模式选择信号来控制。在SDC里,必须用set_case_analysis把这些信号固定到测试模式的值,否则STA工具会同时分析两种模式,导致约束冲突。
具体操作上,假设有一个test_mode信号,高电平表示MBIST模式,那么SDC里要写:
set_case_analysis 1 [get_ports test_mode]如果还有更细的模式选择,比如mbist_en、scan_en等,也要一并设置。这里有个坑:set_case_analysis的顺序和优先级。如果多个模式信号之间有依赖关系,比如test_mode为1时mbist_en才有效,那么要确保case analysis的设置顺序正确,或者用-set_case_analysis的优先级选项。
另外,有些设计会用锁存器或者寄存器来存储模式选择信号,这种情况下不能直接对端口做case analysis,而要对寄存器的输出做。我遇到过一种情况:模式选择信号经过了一个同步器,SDC里对端口做了case analysis,但同步器后面的信号没有被正确传播,导致STA分析的是错误模式。解决办法是用set_case_analysis配合set_disable_timing,或者直接在同步器输出上做case analysis。
注意:set_case_analysis会影响整个时序分析,包括功能路径和测试路径。如果设计中有部分逻辑在MBIST模式下仍然需要保持功能行为,要特别小心,避免误约束。
3. Tessent MBIST SDC的核心约束逐条拆解
3.1 时钟定义:create_clock与create_generated_clock
MBIST模式下的时钟定义,是SDC约束的起点。Tessent工具在插入MBIST逻辑时,会生成一个时钟定义文件(通常叫mbist_clock.sdc或者类似名字),里面包含了基本的时钟定义。但这个文件往往需要根据实际设计进行修改和补充。
对于测试时钟源,典型的定义是:
create_clock -name test_clk -period 100 [get_ports test_clk]周期100ns对应10MHz,这是ATE常用的测试频率。如果测试时钟经过PLL或者分频器,要用create_generated_clock:
create_generated_clock -name mbist_clk -source [get_ports test_clk] \ -divide_by 2 [get_pins u_div/clk_out]这里的关键是**-source要指向正确的源时钟**,-divide_by要跟实际分频比一致。我见过有人把-source指向了功能时钟,结果生成的时钟波形完全不对,STA结果自然也是错的。
对于memory接口时钟,如果经过了时钟门控,要用create_generated_clock配合-combinational或者-edge_shift来描述。时钟门控在MBIST模式下通常是常开的,所以可以用set_case_analysis把门控使能信号固定为有效值,然后直接传播时钟。
3.2 时钟分组与异步关系
MBIST模式下,通常有多个时钟域:测试时钟域、MBIST控制器时钟域、memory时钟域,可能还有扫描链时钟域。这些时钟域之间如果是异步的,要用set_clock_groups声明:
set_clock_groups -asynchronous \ -group {test_clk} \ -group {mbist_clk} \ -group {scan_clk}这一步非常重要,因为如果不声明异步关系,STA工具会默认检查跨时钟域的时序路径,产生大量无意义的violation。但要注意,不是所有跨时钟域路径都是异步的。比如MBIST控制器到memory的路径,虽然时钟名字不同,但可能是同源的,这种情况下不能设为异步,而要检查实际的时序关系。
我通常的做法是:先列出所有时钟域,然后逐一确认它们之间的相位关系。同源的、有确定相位关系的,不设异步;真正异步的,才设clock groups。这个判断过程需要结合时钟架构图来做,不能拍脑袋。
3.3 输入输出延迟与驱动强度
MBIST模式下,ATE直接驱动芯片的测试端口,所以输入延迟和输出延迟的设置跟功能模式不同。典型的设置是:
set_input_delay -clock test_clk -max 5 [get_ports mbist_data_in*] set_input_delay -clock test_clk -min 2 [get_ports mbist_data_in*] set_output_delay -clock test_clk -max 5 [get_ports mbist_data_out*] set_output_delay -clock test_clk -min 2 [get_ports mbist_data_out*]这些值要根据ATE的实际时序参数来定。如果不知道具体值,可以先设一个保守的估计,比如周期的20%到30%,然后在后续分析中调整。
驱动强度方面,ATE的驱动能力通常比芯片内部的驱动器弱,所以要用set_driving_cell或者set_input_transition来模拟:
set_driving_cell -lib_cell BUFFD4 -pin Z [get_ports mbist_data_in*]或者更简单的方式:
set_input_transition 1.0 [get_ports mbist_data_in*]这里有个经验:输入转换时间不要设得太乐观。我见过有人设0.1ns,结果STA过了,硅片上却因为信号边沿太慢导致setup violation。保守一点,设0.5ns到1.0ns比较稳妥。
3.4 多周期路径与false path
MBIST模式下,很多路径不需要在一个时钟周期内完成。比如MBIST控制器的配置寄存器写入,可能只需要在测试开始前完成一次,不需要每个周期都检查。这种情况下要用set_multicycle_path:
set_multicycle_path -setup 10 -from [get_pins u_mbist/config_reg*] \ -to [get_pins u_mbist/ctrl_reg*] set_multicycle_path -hold 9 -from [get_pins u_mbist/config_reg*] \ -to [get_pins u_mbist/ctrl_reg*]注意setup和hold的配合:setup设N,hold通常设N-1。如果只设setup不设hold,hold检查会默认在同一个周期,可能导致hold violation。
false path的使用要更谨慎。只有确认某条路径在MBIST模式下完全不需要检查时,才设false path。比如一些功能模式下的调试逻辑,在MBIST模式下被完全旁路,可以设false path。但如果不确定,宁可先不设,等STA报出来再分析。
提示:set_multicycle_path和set_false_path都是强约束,会覆盖默认的时序检查。使用前最好先用report_timing确认路径的实际需求,避免过度约束或约束不足。
3.5 时钟不确定性(uncertainty)与latency
MBIST模式下的时钟不确定性,主要来自ATE的时钟抖动和芯片内部的时钟树偏差。典型的设置是:
set_clock_uncertainty -setup 0.5 [get_clocks test_clk] set_clock_uncertainty -hold 0.3 [get_clocks test_clk]这些值要根据ATE的规格和时钟树综合的结果来定。如果时钟树还没综合,可以先设一个估计值,比如周期的5%到10%。
时钟latency方面,MBIST模式下通常不需要设source latency,因为时钟从ATE直接灌入,没有片上的时钟生成电路。但如果有PLL或者分频器,要设generated clock的latency。
4. 实操流程:从Tessent输出到STA收敛
4.1 Tessent MBIST插入后的文件清单
Tessent工具在完成MBIST插入后,会生成一系列文件。跟SDC相关的主要有:
- mbist_clock.sdc:基本的时钟定义,包括测试时钟和生成的时钟。
- mbist_mode.sdc:模式选择信号的case analysis设置。
- mbist_path.sdc:MBIST相关路径的约束,包括multicycle和false path。
- mbist_interface.sdc:memory接口的时序约束。
这些文件通常需要合并到顶层的SDC中。合并的顺序很重要:先读功能SDC,再读MBIST SDC,确保MBIST的约束覆盖功能约束。如果顺序反了,功能约束可能会覆盖MBIST约束,导致测试模式下的时序检查不正确。
我通常的做法是创建一个顶层的MBIST模式SDC文件,用include的方式把Tessent生成的文件和手写的补充约束整合在一起:
# mbist_mode_top.sdc set_case_analysis 1 [get_ports test_mode] source ./mbist_clock.sdc source ./mbist_mode.sdc source ./mbist_path.sdc source ./mbist_interface.sdc # 手写补充约束 set_clock_groups -asynchronous -group {test_clk} -group {scan_clk} set_input_delay -clock test_clk -max 5 [get_ports mbist_data_in*]4.2 约束检查与调试步骤
写完SDC后,不要急着跑完整的STA。先做几步检查:
第一步:检查时钟定义。用report_clocks确认所有时钟都被正确定义,频率、波形、分频关系都对。
第二步:检查case analysis。用report_case_analysis确认模式选择信号被正确固定,没有冲突或遗漏。
第三步:检查时钟分组。用report_clock_groups确认异步关系设置正确,没有把同源时钟误设为异步。
第四步:跑一次快速的时序分析。用check_timing和report_timing_requirements检查约束的完整性,看看有没有未约束的路径或者冲突的约束。
第五步:分析violation。如果有时序violation,先用report_timing -path_type full_clock_expanded看详细的路径信息,确认是真实的violation还是约束问题。
这个流程我跑过很多次,最花时间的通常是第五步。因为MBIST的violation往往不是单纯的时序问题,而是约束本身有问题。比如时钟定义错了、case analysis没设对、异步关系没声明,都会导致假violation。
4.3 一个真实的调试案例
去年做一个28nm的项目,MBIST模式下的STA一直报setup violation,路径是从MBIST控制器到memory的数据线。功能模式下这条路径没问题,MBIST模式下却差了0.3ns。
我先检查了时钟定义,发现MBIST控制器的时钟和memory的时钟虽然名字不同,但实际上是同源的,都来自测试时钟经过一个分频器。但SDC里把它们设成了异步时钟组,导致STA没有检查它们之间的时序关系,而是用了一个默认的时序检查,结果就报了violation。
解决办法是把这两个时钟从异步组里拿出来,用create_generated_clock重新定义它们的关系,确保STA知道它们是同源的。改完之后,violation消失了,因为实际的时序关系是满足的。
这个案例的教训是:不要想当然地设异步时钟组。每设一个异步关系,都要确认这两个时钟真的是异步的。同源的时钟,即使频率不同,也要用generated clock来描述它们的关系。
4.4 与功能SDC的共存策略
MBIST SDC和功能SDC的共存,是另一个容易出问题的地方。因为两种模式的约束可能冲突,比如同一个端口在功能模式下有input delay,在MBIST模式下也有input delay,但值不同。
处理策略有两种:
策略一:分文件、分模式。功能SDC和MBIST SDC分别放在不同的文件里,用不同的模式选择信号来区分。跑STA时,根据分析的模式读对应的SDC。这种策略的优点是清晰,缺点是如果两种模式有共享的约束,需要重复写。
策略二:单文件、条件约束。在一个SDC文件里,用if-else或者条件语句来区分模式。比如:
if {$mode == "mbist"} { set_input_delay -clock test_clk -max 5 [get_ports data_in*] } else { set_input_delay -clock func_clk -max 2 [get_ports data_in*] }这种策略的优点是约束集中,缺点是文件复杂,容易出错。
我个人的偏好是策略一,因为DFT模式和功能模式的时序分析通常是分开跑的,分文件更清晰,也更容易维护。但不管用哪种策略,都要确保两种模式的约束不会互相干扰。
5. 常见问题与排查技巧实录
5.1 MBIST SDC常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 大量setup violation集中在memory接口 | 时钟定义错误或异步关系误设 | report_clocks确认时钟关系 | 修正create_generated_clock或clock_groups |
| hold violation在测试模式下出现 | 时钟不确定性设置过小 | report_clock_uncertainty | 增大hold uncertainty |
| 某些路径没有被检查 | false path或multicycle设置过度 | report_timing_requirements | 移除不必要的false path |
| 模式切换后约束冲突 | case analysis设置错误 | report_case_analysis | 修正case analysis顺序或值 |
| 输入输出延迟不匹配 | ATE时序参数估计错误 | 对比ATE规格和SDC设置 | 根据实测调整delay值 |
| 时钟门控路径报violation | 门控使能信号未固定 | report_case_analysis | 用set_case_analysis固定门控使能 |
5.2 独家避坑技巧
技巧一:先跑功能模式,再跑MBIST模式。不要一上来就跑MBIST的STA。先用功能SDC跑一遍,确认功能时序没问题,然后再切换到MBIST模式。这样可以排除功能约束的干扰,更容易定位MBIST特有的问题。
技巧二:用report_clock_networks检查时钟传播。这个命令可以显示时钟从源到终点的完整传播路径,包括经过的mux、分频器、门控。如果时钟传播路径和预期不符,说明时钟定义有问题。
技巧三:对MBIST控制器的配置寄存器设multicycle。MBIST控制器的配置寄存器通常在测试开始前写入一次,不需要每个周期都检查。设一个较大的multicycle(比如100),可以避免不必要的violation。
技巧四:memory接口的时序约束要参考memory的datasheet。不同memory的setup/hold要求不同,不能一概而论。Tessent生成的约束通常是保守的,但最好根据实际memory的规格调整。
技巧五:保留一份约束的版本记录。MBIST SDC经常需要反复调整,每次调整都可能影响其他路径。保留版本记录,方便回溯和对比。
5.3 与Tessent工具的配合要点
Tessent工具在生成MBIST逻辑时,会同时生成一些约束模板。但这些模板往往需要根据实际设计修改。我通常的做法是:
- 先用Tessent生成的模板跑一遍STA,看看有哪些violation。
- 分析violation的原因,判断是约束问题还是真实的时序问题。
- 如果是约束问题,修改SDC;如果是真实的时序问题,反馈给前端或后端调整设计。
- 重复这个过程,直到STA收敛。
Tessent还提供了一些命令来辅助约束生成,比如report_mbist_clock和report_mbist_path。这些命令可以输出MBIST相关的时钟和路径信息,帮助确认约束的正确性。
注意:Tessent生成的约束模板可能不包含所有需要的约束,特别是时钟分组和输入输出延迟。这些需要手动补充。
5.4 跨时钟域路径的处理
MBIST模式下,跨时钟域路径的处理是个难点。因为MBIST控制器和memory可能在不同的时钟域,但它们之间的数据交换又需要检查时序。
处理原则是:同源的跨时钟域路径要检查,异步的跨时钟域路径要设false path或clock groups。
判断同源还是异步,要看时钟的源头。如果两个时钟都来自同一个测试时钟,只是经过了不同的分频器,那么它们是同源的,有确定的相位关系,需要检查时序。如果两个时钟来自完全独立的源,比如一个来自ATE,一个来自片上的PLL,那么它们是异步的,不需要检查时序。
对于同源的跨时钟域路径,要用create_generated_clock正确定义时钟关系,然后用set_clock_groups -logically_exclusive或者-physically_exclusive来声明它们不能同时有效(如果确实如此)。
6. 从约束到硅片:MBIST SDC的验证与签核
6.1 形式验证与动态仿真
SDC写完后,不能只靠STA来验证。形式验证和动态仿真是必要的补充。
形式验证方面,可以用CDC(Clock Domain Crossing)检查工具来验证时钟域交叉的正确性。这些工具可以检查是否有未同步的跨时钟域路径,以及同步器的正确性。
动态仿真方面,可以跑MBIST的测试向量,在仿真中检查时序。虽然仿真的时序精度不如STA,但可以发现一些STA覆盖不到的问题,比如复位序列、模式切换的时序等。
我通常的做法是:STA收敛后,跑一遍MBIST的仿真,确认功能正确。如果仿真中发现时序问题,再回头检查SDC。
6.2 硅片测试的反馈
MBIST SDC的最终验证,是硅片测试。如果硅片上MBIST测试通过,说明约束基本正确。如果失败,需要分析是约束问题还是设计问题。
硅片测试失败时,首先要确认测试条件是否和SDC中的假设一致。比如ATE的实际时钟频率、输入延迟、输出延迟是否和SDC中设置的一样。如果不一样,要调整SDC重新分析。
其次,要确认MBIST的测试算法和SDC中的约束是否匹配。不同的MBIST算法(如March C-、March SS等)对时序的要求可能不同。如果算法变了,约束也要相应调整。
6.3 签核清单
在tapeout前,MBIST SDC的签核清单包括:
- 所有时钟都被正确定义,包括测试时钟、生成时钟、门控时钟。
- 所有模式选择信号都被正确设置case analysis。
- 所有异步时钟域都被正确声明clock groups。
- 所有输入输出延迟都根据ATE规格设置。
- 所有multicycle和false path都有明确的理由和文档记录。
- STA在MBIST模式下收敛,没有未解释的violation。
- 形式验证和动态仿真通过。
- 约束文件有版本记录和变更日志。
这个清单看起来简单,但每一条都需要仔细确认。我见过太多项目因为漏了其中一条,导致硅片上出问题。
6.4 个人经验体会
做了这么多年DFT和时序约束,我最大的体会是:MBIST SDC不是写完就完事的,它是一个需要反复迭代和验证的过程。从Tessent生成模板,到手动补充约束,到STA收敛,到仿真验证,到硅片测试,每一步都可能发现问题,每一步都需要回头调整。
另一个体会是:不要怕麻烦,该画的图要画,该记的文档要记。MBIST的时钟架构往往比较复杂,光靠脑子记容易出错。画一张清晰的时钟架构图,标注每个时钟的来源、频率、分频关系,写约束的时候对照着看,能避免很多低级错误。
最后分享一个小技巧:如果STA报的violation太多,不知道从哪下手,可以先按时钟域分组,看看violation集中在哪个时钟域。通常问题最大的那个时钟域,就是约束最可能出错的地方。从那里开始排查,效率会高很多。
MBIST SDC这个领域,说难不难,说简单也不简单。关键是要理解MBIST的时钟架构,理解SDC的约束语义,然后耐心地一步步调试。希望这篇文章能帮你少走一些弯路,顺利搞定MBIST的时序收敛。