
1. 为什么set_dft_signal是DFT约束中踩坑率最高的命令做DFT综合的工程师应该都有这种体会DC综合流程里set_dft_signal这行命令看起来平平无奇无非就是告诉工具哪些信号是扫描时钟、哪些是扫描使能、哪些是测试模式。但实际项目中因为这条命令配置不当导致的DRC违例、扫描链插入失败、覆盖率不达标、甚至流片后ATE测试才发现问题的案例我这些年见了不下两位数。说实话DFT的坑很多但set_dft_signal的坑属于隐蔽性最强的那一类。原因很简单它配错了往往不会立即报错工具会照常跑完综合、完成扫描链插入看起来很顺利。直到你开始做dft_drc检查或者后端做完时钟树后做仿真甚至等到封装回来上ATE测试时问题才像火山一样爆发出来。到这个阶段再回去查配置排查路径已经长得让人头皮发麻。1.1 它在DC DFT流程中的真实职责先理清set_dft_signal在整个流程里的位置。一个典型的DC DFT综合流程大概是这样read_verilog rtl_top.v link current_design rtl_top set_dft_config -scan_serialization_style multiplexed_flip_flop set_dft_signal -view spec -type ScanClock -port clk -active_state 1 set_dft_signal -view spec -type ScanEnable -port scan_en -active_state 1 set_dft_signal -view spec -type TestMode -port test_mode -active_state 1 set_dft_signal -view spec -type ScanDataIn -port scan_in set_dft_signal -view spec -type ScanDataOut -port scan_out dft_drc insert_dftset_dft_signal干的事是把你设计里跟测试相关的所有信号的角色告诉工具这些信号在测试模式下分别充当什么工种。它管理的信号类型包括但不限于ScanClock扫描时钟、ScanEnable扫描使能、TestMode测试模式、ScanDataIn扫描数据输入、ScanDataOut扫描数据输出、Reset复位、Constant常量、MasterClock主时钟、CaptureClock捕获时钟。每个类型背后的语义都不一样而且它们之间还有隐含的相互制约关系。比如ScanClock定义得不完整直接影响扫描链上所有触发器能否正常移位和捕获TestMode定义得不正确可能导致工具把功能逻辑误当作DFT逻辑来优化。这也是为什么我强烈建议写set_dft_signal之前先把手头设计的时钟结构、复位结构和测试端口梳理清楚而不是想到哪写到哪。1.2 一条命令管理所有测试信号选项组合很容易配错set_dft_signal的选项组合非常多稍微不注意就会翻车。核心选项大概有这些选项作用备注-view指定信号的视图spec/existing_dft/non_dft最容易混淆的选项-type指定信号类型决定信号在DFT中的角色-port/-pin/-hookup_pin指定连接的端口或pin三种指定方式适用场景不同-active_state有效电平0或1必须与RTL实际逻辑一致-usage使用方式scan/clock/hold_time影响工具对信号的处理策略-create_port自动创建测试端口复用到功能端口时慎用-test_clock标记测试时钟PLL/分频时钟场景常用-hierarchy_clock标记层级时钟跨模块时钟时涉及一个真实项目中往往要写几组甚至十几组set_dft_signal。比如处理器类芯片主时钟、总线时钟、外设时钟、PLL参考时钟每一路时钟都要考虑在测试模式下如何约束每个IO复用端口都要决定是复用为扫描输入、扫描输出还是保持功能模式。我在一个28nm的MCU项目上就遇到过这种情况设计里有PLL产生的CPU时钟、一个低速的RTC 32K时钟还有一个外部SPI接口。一开始我只定义了CPU时钟为ScanClockRTC端口直接复用为扫描端口结果dft_drc报了一大堆时钟相关违例查了半天才发现32K时钟在测试模式下完全没被约束成扫描时钟导致跨时钟域的触发器在移位阶段全乱了。后来补上这路时钟的定义DRC瞬间干净。1.3 配错的后果有延迟性这是set_dft_signal最坑的一点错误不是当场报出来的。比如你把ScanEnable的有效电平配反了工具在做insert_dft时可能根本不会报错扫描链照样给你stitch上。到了dft_sim阶段测试向量跑移位测试发现第二个时钟周期数据就全乱了。如果是低有效配成了高有效逻辑上等于整个扫描链的使能信号永远处于无效状态实则是所有扫描单元彻底罢工。再比如TestMode信号如果定义得不对工具在做DFT优化时可能不会把测试模式下的恒值逻辑比如某些控制信号在测试模式下拉死到0正确约束住后仿真时这些节点浮空或者受功能逻辑影响直接导致ATE上测试失败。这类问题往往要到芯片回来了才知道修改代价巨大。所以我的经验是set_dft_signal的配置时间在整个DFT流程里应该占到三分之一以上。前端把RTL吃透端口梳理清楚配置写得细后面的DRC和仿真阶段就能省掉非常多的返工时间。2. 扫描时钟与扫描使能的典型配置与常见误区扫描时钟ScanClock和扫描使能ScanEnable是set_dft_signal里最核心、也最容易犯错的两个类型。几乎每个设计都要用但几乎每个设计都会在这两个信号上出过这样那样的问题。2.1 最标准的一组配置示例先给一个最朴素的完整配置示例单时钟域、独立测试端口的情况set_dft_config -scan_serialization_style multiplexed_flip_flop set_dft_signal -view spec -type ScanClock -port clk -active_state 1 set_dft_signal -view spec -type ScanEnable -port scan_en -active_state 1 set_dft_signal -view spec -type TestMode -port test_mode -active_state 1 set_dft_signal -view spec -type ScanDataIn -port scan_in set_dft_signal -view spec -type ScanDataOut -port scan_out set_dft_signal -view spec -type Reset -port rst_n -active_state 0这组配置的含义是clk在测试模式下作为扫描时钟scan_en高有效作为扫描使能test_mode高有效进入测试模式scan_in/scan_out分别作为扫描链的串行输入输出rst_n低有效作为异步复位。看起来很简单对吧但有一个细节值得注意这里的-test_type和-usage没写工具默认按照scan方式处理时钟。如果你在多个时钟域下使用不同的时钟作为扫描时钟就需要额外的约束来明确它们之间的关系比如哪个是主时钟、哪个是捕获时钟、是否需要在移位阶段保持稳定这些要靠-usage和-timing选项来补充。2.2 active_state选1还是0active_state是我见过翻车最多的地方。很多人默认扫描使能都是高有效看到RTL代码里写的是scan_enable信号就直接配了-active_state 1。但如果RTL里实际逻辑是assign scan_en_n ~scan_enable或者某些DFT MUX的控制端是低有效配高有效就等于整个扫描链使能信号永远不对DRC可能在内部逻辑上能过但仿真完全跑不通。这里我的建议是配之前一定去RTL里确认信号的最终控制逻辑。不要只看端口名要看这个信号真正作用在扫描MUX、ICG门控单元或异步复位端上的那一级逻辑。有的设计为了方便后端布局会在靠近叶节点的地方做一次反相导致顶层端口有效电平和内部实际有效电平不一致。这种情况如果直接在顶层配active_state肯定会出问题。我踩过的坑一个设计里scan_enable是顶层输入经过两级缓冲后接到扫描MUX其中第二级缓冲是反向的等效于内部低有效。我当时没仔细看直接配了高有效。结果dft_drc的setup阶段查不出来到了测试向量仿真阶段shifting的时候数据完全乱掉。排查了很久才发现是有效电平的问题。这个教训让我养成了一个习惯配置完之后一定用report_dft_signal去看工具实际解析出来的信号属性再做一遍交叉核对。2.3 负沿时钟与门控时钟的处理很多工程师只定义了正沿时钟作为ScanClock忽略了设计中真正存在的负沿时钟。如果你设计里有使用负沿触发的触发器而扫描时钟只定义了正沿工具在insert_dft时会用正沿时钟去驱动这些负沿触发器DRC会报出时钟沿不匹配的违例。处理方式是在set_dft_signal里直接用port上的反相来表示set_dft_signal -view spec -type ScanClock -port clk -active_state 1如果负沿触发器确实存在工具会自动识别并处理但前提是DRC允许。如果你的设计风格是混合沿触发器混用最好在RTL阶段就统一改成同沿触发DFT阶段再处理就是给自己上强度。门控时钟ICG是另一个高频坑区。现在很多设计为了低功耗大量使用ICG单元做时钟门控。在测试模式下如果ICG的使能端被功能逻辑控制扫描时钟就可能在某些触发器上完全丢失导致移位失败。DC DFT工具提供了自动修复机制关键在set_dft_config里打开set_dft_config -fix_clock_enable true打开这个选项后工具会在测试模式下把ICG的控制端强制拉成有效状态确保扫描时钟能穿过门控到达所有触发器。但有个前提你需要在set_dft_signal里把TestMode信号配好工具才能利用测试模式信号去做这个强制。这两个配置是耦合的少一个都不行。2.4 时钟配置的完整性检查时钟配置完成后强烈建议用报告命令做一次确认report_dft_signal这个报告会把当前设计里所有已经配置的DFT信号列出来包含类型、端口、有效电平、视图等。检查要点有这几个所有主时钟是否都定义成了ScanClock分频时钟/派生时钟是否也纳入了扫描时钟体系ScanEnable和TestMode的有效电平是否与RTL一致复位信号是否配置成了Reset类型且有效电平正确是否有端口遗漏了DFT定义特别是IO复用的端口我一般会在写完所有set_dft_signal后直接跑一次这个命令把输出存成log和RTL里定义的测试端口清单逐项核对。花不了多少时间但能拦截掉大部分低级错误。3. TestMode信号与-view三大状态的选型逻辑如果说ScanClock和ScanEnable是set_dft_signal的面子那-test_view就是里子。不夸张地说view选错是所有DFT配置错误里最隐蔽、最难查的一种。3.1 -view spec、existing_dft、non_dft到底什么区别用生活化的话来解释spec是计划existing_dft是现状non_dft是无关。-set_dft_config对比来说-view spec是告诉工具我期望这些信号在DFT实现后应该长这样你在insert_dft的时候帮我实现出来。大多数纯逻辑设计都用spec视图工具会在扫描链插入阶段按照你定义的spec去把测试端口和内部逻辑连接好。-view existing_dft则是告诉工具这些DFT逻辑已经在设计里物理存在了你不需要帮我再实现一遍只要识别并利用它们就行。典型场景是RTL里已经手动插好了扫描MUX或者从IP供应商拿到的第三方模块内部已经含有一套DFT结构。这时候如果你再用spec去定义等于要求工具再插一遍反而搞出一堆重复逻辑。-view non_dft是告诉工具这些信号跟测试无关你离它们远点。比如某些常开或者常关的控制信号测试模式下不参与任何扫描逻辑用non_dft标记后工具就不会动它们。三者关系我用表格理一下视图语义insert_dft时的行为典型场景spec期望的DFT规范工具自动实现连接纯逻辑标准单元设计existing_dft已有DFT结构识别但不再插入RTL手工MUX、第三方IPnon_dft与DFT无关不处理功能常值控制信号3.2 什么时候必须用existing_dft我在一个AI加速器项目上遇到过这种情况RTL工程师为了控制时序已经手工在关键路径上插好了扫描MUX而且部分扫描链在RTL阶段就预先连好了。我在综合时如果还用spec视图去定义ScanDataIn和ScanDataOut工具会在已有MUX的基础上再插一遍等于双重插入逻辑直接错乱。正确的做法是手工MUX部分的信号用existing_dft视图定义告诉工具扫描结构已经在设计里你在DFT阶段负责识别和优化但不要再重复插入。这样工具才不会画蛇添足。怎么判断设计里有没有现成DFT逻辑最简单的方式是检查RTL里有没有类似test_mode ? scan_in : functional_signal的三目运算或MUX结构以及在综合后的网表里用all_connected查询相关信号的连接关系。3.3 view混用的后果一个设计里可以同时存在多个view的信号这是完全合法且常见的。但混用的时候有一个很容易踩的坑同一个信号被重复定义。比如你最开始用spec定义了scan_en后面对接了第三方IP这个IP内部也有一根口头上叫scan_en的信号你又在IP的边界上用existing_dft定义了它。如果两者的有效电平和端口定义不一致工具后定义的可能覆盖前定义导致整条扫描链使能逻辑混乱。这种冲突DRC往往查不出来因为这个信号内部一致性是满足的但你的设计意图被覆盖了。排查起来相当痛苦因为网表里看起来两个地方都是scan_en但语义完全不同。我的经验是在统一的设计约束文件里管理所有set_dft_signal每个信号定义后加注释标注来源和用途。如果同一个端口名在多个地方出现必须确认它们的定义逻辑一致。真遇到不一致的情况宁可把其中一边的名称改掉也不要让工具在模棱两可的状态下做自动推断。4. 多时钟域与IO复用场景的实战配置到了这个章节基本就开始接触真实项目的复杂度了。单时钟域、独立测试端口的设计在现在的SoC里几乎不存在多时钟域、IO复用才是常态。4.1 PLL输出时钟与分频时钟的test_clock配置带PLL的设计核心时钟往往来自PLL输出。在功能模式下PLL会产生高频时钟但在DFT测试模式下测试时钟通常由外部ATE直接提供PLL输出时钟不一定稳定甚至PLL本身在测试模式下会被旁路。这时候的配置策略是外部ATE输入的参考时钟作为ScanClockPLL输出的派生时钟用-test_clock标记同时用-set_dft_signal的-timing选项指定它们之间的时序关系。一个具体例子set_dft_signal -view spec -type ScanClock -port clk_ref -active_state 1 set_dft_signal -view spec -type ScanClock -port pll_out -active_state 1 -test_clock set_dft_signal -view spec -type ScanEnable -port scan_en -active_state 1 set_dft_signal -view spec -type TestMode -port test_mode -active_state 1这里把pll_out定义为test_clock的意义是告诉工具pll_out时钟在测试模式下可以不必完全满足正常扫描时钟的所有约束它在捕获阶段由内部逻辑提供不参与移位段的高频切换。如果你不这样配置工具会按照标准扫描时钟来要求pll_out的时序结果往往是大量时序违例DRC过不去。分频时钟的处理也类似。假设设计里有clk_div2、clk_div4这样的分频时钟它们通常是主时钟的派生时钟。DFT配置时有两种选择一种是把它们直接定义成ScanClock另一种是做合并时钟处理。如果分频器在测试模式下能被TestMode信号强制成已知状态建议用set_dft_config里的-internal_clock配合处理如果分频器本身要被扫描覆盖那这些分频时钟确实也需要作为ScanClock来约束否则分频器上的触发器在移位阶段没有时钟可用。4.2 复用功能IO作为扫描IO的配置现代芯片几乎不会为扫描单独预留一组完整IO绝大多数情况是复用功能IO。复用就带来配置上的讲究。假设功能端口gpio[3:0]在测试模式下兼任扫描输入输出口配置可以这样写set_dft_signal -view spec -type ScanDataIn -port gpio[0] -usage scan set_dft_signal -view spec -type ScanDataIn -port gpio[1] -usage scan set_dft_signal -view spec -type ScanDataOut -port gpio[2] set_dft_signal -view spec -type ScanDataOut -port gpio[3]这里的关键是-usage scan它告诉工具这个端口在功能模式下还有别的用途但DFT阶段作为扫描端口使用。工具在insert_dft时会建立好复用逻辑确保功能模式和测试模式下端口行为不冲突。如果是三态IO复用还需要考虑输出使能信号在测试模式下的状态。很多工程师漏配了这一步导致扫描输出端口在测试模式下处于高阻态ATE读取不到数据。处理办法是把测试模式下IO的OE信号用TestMode强制成有效输出状态或者把OE信号本身也纳入DFT约束体系。4.3 复位与常量信号的DFT约束复位信号的配置也是一个大项。异步复位的触发器在扫描模式下必须确保复位端不会中途被激活否则扫描链移位时触发器被意外清零数据就丢了。处理方式是set_dft_signal -view spec -type Reset -port rst_n -active_state 0工具会识别这个复位信号并在测试模式下将其控制在无效状态。如果你的设计里还有类似在测试模式下把某个信号拉成固定值的需求可以用Constant类型set_dft_signal -view spec -type Constant -port tie_high_in_test -active_state 1这种Constant信号通常用在测试模式下需要固定电平的控制线上。比如某些总线仲裁逻辑在扫描测试时我们希望它不动作就可以在TestMode有效时把它钳制到固定值。多时钟域下每个时钟域都有自己的复位很常见。复位信号配置时需要注意如果异步复位来自不同源工具无法自动将它们归并为一类需要分别配置。同时建议检查复位信号是否真正到达了所有需要复位的触发器有些触发器是同步复位配置时就该用别的处理方式而不是简单标记Reset类型。5. 配置完以后必须做的三件事从报告自查到DRC排查set_dft_signal配置完成不代表事情结束了。恰恰相反真正的调试工作从这里才开始。我每次配置完至少要完成三个步骤才敢放心往下走。5.1 report_dft_signal自查第一步永远是report_dft_signal。我会把完整输出拉出来对着设计文档逐一核对。重点核对以下内容每个DFT信号是否出现在预期的端口上有效电平是否与RTL一致view类型是否符合设计实际情况ScanClock是否覆盖了所有时钟域ScanEnable和TestMode是否都正确配置了这一步花的时间不多但能拦截掉90%的低级错误。尤其是多个工程师协作的项目不同模块的DFT配置可能由不同人负责合并时很容易出现定义冲突报告里会直接暴露出来。5.2 dft_drc预检与violation排查第二步是跑dft_drc。这里有个重要经验第一次跑DRC可能一堆违例但不要慌要学会按优先级逐条排查。常见违例类型和排查路径大致如下时钟相关违例检查是否所有触发器都有明确的扫描时钟来源时钟门控是否正确处理使能相关违例检查ScanEnable是否覆盖了所有扫描单元有效电平是否一致复位相关违例检查异步复位是否被正确识别测试模式下是否处于无效状态三态/IO相关违例检查复用IO在测试模式下的驱动和方向是否正确排查的思路从最大范围开始先看有没有大面积的时钟域问题再看个别异常点。通常一条DRC违例背后可能暴露的是一整类配置错误修掉根因一批违例会同时消失。我曾经遇到一个案例dft_drc报了上百条触发器无时钟可达的违例一开始以为是时钟树问题排查了很久才发现实际上是scan_en的有效电平在某个子模块里被反相了导致这些触发器都被关在扫描模式外。修正有效电平后上百条违例一次性清零。这类问题如果逐条排查效率极低抓住根因才走得快。5.3 与set_dft_config配合的优化思路set_dft_config和set_dft_signal是配套使用的光配set_dft_signal不够。几个常用的优化配置set_dft_config -fix_clock_enable true set_dft_config -fix_reset true set_dft_config -fix_set_hold_time true-fix_clock_enable解决ICG门控时钟问题-fix_reset自动修复测试模式下的复位冲突-fix_set_hold_time修复测试模式下可能出现的建立保持违例。这些选项开启后工具会在insert_dft阶段自动插入修复逻辑代价是面积增加和时序轻微影响但相比手工修复自动化修复的效率和可靠性都更高。还有几个常用的set_dft_config选项值得提及-max_scan_length限制扫描链最大长度超过时自动拆成多条链。通常根据测试时间和ATE通道数来设定-scan_serialization_style扫描链串化风格multiplexed_flip_flop是最常见的选择适合大多数标准单元设计-internal_clock内部时钟模式适用于无独立时钟端口的设计我在项目中一般先把set_dft_config的基础选项定好再写set_dft_signal避免配置顺序带来的相互覆盖。特别是-fix_clock_enable和-fix_reset这两个选项一定要在insert_dft前确认打开否则ICG单元和复位冲突很容易让整个扫描链失败。5.4 一个完整排查链路的复盘最后分享一个真实的排查过程算是给前面所有内容做个收束。某个项目配置完set_dft_signal后跑dft_drc报出几十条与时钟相关的违例。报告指向的触发器分布在两个不同的时钟域里。第一反应是检查ScanClock配置但主时钟、分频时钟都定义了看起来没什么问题。顺着触发器往回追发现这些违例触发器全部挂在同一类ICG单元后面。ICG的使能端来自一个功能模式的控制信号在测试模式下这个信号的状态不可控导致扫描时钟无法透过ICG到达触发器。这就是典型的门控时钟DFT问题。解决方案分两步第一步在set_dft_config里打开-fix_clock_enable让工具自动在测试模式下强制ICG使能第二步检查这个控制信号是否需要在测试模式下被钳制到固定值如果需要再用一个Constant类型的set_dft_signal把它的测试模式状态固定下来。两者配合DRC违例全部消除。这个案例给我的启发是set_dft_signal的配置不是孤立的它和set_dft_config、RTL结构、时钟树结构、IO复用方案都紧密耦合。真正专业的DFT工程师不是会背几个命令选项而是能快速定位配置和设计意图之间的偏差在哪里。如果你正准备在一个新项目上做DFT综合我的建议是动手写set_dft_signal前先在纸上画出完整的时钟树、复位树、测试端口复用关系图。画出这张图再回头写命令很多坑自然就避开了。