ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Tessent Mbist时钟架构与SDC约束实战详解

Tessent Mbist时钟架构与SDC约束实战详解 我最早接触Tessent Mbist的时候第一反应是“这不就是把memory包一圈BIST逻辑嘛约束能有多复杂”。结果真正开始做时序收敛、跑DRC、搞pattern的时候被时钟架构和SDC配合教育得服服帖帖。Mbist这套东西功能逻辑固然是核心但真正决定你项目能不能按时signoff的往往是时钟怎么布置、SDC怎么写。这篇笔记就是把我在Tessent Mbist上关于时钟架构和SDC约束的理解做一次梳理适合正在做DFT集成、或者准备上手Mbist但还没被时钟绕晕的工程师。先说清楚一个概念MbistMemory Built-In Self-Test是用来给片上memory做生产测试的。它在你原本的功能逻辑之外插入一段测试控制逻辑通过一段固定的状态机序列对memory阵列进行读写、比对从而判断memory有没有制造缺陷。整个过程需要一组独立的测试时钟和测试控制信号来驱动这些时钟的走法、来源、约束方式直接决定了insertion之后功能逻辑会不会被影响、测试pattern能不能稳定工作、DFT DRC能不能干干净净地过。换句话说时钟架构是Mbist这栋房子的地基SDC是地基里的钢筋缺一不可。这篇内容我尽量用实际项目里会遇到的说法来讲不堆术语。如果你已经用Tessent做DFT有一阵子了可以直接跳到时钟架构拆解和SDC实操那两节如果你刚入门建议从头看节奏不快每一段都值得细读。1. 整体思路拆解为什么Mbist的时钟问题值得专门写一篇1.1 Mbist时钟和功能时钟的本质差异功能模式下memory的时钟来自芯片内部的PLL、分频器、门控时钟树整个时钟路径是设计团队花了大精力去平衡的skew、jitter、latency都有严格管控。Mbist插入之后测试模式下的时钟路径完全变了样——测试时钟经过Tessent内部逻辑重新分配、分频、门控再送到memory的时钟端口上。这条新的时钟路径功能模式根本不存在所以SDC里如果没有做对应的声明工具只能靠猜猜出来的约束往往既不准确也不安全。我做过一个项目Mbist insertion之后功能pattern的时序报告突然多出一堆violation查了半天最后发现是Mbist controller插入时把memory clock路径上的一个buffer替换掉了导致原本平衡的时钟树被打破。这个问题的根源就是插入逻辑之后工具对新增时钟路径没有正确的约束认知于是时序优化时做了错误的假设。Mbist的时钟还有一个特点它通常不是直接从外部引脚进来的而是在芯片内部经过Tessent逻辑再生成。这意味着传统SDC里那种“create_clock 在端口上然后一路 propagate”的思路在Mbist里经常会失效——因为内部生成的时钟工具不会自动知道它的周期和相位。1.2 理解SDC约束在Mbist里的角色SDCSynopsys Design Constraints对于Mbist来说不只是给STA用的它还承担着告诉工具“哪些时钟是真实存在的、哪些时钟是异步关系、哪些路径需要被检查”的责任。在Tessent的流程里SDC还会被用来指导pattern生成时的时钟捕获沿选择、DRC检查时的时钟域判断。换句话说SDC写对了后面的流程是顺水推舟SDC写漏了后面全是救火。我见过有人在Mbist里把memory的刷新时钟refresh clock漏定义了结果pattern仿真的时候memory数据莫名其妙丢失查了整整两天才定位到问题。这种坑写SDC的时候多花十分钟就能省下后面几十个小时的debug时间。2. 时钟架构拆解Tessent Mbist里的时钟到底怎么走2.1 从外部引脚到memory时钟端口的完整路径要理解Mbist的时钟架构最好从一条完整的时钟路径看起。以一个典型的SoC为例外部或内部PLL产生的时钟经过测试时钟引脚或功能时钟引脚复用进入芯片到达Tessent的Mbist controller。在controller内部时钟经过分频、门控、选择逻辑产生BIST_CLKBIST时钟和相关的控制时钟最后送到各memory group的时钟端口。这条路径上有几个关键的“中间人”PLL/分频器决定了Mbist工作频率的基准。Mbist controller本身通常支持可配置的分频比用来适配不同memory的最高工作频率。时钟门控单元Mbist模式下门控逻辑由Tessent controller的控制信号比如pause、hold驱动用于在特定周期暂停时钟以便完成memory的特定操作序列。时钟选择器MUX负责在功能时钟和测试时钟之间切换。这个MUX的控制信号通常来自TDRTest Data Register或用户自定义的控制寄存器。如果这个过程没有在SDC里做完整的声明STA工具会把这条内部生成的时钟当成ideal network来处理或者干脆报告no clock。实际项目里这种问题表现出来就是Mbist controller内部逻辑的timing一片绿但memory接口上的hold time violation多到哭。2.2 Tessent内部的几类关键时钟信号在Tessent Mbist的环境里有几类时钟信号是必须分清楚的。下面我用一个表格来整理方便对照记忆。信号类别典型命名来源用途SDC处理方式测试主时钟TCK / BIST_CLK外部引脚或PLL驱动Mbist controller状态机create_clock在端口后续由工具推断用户自定义时钟user_defined_clockPLL/分频器驱动memory时钟端口create_generated_clock或直接定义内存时钟memory_CLK经Mbist controller输出驱动memory阵列时钟与用户自定义时钟同步/异步约束刷新时钟refresh_CLK与memory时钟同源控制memory刷新逻辑需与memory时钟定义清楚关系TDR时钟tdr_clockJTAG或测试接口驱动TDR寄存器通常与memory时钟异步这类命名的细节在不同Tessent版本里略有差别但核心思路是一致的Mbist环境里的时钟分两大类一类是工具自己能认出来的比如TCK、tdr相关的另一类是需要你显式告诉工具的比如memory时钟、用户自定义时钟。凡是需要显式定义的漏掉一个后面都会以某种形式来找你麻烦。2.3 多Mbist group之间的时钟隔离实际的SoC里不会只有一个Mbist controller。大的设计里可能有几个group每个group负责一组memory各自有独立的Mbist controller和时钟路径。group与group之间的时钟可能同源也可能来自不同的PLL甚至频率完全不同。这就是SDC里set_clock_groups要发挥作用的地方。如果group A和group B的时钟是异步的但你只写了“两个时钟存在”却没有声明它们是异步关系工具会默认它们是同步的然后老老实实地去检查group A到group B之间的时序路径——结果往往是满屏的violation而且这些violation毫无实际意义。我当时做的一个项目里就因为漏了一条set_clock_groups -asynchronous导致Mbist插入后的DRC报告里冒出来几千条violationRed级问题一大堆。加完约束再跑干干净净。这件事让我养成了一个习惯写完SDC的第一件事就是检查有没有把该隔离的时钟域都隔离干净。3. SDC约束实操从模板到落地的完整过程3.1 起步一个实用的SDC基础模板Mbist的SDC约束通常不是从零开始写的。Tessent flow里一般会有一个模板或者在insert_mbist的时候生成一个初步的SDC你需要做的是把它补全。下面是我常用的一个基础框架你可以作为起点来参考。# 1. 定义基本时钟测试主时钟 create_clock -name TCK -period 20 [get_ports TCK] # 2. 定义用户自定义时钟memory的输入时钟 # 假设mbist_clk是经过PLL分频后从特定端口进来的时钟 create_clock -name mbist_clk -period 10 [get_ports mbist_clk] # 3. 定义由mbist_clk分频产生的memory时钟 create_generated_clock -name mem_clk_2x \ -source [get_ports mbist_clk] \ -divide_by 2 [get_pins u_mbist_ctrl/clk_div/clk_out] # 4. 异步时钟域约束 set_clock_groups -asynchronous \ -group {TCK} \ -group {mbist_clk mem_clk_2x} # 5. 测试控制信号的时钟约束 set_case_analysis 0 [get_ports scan_enable] set_case_analysis 0 [get_ports mbist_enable]这个模板只覆盖了最基本的内容。真正写的时候你还需要考虑复位信号、TDR时钟、memory接口上的各类控制信号以及Mbist的多个group之间如何交互。3.2 核心约束详解create_generated_clock在Mbist里的特殊用法create_generated_clock是Mbist SDC里最常用也是最容易出错的命令。它用来定义一个由其他时钟派生出来的时钟关键是要指定source源时钟和分频/倍频关系。Mbist里典型的使用场景是这样的输入时钟是100MHzMbist controller内部做2分频得到50MHz的memory时钟。在SDC里你需要把这个内部生成的分频时钟用create_generated_clock声明出来这样工具才会正确计算skew和timing。实际操作中我遇到过一个问题有时候分频器不在Mbist controller内部而是在PLL后面、进入Tessent逻辑之前的公共路径上。这时候create_generated_clock的source不能只指到分频器输入端的那个pin还需要用-master_clock指定是谁的master clock。如果你漏了这个参数工具可能会报告ambiguous clock reference或者干脆把分频时钟当成一个独立的未知时钟处理。3.3 时钟域约束哪些要设asynchronous哪些要设logically_exclusiveMbist环境下的时钟域关系本质上就三类同步、异步、逻辑互斥。在SDC里分别对应set_clock_groups的-synchronous其实是默认的行为不需要显式声明、-asynchronous和-logically_exclusive。异步关系两个时钟没有固定的相位关系比如TCK和memory时钟。这类要设-asynchronous告诉工具“这两个时钟域之间的路径不用检查”。逻辑互斥两个时钟不会同时有效比如功能时钟和测试时钟二者通过MUX选择物理上不会同时驱动同一路径。这类要设-logically_exclusive同时还需要注意MUX选择端口的case_analysis也要配合设好。同步关系时钟之间有明确的相位关系比如分频时钟和它的源时钟。这类不需要额外约束但最好确认一下SDC里没有误设成异步。有一个细节值得强调Mbist里的memory时钟和Mbist controller的时钟在功能模式与测试模式下可能分别来自不同的源所以严格来说它们之间是逻辑互斥关系不是异步关系。这两个词在SDC里的含义差别很大写错一个工具的行为会完全不同——设成logically_exclusive工具会尝试做时钟MUX的时序分析设成asynchronous工具会直接跳过路径检查。别问我是怎么知道这个区别的问就是被DRC Red报告教育过。3.4 约束mbist专用信号scan_enable、mbist_enable、tck、tdr除了时钟本身Mbist环境里还有一批关键的测试控制信号它们的约束方式直接影响pattern的正确性。scan_enable在功能模式下必须设0case_analysis 0在shift模式下设1。Mbist controller的模式切换逻辑通常受scan_enable控制所以这个约束没设对后面跑的pattern就是废的。mbist_enable是Mbist模式的使能信号。Mbist pattern执行期间它应该是1。这个信号的case_analysis也要写清楚否则STA会认为pattern期间的路径是无效的。tdr_clock和tck通常跟JTAG接口相关。如果你的Mbist控制器是通过TDR配置的那么TDR时钟的约束也不能漏。这里有一点要注意tdr_clock和memory时钟通常是完全不同的频率甚至不同的时钟域务必在set_clock_groups里把它们隔离掉。我在一次项目里就是因为mbist_enable的case_analysis没设结果DFM工具在做Mbist pattern仿真时把功能逻辑的时序也带进去了整个仿真跑得奇慢无比而且报了一堆奇怪的X态冲突。加了约束之后仿真时间直接砍半。4. 实操过程一个单group Mbist项目从零到约束收敛的记录4.1 案例背景与初始条件用一个实际的例子来讲。假设我们有一个SoC内部有一个memory group包含8个单端口SRAM最高工作频率是50MHz。Mbist controller的输入时钟来自PLL的100MHz输出通过一个专门引脚进来我们叫它pll_clk_mbist。外部还有一个测试时钟TCK频率20MHz用来配置TDR。芯片还有个scan_enable信号在测试模式下由ATE控制。在这个场景里约束的目标很清楚让STA工具知道pll_clk_mbist产生了一个二倍分频的memory时钟TCK是独立的异步时钟scan_enable和mbist_enable在特定模式下是恒定值。只要把这些信息完整地表达在SDC里后面的流程就会顺畅很多。4.2 SDC编写过程与每一行的理由第一步定义端口上的主时钟。create_clock -name pll_clk_mbist -period 10 [get_ports pll_clk_mbist] create_clock -name TCK -period 50 [get_ports TCK]pll_clk_mbist的周期是10ns对应100MHz。TCK周期50ns对应20MHz。这两个端口时钟先声明好作为后续所有内部时钟的源头。第二步定义Mbist controller内部生成的memory时钟。假设Mbist controller内部有一个u_mbist_ctrl/u_clk_divider/clk_out引脚输出的是pll_clk_mbist的二分频信号也就是50MHz。create_generated_clock -name mem_clk \ -source [get_pins u_mbist_ctrl/u_clk_divider/clk_in] \ -divide_by 2 [get_pins u_mbist_ctrl/u_clk_divider/clk_out]这里有个细节source引脚写的是分频器的输入而不是pll_clk_mbist的端口。这样做的好处是工具可以正确计算从pll_clk_mbist端口到分频器输出之间的延迟从而算出mem_clk的实际到达时间。如果你直接写-source [get_ports pll_clk_mbist]工具也能工作但latency的准确性会差一些。第三步声明时钟域关系。set_clock_groups -asynchronous \ -group {TCK} \ -group {pll_clk_mbist mem_clk}这里把TCK和mbist相关的时钟全部隔离开。理由是TCK来自JTAG测试接口pll_clk_mbist来自芯片内部PLL两者没有任何确定的相位关系。不隔离的话工具会试图检查TCK到Mbist controller之间的路径而这些路径上常常存在异步FIFO或跨时钟握手逻辑属于假路径检查了也是白检查还不如直接设掉。第四步设定测试控制信号。set_case_analysis 0 [get_ports scan_enable] set_case_analysis 0 [get_ports mbist_enable]这条约束的意思是在功能模式下scan_enable和mbist_enable都是0。这样工具在分析功能路径时不会把Mbist controller的测试路径混进来。等到做DFT模式分析时再通过其他约束切换。写完这四步SDC的基础就成型了。实际项目里当然还有其他细节比如复位信号的处理、memory内部时钟如果有BIST专用的内部时钟的约束、多group之间的隔离等但核心框架就是这个。4.3 插入Mbist后SDC需要做的增量调整Mbist insertion之前和之后SDC的写法有一些差别。插入之前Mbist controller还不存在你只需要约束外部引脚和功能时钟插入之后controller实例出现了你需要为这些新出现的内部寄存器、分频器补充约束。比较常见的增量调整包括给Mbist controller内部生成的时钟加约束。这通常发生在u_mbist_ctrl这个实例内部需要找对分频器的输出pin然后用create_generated_clock声明。给Mbist controller的复位信号加约束。Mbist controller通常有自己的复位逻辑由TDR或外部引脚控制。复位信号的release时间需要满足时序要求这个约束不写复位可能释放过早或过晚。给Mbist controller的输出端口比如memory的clock、enable、write enable加约束。这些端口在功能模式下是悬空的但在Mbist模式下有真实时序要求。有一个实操技巧insert_mbist完成之后可以用Tessent的报告命令比如report_timing -through快速检查当前SDC是否已经覆盖了所有memory的clock路径。如果report里出现no clock或unconstrained的提示多半是SDC还没补全。5. 常见问题与排查技巧时钟约束的坑,我替你踩过了5.1 问题速查表我把做Mbist时钟约束时比较容易踩的坑整理成了一个速查表方便你遇到问题的时候快速排查。现象可能原因排查思路解决方案Mbist controller内部时序violation一片红分频时钟未定义或定义错误检查report_clock看mem_clk是否存在且周期正确用create_generated_clock补定义注意source选择memory接口hold violation特别多clock uncertainty或者latency设置不合理检查memory时钟的latency和skew计算检查clock latency调整set_clock_uncertaintypattern仿真时memory读出数据全Xrefresh clock未约束或约束错误检查refresh clock的仿真波形在SDC中定义refresh clock确认其周期与memory规格匹配DRC报告跨group违例group之间时钟域未隔离查看violation路径的起点和终点在哪个group用set_clock_groups -asynchronous隔离group之间时钟Mbist模式下的功能逻辑时序崩溃mbist_enable的case_analysis未设置检查mbist_enable是否在SDC中设定恒定值增加set_case_analysis约束必要时分模式写SDC仿真出现大量X态传播复位信号约束不完整查看复位Release时序是否满足要求增加set_case_analysis和复位释放时序约束5.2 排查工具与脚本建议排查Mbist时钟问题最常用的还是Tessent自带的报告命令以及STA工具本身的时钟报告。我用得最多的几个命令分享给你# 查看当前设计中有哪些时钟 report_clock # 查看指定时钟的详细信息包括source、周期、waveform report_clock -verbose [get_clocks mem_clk] # 查看时钟域之间的关系 report_clock_groups # 检查哪些path没有被约束 report_timing -unconstrained_paths # 查看某个pin上工具认为的时钟是什么 report_clock -skew [get_pins u_mbist_ctrl/u_clk_divider/clk_out]这三板斧下来至少80%的时钟约束问题都能定位到具体原因。剩下20%的问题多半是跟具体设计绑定的需要结合RTL和仿真波形一起看。5.3 一个真实的排查过程复盘有一次我接手一个项目mem_clk的约束看着都写了但仿真跑pattern时memory 的地址信号在特定周期出现了未知态数据读取不稳定。一开始怀疑是memory模型的问题花了不少时间看仿真波形后来才发现根源在Mbist controller 的 data_bist_out 路径上——那条路径的时钟约束被工具识别成TCK了导致时序分析时用了完全错误的clock。排查的过程很朴素先用report_timing查那个路径的clock信息发现工具的认知和我的预期不一致。再追踪到约束文件发现create_generated_clock的source选错了引脚指到了分频器输出而不是输入。修正之后重新跑仿真问题消失。这件事给我最大的教训是Mbist时钟约束写完之后务必用report_clock把工具认为的时钟结构和你自己脑子里的结构对一遍。工具不会提醒你“你的source选错了”它只会按你给的约束干活然后在一百个看似无关的地方挂掉。检查手段其实很简单cost不高收益却很大。5.4 与SSNShared Scan Network的配合注意事项如果你的项目用了Tessent SSNShared Scan Network共享扫描网络Mbist时钟约束还要额外留意几个点。SSN环境下不同block之间的时钟树结构会有共享Mbist controller的时钟路径可能会和其他block的测试时钟有交集。这里我最想提醒的是SSN模式下SDC的读入顺序可能影响约束效果。比如某个clock group先被定义后续的create_generated_clock引用它如果顺序反了工具会报unknown object。排查这种问题多看一眼constraint file的加载顺序就能定位。另外SSN环境下mbist_clk和scan_clk扫描时钟之间往往是逻辑互斥关系而不是异步关系。写SDC时要特别注意不要误设成asynchronous否则pattern生成工具可能会认为mbist路径的时钟关系不明确产生次优的capture方案。6. 实际操作中的心得体会和后续扩展时钟约束这部分写的时候总觉得差不多就行但每一次项目落地都会冒出新的问题。我个人的体会是Mbist的SDC约束本质上是在“告诉工具这个测试场景下的真实物理世界是什么样的”。你写得越接近物理现实后面的时序分析就越可靠DRC越干净pattern仿真越顺利。反之SDC里一个不起眼的疏忽可能要用几十小时的debug来还。最后分享一个小技巧。Mbist插入完成后我会把SDC里所有涉及memory接口的约束单独整理成一个文件然后在主SDC里用source命令引入。这样做的好处是当memory接口发生变化或者需要针对不同memory group调整约束时不用在主SDC里翻来翻去改一个小文件就够了。这个习惯帮我省了不少时间推荐你也试试。这一篇算是我Tessent Mbist学习笔记的“-0”先把时钟架构和SDC约束的主线理清楚。接下来如果时间允许我打算继续写insertion的具体步骤、pattern生成和仿真验证、Mbist controller与TDR配置的细节等等。这些内容环环相扣每拆开一个部分都会发现新的坑和新的解法。希望这些笔记也能帮到正在跟Mbist缠斗的你。
返回列表