ARTICLE DETAIL

建站实战干货

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

深入理解IJTAG核心:ICL如何定义动态扫描网络与测试路径

2026/9/28 16:29:06 拓冰建站 浏览量
深入理解IJTAG核心:ICL如何定义动态扫描网络与测试路径 几年前我在一个SoC项目里被测试时间折腾得够呛。那颗芯片里集成了二十多个嵌入式仪器——各种传感器、存储器BIST、高速接口的调试逻辑——按老办法全挂在一条JTAG链上TDI进TDI出串到底。每次想去访问链尾那个仪器前面的数据都得陪着走一遍单条链移位深度轻松破千。芯片测试是按秒计费的这种方案直接拖垮成本。后来切到IEEE 1687 IJTAG通过SIB把扫描网络切成可以动态开合的分段才把测试时间压了下来。但这套网络比固定菊花链复杂得多谁是父、谁是子、哪一段可被旁路、控制位从哪里进来全靠一份ICLInstrument Connectivity Language文件说清楚。对于用Tessent做DFT的工程师来说ICL既是网络拓扑的“地图”又是工具自动生成pattern的关键输入。这篇文章我从实践角度把ICL在IJTAG网络中的核心作用捋一遍适合刚接触IJTAG的DFT工程师也适合想搞懂Tessent内部是如何“看懂”网络的人。1. 为什么IEEE 1687非要搞一个“连接语言”出来1.1 传统JTAG的串接困境经典的IEEE 1149.1边界扫描架构允许把多个TAP器件或片内instrument以菊花链形式串在TDI和TDO之间。芯片规模小的时候这么做完全没问题链上几十个bit一移位就完事。可到了大规模SoC时代嵌入式仪器数量从几个涨到几十个链长很快超过500甚至1000 bit。访问链尾的寄存器时链头的几百个bit也被迫跟着挪一遍。带来的代价至少有三个方面。测试时间线性恶化是最直观的——移位深度等于整条链的长度每次访问的TCK周期数跟着上涨在Multisite测试场景里时间就是真金白银。动态功耗和毛刺风险排在第二整条链都被驱动翻转那些这次根本用不到的仪器也在白白翻转高速shift时电源噪声和串扰问题会被放大。第三个是网络应变能力差芯片流片后想调整访问路径或者想把某个失效的仪器隔离掉静态链路几乎做不到改动往往要动到顶层结构。这个现象在行业里被称为“长链问题”。解决思路其实早就有了不要把所有仪器都串成一条不可分割的链条而是给每段分支加一个可控的开关按需接入。1.2 IJTAG把“一条链”改成“一棵树”IEEE 1687引入SIBSegment Insertion Bit作为基本开关单元。SIB本质上是一个带旁路的多路开关控制位置0时数据直接从SIB的输入走到输出后面挂的分支完全不插入主路径控制位置1时分支被串入扫描链可以访问分支上的仪器。这样整个访问网络从一条固定链变成一棵可以由控制bit动态配置的树。工程师只需要在需要的时候展开某一个分支其余部分保持旁路。测试向量平均长度大幅下降还能针对不同仪器单独路由调试和诊断也灵活得多。这个思路其实不复杂类似你晚上在办公室只打开工位上的台灯而不是每次开灯都把整栋楼的电闸一起合上。听起来简单但工程化落地时这套“树”做得越大网络状态就越复杂。1.3 网络动态了工具反而“瞎了”问题随之而来动态可配置网络依赖控制寄存器当前状态不同状态下扫描路径完全不同。一个pattern要正确工作生成它的工具必须精确知道每个SIB的控制bit是谁、极性是什么、目标仪器挂在哪个分支、分支如何逐层展开。这部分信息不像传统JTAG那样画一条线就能说清它需要一种结构化的、机器可读的描述方式。传统项目里这些信息散落在Excel连线表、图纸、甚至口头沟通里对EDA工具来说完全不可解析。到了Tessent里要跑ATPG和诊断工具需要自动完成“路径解析、网络展开、控制bit对齐”这些动作。于是IEEE 1687标准里定义了ICL。ICL的存在意义就是把“人类可读的连线图”升级成“机器可读的连接描述”让Tessent这类工具在编译阶段就把整个IJTAG网络完整解析出来。维度IEEE 1149.1IEEE 1687 (IJTAG)网络形态固定菊花链树状可配置网络访问路径控制全链移入移出SIB按需展开仪器连接描述无标准化描述ICL操作行为描述SVF等外部协议PDL扩展性弱强2. ICL文件到底描述了什么从硬件角度逐行读2.1 它不是网表也不是RTL很多工程师第一次拿到.icl文件会以为它跟Verilog差不多。语法确实有点像但定位完全不同。ICL不是用来做逻辑综合的也不描述任何数字逻辑行为它只回答三个问题这个网络里有哪些“仪器”每个仪器有哪些扫描端口这些端口之间怎么连ICL的基本组成单元是Module。一个Module可以对应一个物理仪器、一个SIB逻辑节点、一个wrapper层甚至一整棵子网络。Module内部通过ScanIn、ScanOut等端口对外呈现扫描接口再用ScanRegister、ScanMux这类原语描述内部的连接关系。这里的关键是“连接”二字ICL里几乎没有逻辑表达式没有always块没有时序控制所有内容都在描述端口与端口之间的连通性。2.2 一个最小示例带扫描寄存器的仪器包装层先看一个最简单的例子某个温度传感器带一个32 bit配置寄存器外面包了一层测试wrapper。它的ICL描述大致如下// 传感器仪器wrapper示例 Module temp_sensor_wrapper { ScanIn si; ScanOut so; ScanIn tck; ScanIn reset; ScanRegister config_reg ( .si ( si ), .so ( so ), .clk ( tck ), .reset ( reset ) ); }这段描述里temp_sensor_wrapper对外暴露两个扫描端口si、so外加时钟和复位。内部只有一个ScanRegister把si直连到寄存器的串行输入、寄存器的串行输出直连到so。TCK被用作寄存器时钟reset用于复位。没有写任何关于“这个寄存器怎么初始化、要移入什么数据”的细节——那些属于PDL的范畴。ICL只负责告诉你从外部si进来经过这个32 bit寄存器再从so出来。访问路径、扫描深度工具的编译阶段就能自己算清楚。2.3 SIB节点怎么表达再来看SIB。一个典型SIB在ICL里通常用ScanMux和ScanMuxSel组合描述。ScanMux描述旁路与串接的路径选择ScanMuxSel负责让控制位本身也能沿链传递。// SIB节点的ICL示意 Module sib_node { ScanIn si; ScanOut so; ScanIn sel_in; ScanOut sel_out; ScanOut branch_si; ScanIn branch_so; ScanMux main_path ( .si ( si ), .so ( so ), .sel ( sel_in ), .si_select ( branch_si ), .so_select ( branch_so ) ); ScanMuxSel ctrl_path ( .sel_in ( sel_in ), .sel_out ( sel_out ) ); }读这段代码时抓住两个关键点。main_path这个ScanMux决定当前SIB是旁路还是把branch_si/branch_so对应的分支串进主链。ctrl_path把sel_in的控制信号继续向右传递保证控制移位链是连续的不会因为某个SIB被旁路而断掉。所以一个SIB在ICL里表达的不只是“开关”还隐含着控制链自身的完整性。Tessent读取这些原语后会把它转换成内部路径模型再结合PDL生成合法的测试向量。注意不同版本的IEEE 1687标准和不同EDA工具对ScanMux的端口命名存在细微差异上面是按常见语义写的示意代码。真正写文件时以你手头工具支持的视图模板为准。2.4 层次化顶层网络如何逐层展开单颗SoC里通常有几十个SIB和仪器ICL采用层次化方式组织。顶层Module会实例化子Module形成一棵树。例化语句的写法跟Verilog很像Module top_network { ScanIn tdi; ScanOut tdo; ScanIn tck; ScanIn rst_n; ScanIn top_sel; ScanOut top_sel_out; wire sensor_si; wire sensor_so; sib_node sib_inst ( .si( tdi ), .so( tdo ), .sel_in( top_sel ), .sel_out( top_sel_out ), .branch_si( sensor_si ), .branch_so( sensor_so ) ); temp_sensor_wrapper u_sensor ( .si( sensor_si ), .so( sensor_so ), .tck( tck ), .reset( rst_n ) ); }这段示意代码里外部通过tdi进入经过sib_inst只有sel_in被置位时路径才会继续扩展到u_sensor否则数据直接从tdo旁路出去。层次结构在这里的意义不只是组织代码它直接对应了扫描访问时的路径深度和展开顺序。Tessent在编译ICL时会把所有层次信息解析成一张带控制依赖的连通图后续所有pattern生成的路径计算都基于这张图。2.5 ICL没有“隐式连接”最后补充一个特别的习惯差异。ICL规范里没有“隐式连接”的概念所有连接关系都必须显式写出来。Verilog网表里如果你忘记连一个端口工具可能默认悬空或报warning而ICL如果少连一个端口整个路径解析都可能跑偏。所以写ICL的原则只有一条宁多勿漏端口宁可写满也不要靠“默认”两个字赌工具行为。3. Tessent工具链里ICL如何参与一张pattern的诞生3.1 ICL从哪里来实际项目里ICL来源通常有三条路。第一种是IP供应商随核提供很多商用IP会附带经过验证的ICL和PDL直接集成即可这是最省事的路径。第二种是从RTL或网表自动提取Tessent工具链可以基于设计文件解析出ICL适用于没有现成描述的自研模块。第三种是手工编写一般只在极小规模工程或快速验证阶段用手工写长文件容易踩坑不建议大规模铺开。无论哪条路工具最终会把ICL编译成内部的仪器与连接模型。这一步是后续所有DFT流程的公共基础。如果ICL存在语法错误或连接冲突后续的pattern生成会直接失败而且报错位置往往离真正的问题点很远排查起来非常痛苦。3.2 ICL和PDL是“骨架”与“动作”的关系如果只有ICL工具知道网络结构但不知道具体怎么操作某个仪器。要完成一次读或写还需要PDLProcedural Description Language。PDL用类似C的函数风格描述访问动作比如iWrite config_reg 0x01234567; iRead sensor_status;工具会把PDL动作和ICL网络信息合并在一起计算从TDI到目标寄存器的最短路径确定路径上每个SIB的控制bit状态最后展开成完整的串行bit序列。所以ICL和PDL是成对出现的。ICL可以理解为骨架PDL是动作。缺了ICLPDL里的目标寄存器找不到物理对应关系缺了PDLICL描述的网络只是一张有结构没有行为的静态图。3.3 Tessent里从ICL编译到向量输出的流程在我实际的使用习惯里Tessent的IJTAG flow大致是这样的读入设计数据导入或提取各仪器IP的ICL补上顶层互连描述。运行一致性检查和连接性检查确保每个例化端口都在父模块里有映射。编译ICL构建内部的网络模型。读入PDL把每个应用程序分解成对某一具体仪器的load/unload序列。对每个序列做路径解析决定哪些SIB需要置位、哪些需要旁路完成从网络根节点到目标仪器的扫描路径展开。输出pattern常见有WGL、STIL或Tessent自有格式交到仿真或ATE。这套流程里第5步是关键计算量最大。ICL写得越规整路径展开的歧义就越少生成的pattern越干净。如果ICL里端口连接模糊、旁路分支互相嵌套工具只能靠大量搜索去猜路径性能会非常难看极端情况下还会出现路径解析超时。3.4 ICL结构质量直接体现在测试时间上同一个网络拓扑ICL里SIB层级安排合理工具能把向量长度压缩到接近理论最小值如果层级混乱每个SIB都串满控制bit展开后的向量长度可能比最优值多出30%-50%。这不是玄学而是“控制链是否连续、旁路分支是否集中在高层”这类结构因素直接决定的。我在Tessent里每次综合完网络都会先检查每一条SIB链路上控制bit的数量避免出现某个SIB的控制位被放在链尾深处的“长尾”情况。4. 我实际调试ICL遇到的典型坑4.1 症状一pattern仿真到某一拍后全部错乱有次集成一颗第三方IP仿真pattern时前面几十拍都是对的到某个SIB下挂的仪器访问时报错。一开始我怀疑PDL操作码写错反复检查却没有问题。后来把pattern按shift cycle逐步展开才发现工具在展开路径时把某个SIB的旁路状态判断反了ICL里ScanMux的sel端口极性跟硬件设计实际行为不一致硬件里sel0是旁路ICL里却按sel1是旁路写了。这个坑的点在于ICL本身不会报错工具只按文件描述去计算。只要文件跟硬件在语义上不一致出来的pattern就是合法但错误的。排查方法其实比较机械在Tessent里对单个SIB做路径追踪把该SIB的sel bit单独设0和设1分别仿真对比硬件实际行为。固定做法是拿到外部核的ICL后第一件事就是对照硬件设计文档核对SIB的sel极性和旁路默认值不要只信文件名。4.2 症状二目标仪器“找不到”另一种常见情况是新加的一个调试模块在Tessent里始终无法被选中报错大致是“instrument not reachable”。查了很久发现模块在ICL里的例化层级少了一层。硬件上模块挂在某个SIB分支下ICL里却直接挂在了顶层SIB到模块的那段分支连接完全没描述。工具按ICL展开时永远找不到那条需要先置位某SIB再访问的分支路径。这种问题从语法上完全看不出问题因为端口类型、方向都是对的。排查思路是沿着网络根节点一层层往下做可达性分析工具一般能列出当前可达的所有仪器把这份清单跟设计文档里的访问清单对比哪里缺就从哪里补。4.3 症状三跨时钟域带来的移位毛刺ICL里经常会给扫描寄存器指定clk端口。如果一条扫描链上挂了两个源时钟不同的寄存器又没有做时钟域隔离描述生成的pattern在实际芯片上很可能出现第一级寄存器采到毛刺、移位数据错位。这类问题在抽象仿真里不一定暴露因为仿真模型常常是理想时钟等到ATE或板级测试才暴露代价就大了。我的做法是哪怕是纯测试逻辑也要求扫描链上所有仪器显式声明同一个测试时钟TCK对跨域路径在ICL里用同步器原语包一层或者干脆在硬件上把域间寄存器隔离。ICL不是用来解决时序收敛问题的别把不切实际的期望放到它身上。4.4 命名冲突与集成噩梦多个IP供应商同时存在时两家IP都定义Module mux_ctl并不是什么稀奇事。如果没有做namespace隔离顶层合并时会出现模块定义互相覆盖、端口映射错乱。这类问题一般不会报语法错但行为会变得莫名其妙排查成本极高。现在我所在的团队有个硬性规则所有外来ICL必须在入口脚本里统一加前缀或做命名空间映射不允许裸模块名直接例化。4.5 一条实用的排错顺序踩坑多了以后我给自己定了一个比较顺的排查顺序分享出来供参考先做ICL语法和连接性检查排除显式错误。再对单条SIB路径做状态穷举核对sel极性和默认旁路。接着做目标仪器可达性分析确认层级分支完整。然后对照PDL逐条动作展开pattern波形确认控制移位链连续性。仍然找不到问题最后才去怀疑时序和跨时钟域。按照这个顺序排查大部分问题都能在2小时内定位而不是一上来就去翻波形、猜时序。5. ICL的边界感懂得什么不该交给ICL5.1 别让ICL去描述行为有些刚上手的工程师会试图把寄存器初始值、操作序列也写进ICL文件这是最常见的误区。ICL只描述连接和结构行为交给PDL。硬塞进去有些工具会忽略更麻烦的是不同工具对这类额外内容的解析行为不一致同一个文件在Tessent里编译通过换一个环境可能直接报错。划清这条边界能省掉很多莫名其妙的问题。5.2 ICL和STIL/SVF/CTL这些协议各自管哪一段做DFT的人对这几种格式都不会陌生但它们的分工经常被混淆。STIL和SVF更多是pattern级的描述面向ATE向量格式不负责描述网络拓扑。CTLCore Test Language面向核测试互操作与IJTAG有关系但侧重点不同。ICL专注于描述访问网络本身是IEEE 1687里特有的。实际项目里它们可以共存ICL描述网络PDL描述动作工具再导出STIL或SVF交给ATE。理解这个分层就不会在项目里拿错文件、用错流程。5.3 团队协作中的ICL文件管理ICL是文本文件天然适合进Git做版本管理但也因为它是文本格式很多人容易在review时草率放过。我有几个比较固执的建议。第一每条规则必须有注释写明对应的硬件地址、SIB id、所属模块注释里禁止只写“as discussed”这种无意义内容。第二提交前必须跑工具自带的ICL lint和连接性检查不允许只在生成pattern的节点上跑。第三版本标签要与硬件版本绑定避免ICL更新了但硬件工程基线没动。5.4 给新人的学习建议如果是刚接触IJTAG的工程师我不建议一上来就啃IEEE 1687标准全文。先找一个小型SIB加单一仪器的测试工程手写一份最小ICL用Tessent跑通编译和pattern生成仔细对比每一步输出报告和波形。搞通了之后再接入真实芯片网络。这个路径比我当年直接啃几百行ICL一边debug一边翻标准快得多。最后说说我自己的体会。ICL这份文件看起来不像RTL那样有“逻辑快感”但它在IJTAG网络里就是最核心的契约——硬件后端按它去连网络EDA工具按它去生成pattern测试工程师按它去debug波形任何一环对不上烧进去的向量就全错。做DFT这些年我遇到的大多数问题都不是算法有多难而是一份ICL少写了一个连接、多写了一个极性。所以现在每次接手新项目我都会先花时间把所有ICL通读一遍顺着网络从TDI走到TDO再放工具去跑。这个习惯帮我省下的调试时间远比写文件那点时间多。希望这篇内容也能让你少走几步弯路。