IJTAG这套东西,在DFT领域里算是越聊越热的话题。如果你接触过复杂SoC或先进工艺节点的芯片,一定对测试数据量爆炸、测试时间失控、调试访问困难这几个问题深有体会。IEEE 1687标准(也就是常说的IJTAG)提供了一套解决"如何高效访问芯片内部仪器"问题的标准化方案。上一篇讲了基础概念和动机,这一篇我们深入内部,把SIB机制、ICL/PDL描述语言,以及和Tessent等工具的配合讲透。对于正在做DFT实现、或者准备在项目中引入层级化测试架构的工程师,这篇内容应该能帮你少走不少弯路。
1. 为什么传统JTAG在复杂芯片面前越来越力不从心
要理解IJTAG的价值,先得看清楚传统JTAG(IEEE 1149.1)在当下芯片设计中的困境。这不是说JTAG不好——它依然是整个测试架构的基石,但当芯片规模到一定程度后,它的短板会变得非常扎眼。
1.1 指令空间和TAP端口成了瓶颈
传统JTAG通过TAP(Test Access Port)状态机和指令寄存器来控制所有测试逻辑。指令寄存器的位宽一旦定死,能编码的指令数就固定了。比如一个5位的指令寄存器,最多就是32条指令。听起来不少,但当你芯片里有几十个IP、每个IP需要独立的BIST(内建自测试)、边界扫描、调试访问功能时,32条指令根本不够分。
我在一个实际项目里就撞到过这堵墙。那颗SoC集成了将近40个不同的可测性模块,每个模块至少需要2到3条指令来完成配置和启动。光把指令分配表列出来就超过了256条,指令寄存器被迫做到8位以上,但即便如此,指令译码逻辑的复杂度也让人头大。更糟糕的是,任何新的IP加入,都意味着指令表要重新规划,前期定好的分配方案可能被推翻重来。
1.2 测试数据串行搬移的低效
JTAG本质上是一条串行移位链。所有的测试向量、配置数据、响应数据,都要经过TDI(Test Data In)和TDO(Test Data Out)一位一位地搬进搬出。芯片规模变大、测试模式的复杂度和深度提升之后,这条串行通道就变成了整个测试流程的咽喉。
举个具体数字:假设一颗芯片的内部扫描链总长约500万位,一次全芯片扫描测试要灌入的向量可能有上千条。按JTAG串行移位的机制,就算时钟跑到50MHz,仅仅搬移数据就要花掉相当可观的时间。这在实验室调试阶段还能忍,到了量产测试阶段,每一毫秒都是成本。
1.3 层级化和模块化设计带来的访问难题
现代SoC几乎都是多层级的:顶层有CPU子系统和总线互联,下面挂着各种功能IP,每个IP内部又有自己的测试逻辑。传统JTAG的扁平化访问机制,要求所有测试逻辑都能从顶层TAP直接看到、直接控制。可模块化设计里,很多IP是第三方提供的,它们内部的具体测试结构对集成者来说是黑盒子,甚至连扫描链怎么接、BIST怎么触发都不清楚。
这就产生了一个矛盾:测试逻辑存在于不同层级、属于不同团队,但访问路径只有顶层一条。结果就是,每次集成新IP,都得重新梳理JTAG访问路径,手工做大量的地址译码和指令扩展,工作量大不说,还特别容易出错。
说实话,这些痛点做DFT的人迟早都会遇到。IJTAG就是针对这些问题提出来的——它不推翻JTAG,而是在JTAG的基础上,增加了一套更灵活、更利于层级化复用的仪器访问机制。
2. SIB机制:层级化测试访问的设计核心
IJTAG最核心、也最值得你花时间理解的就是SIB(Segment Insertion Bit)。这个小小的电路单元,解决了"如何在有限端口下按需访问内部仪器"的问题。理解了SIB,你就理解了整个IEEE 1687的硬件架构。
2.1 SIB的功能本质是一个可控旁路开关
SIB本质上是一个1位寄存器单元,附带一个旁路逻辑。它串联在扫描数据通路中间,控制着某一段扫描通路是"接入"还是"旁路"。当选通的时候,数据从TDI经过这段通路再流向TDO,意味着这段通路里的所有仪器可以被访问;当旁路的时候,数据直接跳过这一段,通路变短、访问速度更快。
我习惯把它理解成"水管里的阀门"。水管是测试通路,阀门就是SIB。你要给后花园浇水,就打开阀门让水流过去;不需要的时候关掉阀门,水走主管道直接到终点,又快又省。放到芯片里,这个"省"的好处体现在测试时间上——配置哪个SIB,只需要把对应的控制位置1或清0,不需要给每个仪器都分配独立指令。
2.2 层级SIB树的组织方式
SIB最有价值的能力是可以嵌套。多个SIB可以组成一棵树状结构:顶层SIB导通后,里面还有第二层SIB,再导通后里面还有第三层。每一层控制各自的仪器子网络,驱动逻辑只需处理当前开通的路径。
以我参与过的一个车载芯片项目为例,测试架构分了四级:顶层挂音频子系统SIB、显示子系统SIB、安全子系统SIB;每个子系统内部再挂具体的IP测试SIB;有些大IP内部还有第三级、第四级。最终从顶层TAP到最深的那个IP测试逻辑,中间需要依次打开4个SIB才能访问到。
层级化的好处是显而易见的:配置某个IP的测试逻辑时,不需要关心其他子系统的SIB状态,也不会有其他模块的寄存器在数据链路上干扰你。模块团队内部怎么组织测试逻辑,完全由他们自己决定,顶层只关心这一级SIB的控制。这就实现了真正意义上的"模块化测试复用"。
2.3 SIB的硬件实现代价与优化
很多人一听到"每级都要加SIB",第一反应是面积开销。确实,每个SIB都会有额外的门电路,但实际算下来,这个代价很低。一个SIB通常只需要一个D触发器和几个门,标准单元库下折合面积大约只有2到3个等效门。对比一个IP内部动辄几百万门的逻辑,这几乎可以忽略不计。
不过需要注意的是,SIB的级联深度会影响访问延时。每经过一级SIB,数据通路上就多了一级额外的移位寄存器,配置指令和数据到达目标的周期数会增加。如果层级过深,比如超过10级,测试配置时间会变得不可接受。我在做功耗管理芯片的时候就踩过这个坑,当时没有预估SIB层级深度对配置时间的影响,结果测试用例里光配置就耗掉了不少周期,后来不得不调整SIB的位置,把高频访问的仪器上移。
2.4 正确理解SIB的"配置即指令"思想
传统JTAG里,你想访问某个仪器,需要先通过TAP状态机往指令寄存器灌入一条对应指令,然后数据路径才会切到目标寄存器。IJTAG的SIB方式不同,它是在数据路径上做文章——通过移位寄存器链上的数据位来控制SIB的开合,从而动态决定扫描数据通路。
这个设计在操作上更加灵活。因为SIB控制了"扫描通路"本身,一旦某个SIB开启,后续所有数据移位操作都直接面向其控制的仪器链,不需要反复灌指令、切状态。尤其对大量连续的数据操作应用场景,效率提升非常明显。你可以把SIB机制想象成"在一个可动态改线的电路板上重新布线",而不是"每次操作前都重新插拔跳线帽"。
3. ICL和PDL:让工具和工程师共享同一种测试语言
如果SIB是IJTAG的硬件骨架,那ICL(Instrument Connectivity Language)和PDL(Procedural Description Language)就是让这套骨架能够被EDA工具理解、被测试程序生成器使用的软件接口。没有这两门语言,光有SIB电路,实现不了自动化。
3.1 ICL描述什么:仪器、连接和扫描路径的"电路图"
ICL是一种文本描述语言,它的作用是把芯片内部的可测试性结构用标准化格式描述出来。简单说,ICL就是在告诉工具:芯片里有哪些仪器(比如BIST控制器、扫描链包装器、调试寄存器堆),这些仪器在扫描通路里是怎么连接的,SIB网络的结构是什么样。
来看一个简化版的ICL描述片段:
Module top_ic { ScanInterface top_tap : TDI, TMS, TCK, TDO; ScanMuxReg sib_audio { ScanIn top_tap; ScanOut audio_chain; } Instrument audio_bist { ScanIn sib_audio; ScanOut sib_audio; ControlRegister length = 8; } }这段描述里,ScanMuxReg就是SIB,Instrument定义一个仪器(这里是BIST),ScanIn/ScanOut描述了数据通路的连接关系。工具拿到这份描述,就能自动生成访问特定仪器的扫描路径。
实测下来,ICL最需要花的功夫是在模块级写清楚每条扫描链的路径定义。这个环节偷懒,后面生成测试向量的时候就会有一堆连接性错误,反复报错排查极耗时间。我建议你把ICL当成"带测试信息的网表"来维护,做到和RTL版本同步更新,这样省心很多。
3.2 PDL描述什么:仪器操作的"操作步骤书"
ICL描述了硬件结构,PDL则描述了对仪器进行的操作步骤。PDL更接近一门编程语言,它有变量、循环、条件分支、函数调用,还能直接对寄存器位域进行操作。
PDL最常见的应用场景是描述一个测试序列,比如"配置BIST控制器寄存器为随机模式,启动BIST,等待完成,读取签名值"。用PDL写出来,大致长这样:
proc run_bist { // 打开通往BIST模块的SIB iWrite top_ic.sib_audio 1; // 配置BIST寄存器 iWrite audio_bist.control 0x01; // 启动BIST iWrite audio_bist.start 1; // 等待BIST完成 iLoop 100 { iRead audio_bist.status; if (audio_bist.status.done == 1) { break; } } // 读取签名 iRead audio_bist.signature; // 关闭SIB,恢复旁路 iWrite top_ic.sib_audio 0; }这个PDL过程的含义非常清晰:打开SIB,配置寄存器,启动BIST,轮询状态,读签名,最后关闭SIB。整套流程和我们手工在实验室里用JTAG调试器敲的命令几乎一样,但PDL是标准格式,可以被工具自动编译、调度,并生成对应的ATE测试程序。
3.3 工具侧如何使用ICL/PDL
在Tessent的IJTAG流程中,ICL和PDL是被当作"标准输入"来对待的。Tessent会自动解析ICL描述,构建内部的可测性层次树;然后根据PDL中的仪器操作序列,自动生成对应的扫描加载数据和捕获使能信号。这相当于,工具的"测试生成器"不再需要你手工指定每条芯核的具体寄存器地址,而是直接照着PDL的描述去驱动整个测试序列。
这种自动化带来的学术价值是测试向量和硬件结构解耦。模块团队更新了内部BIST寄存器的定义,只要同步更新ICL/PDL,顶层和使用方的测试环境无需做任何手工修改,重新生成的向量自然就是正确的。这在以往的JTAG流程里,几乎不可能做到。
4. 在Tessent DFT流程中落地IJTAG架构
我知道很多团队关心的是:IJTAG概念看上去好,但在Tessent里到底怎么落地?这里直接分享我们项目里实践过的路径和几个关键参数设置。
4.1 从工具配置到SIB网络插入
Tessent DFT(曾用名Tessent Shell)对IEEE 1687的原生支持,是这几年用下来最值得推荐的一点。它提供了专门的命令来创建和插入SIB网络,不需要你手动在RTL里写SIB逻辑。
最基础的配置大致是这样:
set_config -ijtag on create_tap -instruction_length 8 add_sib -name sib_audio -depth 1 add_sib -name sib_video -depth 2这几条命令的含义分别是:启用IJTAG流程,创建8位指令寄存器的TAP,增加两个SIB(音频和视频)到指定层级。Tessent会自动分配SIB的控制位,并把它们嵌入到扫描链路中。
值得提醒的是,-instruction_length这个参数要留够余量。虽然IJTAG的核心思想是"少用指令、多用SIB配置",但TAP本身仍然需要一些基础指令(如IDCODE、BYPASS、SAMPLE等)。如果计划要保留和传统JTAG指令的兼容,建议指令寄存器不要低于8位,否则某些IP对接会很困难。
4.2 Tessent中ICL/PDL的生成流程
Tessent在插入SIB网络之后,会顺带生成一份ICL描述文件,描述整个测试网络的连接关系。这份文件会按层次组织,顶层的ICL文件引用各个子模块的ICL文件。具体命令类似:
write_icl -output top_ic.iclPDL的生成则相对复杂一些,因为它来源于具体的测试需求。Tessent提供了一种称为"procedure"的机制,你可以为每个仪器定义测试过程。写好的PDL可以独立于硬件设计被维护和编译,当网表更新后,只需要重新映射一遍即可。
我们自己是用脚本维护每个IP的PDL文件库,芯片版本换的时候只更新寄存器地址映射,不需要重写整个测试行为描述。这个习惯帮我们节省了大量回归测试时间。
4.3 与IEEE 1500芯核测试包装器的配合
做IP复用的时候,一定要清楚IJTAG和IEEE 1500(芯核测试包装器标准)的关系。IEEE 1500解决的是"芯核内部的扫描链和测试逻辑如何标准化包装"的问题,而IJTAG解决的是"如何从芯片顶层访问这些芯核测试逻辑"的问题。两者不是替代关系,而是天然互补。
在Tessent中,你可以给一个IEEE 1500包装的芯核加一个SIB,做成"可旁路的测试访问通道"。这样,当这个芯核被集成到不同项目时,测试访问方式无需改变,只要顶层打开相应的SIB即可。我们有个第三方 modem IP,就是用这种方式实现了一次开发、多项目复用的效果。
4.4 测试时间收益到底有多明显
说一个实际数据。我们之前那颗车规SoC,全芯片扫描测试向量大约有几十万条,原始JTAG的扁平化架构下,测试时间接近10秒。引入IJTAG SIB结构后,因为可以按需配置SIB,只访问需要测试的子系统,测试向量搬移量大幅减少,最终量产测试时间降到了4秒以内,优化比例超过一半。
当然,这个收益不是凭空来的。SIB网络的层级和深度规划、PDL中操作序列的精简、以及ATE通道和时钟频率的匹配,每一环都影响了最终的数字。如果你正准备做类似架构调整,建议先从子系统试点,测完一个子系统再全面铺开。
5. 项目中容易踩的坑:SIB网络和工具配合的实战教训
IJTAG不是装上就能一帆风顺。我们团队在落地过程中踩了不少坑,这里挑几个最有代表性的讲一讲,希望能帮你提前绕开。
5.1 SIB层级过深导致的配置时间失控
前面提到过,SIB层级过深会让配置时间增长。这里给出一个具体的定量分析:假设10级的SIB链,每级配置一个SIB位需要1个TCK周期,纯配置时间就10个周期。看似不长,但如果每个测试模式都要配置一遍,上万个测试模式累积起来,时间是相当可观的。
我们最初在某个AI加速芯片上设计了层层嵌套的5级SIB树,最初觉得挺规整。可当真跑到testmax生成测试向量的时候,发现每次模式切换光配置就得几百上千个周期,而且大部分配置周期都花在反复打开/关闭中间层的SIB上。
后来调整策略是:将测试过程中保持开启状态的SIB尽量上提,只对切换频繁的末端SIB做动态控制。这样既保留了SIB的灵活性,又把配置开销压在了可控范围内。设计SIB树之前,先列一下每个子系统的测试模式切换频率,再决定哪些层级需要做成常开路径,这种做法很管用。
5.2 ICL描述与实际网表不一致
ICL本质上是对网表格的抽象描述,如果两边不一致,工具在生成测试程序时不会立刻报错,而是生成错误的地址映射和移位序列,到时候在ATE上跑测试才发现问题,定位起来非常痛苦。
我们踩过最典型的一次,是某个模块的RTL在更新时调整了扫描链的拼接顺序,但ICL文件没有同步更新。结果工具生成的BIST配置序列全部错位,测出来的签名完全不对,整整排查了一周。后来我们强化了一个流程约束:任何ICL相关RTL的改动,必须同时更新对应的ICL描述,并且跑一遍形式化校验,把ICL生成的扫描路径和网表的真实扫描路径做对比,确保完全一致才能提交。这一条救了我们很多次。
5.3 多个SIB同时配置时的互锁问题
如果你的PDL流程中有多个SIB需要同时配置,要注意它们之间是否存在路径互锁关系。所谓互锁,就是一个SIB的开启依赖另一个SIB的关闭,或者两个SIB共享同一段物理通路,同时开启会导致移位数据冲突。
Tessent在生成PDL时通常会做可访问性分析,自动处理好大部分互锁关系。但碰到修改过手工网表的情况,工具分析不到的边界情况就会漏掉。我的习惯是在写完PDL之后,先用形式化工具做一遍SIB状态可达性检查,确认所有需要同时建立的访问路径都是可达的,再投入向量生成。
5.4 Tessent版本间的行为差异
不同版本的Tessent对IJTAG的支持力度和默认行为有差异。早期版本对SIB的默认插入方式、指令映射策略和后版本都不完全一致。如果你从项目中期升级了Tessent版本,建议先对既有的IJTAG工程做一次完整的回归,仔细核对生成向量的变化。我们有一次升级版本后发现,生成向量的数量不变,但每个向量的移位深度变短了,看起来是优化,实际上是因为新版本工具默认展开了部分SIB层级,改变了路径选择策略。这种行为差异本身不一定是坏事,但如果你没有注意到就直接拿去量产,风险就大了。
6. 从JTAG到IJTAG:团队协作和流程规范的实战建议
最后聊点软性的,但同样重要。IJTAG带来的不只是新技术,还有团队分工和流程规范的改变。如果你正在推动部门引入IJTAG,下面这几件事越早做越省力。
6.1 建立模块级的ICL/PDL负责人机制
ICL/PDL的维护如果全压在DFT集成工程师一个人身上,信息传递非常低效。因为模块内部的测试逻辑细节,只有模块所有者最清楚。我们现在的做法是:每个IP的ICL/PDL由该IP的DFT工程师负责维护,集成工程师只维护顶层SIB网络的描述。这样权责清晰,出了问题也很好定位。
6.2 让ICL进入设计同步流程
RTL版本管理和ICL版本管理的同步,几乎是我们早期最痛苦的事。后来引入了一个简单的检查脚本:在每次同步版本之前自动比对ICL描述的模块端口列表和RTL的实际端口列表是否一致。这种低成本的方式堵住了大部分因版本错位引起的低效调试,值得一试。
6.3 PDL用例库的积累
每写一个新测试用例,都顺手沉淀成可复用的PDL模板。别觉得前期开发慢,回头看你会发现好的PDL模板能让你在新IP验证、系统级测试甚至诊断分析时节省大量时间。比如一个通用的"读取设备ID"流程、一个"执行BIST并返回签名"的流程,几乎每个模块都能复用。把这些公共流程抽出来,后续跟芯片验证团队、测试工厂对接的时候,沟通成本能降一个量级。
我自己在这块还有一个体会:让PDL模板尽量短小、聚焦单点功能。之前我们做过一个巨大的PDL流程,把整个芯片的所有仪器测试都揉到一个过程里,结果调试起来非常痛苦,因为任何一个环节出问题,你都得先搞清楚跑到第几步、卡在哪条访问路径上。拆成小过程之后,每次只做一个仪器的操作,出了问题可以很精准地定位,这个习惯帮我们省了无数个小时。