ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Tessent ICL语法详解:SIB、TDR与TAP定义和连接实战

Tessent ICL语法详解:SIB、TDR与TAP定义和连接实战 做DFT的人看到ICL这几个字母心情通常比较复杂。我在项目里第一次接触Tessent ICLInstrument Connectivity Language时以为这只是工具自动生成的文件直到要自己在RTL里插SIB、自定义TDR还得把不同IP的TAP串起来才发现ICL要么不看要看就得比网表还细。这篇博文想解决的就是这个最现实的问题当你要用Tessent工具链定义SIB、TDR和TAP模块时ICL语法到底该怎么写连接关系怎么描述以及那些工具报错背后到底是什么原因。这篇文章适合三类人看刚接手IEEE 1687、1149.1相关项目的DFT工程师做测试复用IP集成、需要在RTL里挂自定义仪器的验证工程师以及所有被“port not connected”“TDR_ADDR重复”这类报错折磨过的朋友。我会把ICL的模块声明、端口映射、SIB的TDR选择、TDR的数据位宽、TAP的状态机和指令译码全部拆开讲配上可直接抄走的模板最后整理一份排错速查表。写的都是我实际跑过的写法不一定覆盖Tessent所有版本但核心思想和套路是通用的。1. 先搭建ICL的基本盘module、port与ICL_INSTANCE的关系1.1 把ICL当成一张片上接线图而不是RTL代码很多人第一次看ICL文件会懵因为它长得既像Verilog又比Verilog抽象。我更愿意把ICL理解成一张“纯文本接线图”它不描述逻辑实现只描述“有什么端口”“端口之间怎么连”“某个例化对应哪个模块”。你可以把module理解成接线盒port是接线盒上的接口而ICL_INSTANCE则是告诉你“这里放了一个某某型号的接线盒它的接口接到了哪里”。这个定位决定了写ICL时的思维方式。你在RTL里要关心SIB的MUX选通逻辑怎么写但在ICL里只需要告诉工具这个SIB模块有哪些输入输出端口它在实例化时接到了哪条扫描链上它的TDR地址是多少。工具根据这份描述去做pattern retargeting、生成测试激励、做诊断分析。所以ICL写得准不准直接影响后面一系列工具链的输出质量。1.2 一个最小可用的ICL模块长什么样先看一个最朴素的模块声明假设我们要描述一个8位的TDRICL { module MyTDR_8bit { port { port_in tdi { } port_out tdo { } input capture { } input shift { } input update { } input reset { } input select { } } ICL_MODULE_ID MY_TDR_8BIT; } }这里面每一个关键字都有明确含义。ICL是文件顶层所有模块定义都包在这对大括号里。module后面跟的是模块名这个名字建议和RTL模块名保持一致。port块里声明模块的对外端口input和output管的是控制类信号port_in和port_out则用来表达扫描数据通路上的串行输入输出。ICL_MODULE_ID是这个模块在ICL世界里的唯一身份证工具之间做匹配时靠它识别。我之前遇到过一个问题模块名和ICL_MODULE_ID不一致RTL里叫“tdr_8bit_top”ICL_MODULE_ID却写的“MY_TDR_8BIT”结果Tessent在做网表匹配时死活认不出来。后来统一规定模块名、ICL_MODULE_ID、RTL实例名尽量用同一套命名能省掉大量定位问题的精力。1.3 端口方向的细节scan类端口和控制类端口别混用ICL里的端口声明方式比较灵活但有一个原则必须守住扫描数据通路端口使用port_in和port_out而控制信号使用input和output。这不是风格问题而是语义问题。port_in和port_out描述的是扫描移位路径上的数据流向工具做链跟踪时会沿着它们走input和output则用于capture、shift、update这类控制信号工具在生成时序关系时会用到。混用的典型后果是工具把控制端口当成扫描端口去追踪连接报告里出现一堆莫名其妙的环或者“unexpected port type”。所以写端口声明时先分类扫描通路归扫描通路控制信号归控制信号宁可在注释里写清楚也不要图省事混在一起。1.4 ICL文件组织和include机制一个芯片里ICL模块通常不止一两个我的习惯是按照仪器类型拆分文件TAP相关放tap.iclSIB定义放sib.iclTDR按IP或功能块分文件最后用一个顶层文件include进来。Tessent的ICL编译器支持类似C语言的include机制你可以用相对路径或绝对路径引用其他ICL文件但要注意路径解析的搜索顺序这个在大型项目中很容易踩坑。文件拆分还有一个好处不同IP团队维护各自的ICL文件互不干扰。但拆分之后要统一约定命名规则避免两个模块在联合编译时出现同名冲突。我见过两个IP团队都定义了名叫“sib_inst”的ICL_INSTANCE合并后工具直接报duplicate instance name最后只能全局重命名改得头大。2. SIB定义实操用ICL_TDR_SELECT写一个能用的SIB2.1 SIB的核心作用在扫描链上做“段开关”SIB的全称是Segment Insertion Bit是一种可配置的旁路开关。它挂在扫描路径上通过一个控制位决定是“让数据进入后面的TDR段”还是“直接旁路过去”。这个机制最大的好处是不需要访问某段仪器时扫描链长度不会白白变长测试时间和诊断数据量都能省下来。在ICL语法里SIB的描述方式通常不靠手画状态机而是使用ICL_TDR_SELECT这类模板。模板内部封装了旁路和选通的行为你只需要告诉它TDR的地址和对应关系。这也是ICL“高一层描述”的体现工具知道SIB的标准行为不需要你重复描述切换逻辑。2.2 一个最小SIB的ICL定义模板我在项目里常用的SIB定义模板是这样的module SIB_TOP { port { port_in sib_in { } port_out sib_out { } input select { } input shift { } input capture { } input update { } input reset { } port_out tdr_select { } } ICL_MODULE_ID SIB_TOP; ICL_TDR_SELECT sib_select { TDR_ADDR 0x00; SELECT_PORT select; // 其他控制端口映射 } ICL_INSTANCE sib_impl { ICL_MODEL SIB_TOP; ICL_PORTS { sib_in sib_in; sib_out sib_out; select select; shift shift; capture capture; update update; reset reset; tdr_select tdr_select; } } }这里ICL_TDR_SELECT告诉工具“这是一个TDR选择逻辑”TDR_ADDR指定了这个SIB对应的地址。当工具需要访问该地址的TDR时它就知道要让这个SIB进入选通状态。SELECT_PORT则把RTL里的select信号和这个语义绑定保证ICL描述的“意图”和硬件实现是同一个信号。2.3 SIB嵌套时的地址分配原则当设计里有多级SIB嵌套比如顶层SIB下面又挂了二级SIB地址分配就变得敏感。ICL对SIB地址的解析依赖TDR_ADDR的唯一性同一个父SIB下的所有子SIB地址不能重复但不同父SIB下的子SIB可以重复使用相同地址。听起来和内存地址空间很像实际上它就是一套“扫描网络地址空间”的编址规则。我常犯的一个错误是在多级SIB的场景里只检查了全局地址唯一性忽略了局部地址空间。比如顶层A下面的SIB1和顶层B下面的SIB1都用了0x01工具直接报冲突。后来我养成了习惯先在纸上画出SIB树形结构逐层标注地址写进ICL之后再用工具编译验证基本能杜绝这类低级问题。2.4 手写SIB需要注意的RTL一致性一条最重要的提示ICL里写的SIB行为必须和RTL实现完全一致。工具不会去检查你的RTL它只会按照ICL的描述生成pattern。如果你的RTL里SIB的实际地址是0x05但ICL里写的是0x00工具生成的测试序列在芯片上根本选不到这个SIB整个测试会失败。所以每次改完RTL里的SIB地址我一定同步更新ICL并且跑一遍一致性检查。Tessent环境下可以用Tessent ICL Compiler的lint功能做基础检查再结合网表做连接性验证。这个流程虽然多花几分钟但能避免后续在ATE上抓狂。3. TDR的ICL定义数据位宽、控制端口与连接映射3.1 TDR是“被访问的目标”不是“要实现的逻辑”TDRTest Data Register是被SIB或TAP选中的测试数据寄存器。它可能是某个传感器的配置寄存器可能是内建自检的结果锁存器也可能是任意一个需要被测试访问机制读写的自定义寄存器。ICL里描述TDR时不需要描述它的内部电路怎么搭只需要告诉工具三件事数据通路端口是什么、位宽是多少、它挂在哪个选择逻辑下面。把TDR理解成一个“接口描述”很有用。你在RTL里怎么实现移位寄存器、怎么产生捕获时钟工具不关心。ICL关心的是扫描数据从哪个端口进、哪个端口出、一次shift能有多少位。这决定了pattern的长度和数据的解读方式。3.2 定义TDR位宽和控制行为的语法要点TDR的位宽在ICL里通过数据端口的定义间接表达。常见做法是模块里暴露一组位宽为N的扫描数据端口并用工具可识别的属性或模板声明其行为。参考我项目里的写法module TDR_WIDTH16 { port { port_in tdi_16 { width 16; } port_out tdo_16 { width 16; } input select { } input shift { } input capture { } input update { } } ICL_MODULE_ID TDR_WIDTH16; ICL_MODEL tdr_model { ICL_TDR_DATA_WIDTH 16; } }这里width 16声明了数据端口位宽ICL_TDR_DATA_WIDTH 16进一步向工具声明这是16位TDR。两处保持一致的目的是让工具在做位宽检查时不需要猜测。如果端口位宽写16但ICL_TDR_DATA_WIDTH写8编译时工具会提示不匹配尽早暴露问题。3.3 把TDR挂到SIB或TAP上端口映射与连接声明一个TDR模块写完后要被真正“使用”需要在上层模块中实例化并把端口连接起来。这是ICL语法的核心操作类似RTL里的例化与连线。看这个例子module TOP_TDR_BLOCK { port { port_in tdi { } port_out tdo { } input select { } input shift { } input capture { } input update { } } ICL_MODULE_ID TOP_TDR_BLOCK; ICL_INSTANCE tdr16_inst { ICL_MODEL TDR_WIDTH16; ICL_PORTS { tdi_16 tdi; tdo_16 tdo; select select; shift shift; capture capture; update update; } } }在ICL_PORTS块里左边的名字是子模块TDR_WIDTH16的端口名右边是上层模块的端口名或网络名。工具会把两边连起来形成完整的数据通路。如果某个端口没有连接在部分版本里工具只是warning但如果你在继续做retargeting就可能出现pin悬空导致的pattern缺失。3.4 边界扫描TDR和1687自定义TDR的差异做1149.1兼容的边界扫描设计时TDR通常指边界扫描寄存器BSR这类标准寄存器而做1687自定义仪器时TDR更像一个个独立的“测试挂载点”。ICL对两者都支持但描述方式略有差异。边界扫描TDR往往和指令译码器、Bypass逻辑一起捆绑在TAP内部因此不需要单独写成模块而自定义TDR通常是独立模块需要完整声明端口和连接关系。我在实际项目中摸索出的经验是如果TDR是IP供应商交付的先确认对方提供的是“完整ICL模块”还是“半截子文件”。半截子文件经常缺少顶层连接信息需要你补充模块实例化部分。补充时一定要参照IP的端口列表别凭RTL记忆去连不然端口名对不上又要来回debug。4. TAP的ICL描述状态机、指令译码和多TAP层级连接4.1 TAP是整张ICL网络的“入口”TAPTest Access Port是整个扫描访问机制的门面IEEE 1149.1标准的TCK、TMS、TDI、TDO都从这里进出。在ICL里TAP描述的不仅仅是几个引脚更重要的是它内部状态机如何响应TMS序列、如何把指令寄存器译码成TDR选择信号、以及TDO数据通路在什么时候驱动回扫。不是所有ICL顶层都要显式写TAP。如果Tessent已经帮你抽象了标准的1149.1 TAP行为你只需要把TAP当作一个预定义模块去实例化。但在多TAP、桥接、自定义TAP口场景里就需要你自己定义TAP的ICL描述。4.2 用ICL_TAP_STATE_MACHINE描述TAP行为IEEE 1687 ICL标准里对TAP的描述有一类模板叫ICL_TAP_STATE_MACHINE用来声明TAP的协议状态。实际使用Tessent时更常见的方式是引用标准TAP模型库避免重复造轮子。但如果你必须自定义TAP那么至少要定义TCK、TMS、TDI、TDO以及可选的TRST并指明状态机类型例如module CUSTOM_TAP { port { input tck { } input tms { } input tdi { } output tdo { } input trst_n { } } ICL_MODULE_ID CUSTOM_TAP; ICL_TAP_STATE_MACHINE tap_state_machine { ICL_TAP_TYPE 1149.1; } ICL_INSTANCE tap_internal { ICL_MODEL CUSTOM_TAP_CORE; ICL_PORTS { tck tck; tms tms; tdi tdi; tdo tdo; trst_n trst_n; } } }ICL_TAP_TYPE 1149.1是在告诉ICL工具这个TAP遵循1149.1的时序行为。这样一来Tessent生成pattern时就知道TMS序列应该按哪套规则驱动。如果设计用的不是标准1149.1而是某种裁剪过的TAP协议这里需要换成对应的类型或者干脆在更高层用自定义状态机描述。4.3 指令寄存器和TDR选择ICL里的译码逻辑表达TAP的核心功能之一是把指令寄存器中的值译码成TDR选择信号。ICL里通常通过将指令寄存器与各TDR的TDR_ADDR对应起来表达这种关系。当指令译码输出选中某个地址时对应的TDR或SIB就被激活。我们在网表里看到的是一堆译码逻辑但ICL层面只需要描述“这条指令对应哪个TDR”。Tessent工具在生成pattern时会根据ICL里的地址对应关系自动产生加载指令、等待状态、搬移数据等一系列时序。所以ICL描述越清晰工具生成的pattern越可靠。4.4 多TAP与桥接主TAP、辅助TAP的层级关系芯片规模变大之后单一TAP往往不够用。常见的做法是多个TAP通过桥接逻辑串成网络或者有一个主TAP控制若干辅助TAP。ICL在描述这种场景时要特别注意层级关系明确“谁是根节点谁是子节点”。举例来说如果芯片有两个TAP主TAP通过桥接模块访问辅TAP那么在主TAP模块里桥接模块可以看作一个特殊的TDR通过指令选中而在辅TAP模块里它自己又是一套完整的TAP端口。ICL里你需要分别定义两个TAP模块再用顶层模块把桥接关系连起来。连接时最常犯的错是端口方向搞反尤其是TDO通路一不留神就把“从辅TAP读出”写成了“驱动进辅TAP”后患无穷。我建议在多TAP设计中先画一张TAP级连接图标注好每个TAP的TDI和TDO方向再动笔写ICL。端口方向这类问题在纸上推演一遍就能发现不要靠工具报错来提醒。5. 实例化与连接怎么把模块正确地“接线”5.1 写ICL的推荐顺序从TAP往下还是从仪器往上写ICL如果毫无章法很容易写着写着就漏连接。我常用的顺序是“自上而下”先定义顶层TAP端口再把TAP实例化到顶层接着定义它下面的SIB网络最后把TDR挂到SIB或TAP上。这样每一步的连接对象都是明确的不会出现“子模块写好了但不知道往哪里接”的尴尬。一个例外是当你有大量现成的IP级ICL文件时自上而下的方式需要反复查看子模块端口名。这时可以改为“自下而上梳理自上而下连接”先收集所有子模块的ICL文件和端口列表建立一个端口速查表再动笔写顶层。总之顺序可以灵活但一定不能跳步尤其是连接关系跳一步后面就全是坑。5.2 端口映射的细节未连接端口该怎么办在ICL_PORTS里写端口映射时最容易忽略“子模块有、但当前层级确实用不到的端口”。某些工具对未映射端口会输出warning如果你不注意后续仿真或审查时可能会被误判为悬空。我的习惯是凡是没有连接的端口明确留一个注释说明原因例如“该端口在功能模式固定为0ICL中不连接”。如果工具支持显式的no connect声明也要用上。另一个细节是端口名的匹配规则。不同团队写RTL时喜欢加前缀后缀导致ICL端口名和RTL端口名不总是一致。ICL本身只管ICL内部的连接一致性但如果你想用Tessent做网表连接性分析ICL里的端口名最终要能映射到网表端口上。所以端口名的映射关系需要集中管理避免两边各写一套。5.3 用Tessent ICL Compiler做语法检查写完ICL后推荐第一时间用Tessent ICL Compiler做语法检查和lint。命令行方式大概是tessent -icl file.icl -do check不同版本的命令略有差异但思路一致单独编译ICL文件先过滤掉语法层错误再进入连接性检查。这一步非常快却能拦下80%的明显错误。我每次改完ICL都会立刻跑一遍绝不把带语法错误的文件带进后续流程。5.4 阅读编译报告时要盯住的两个关键点编译报告里最容易忽略的是两类信息一是“warning”级别的连接问题二是模块被重复定义的提示。Warning很多时候可以带过但连接类warning要逐个看。曾经有个TDR的位宽不一致工具只报了warning没报error我没注意结果生成的pattern长度不对排查了半天。另一个需要关注的点是工具是否成功识别了所有ICL_MODULE_ID。如果某个模块ID和预期不一致报告里通常会列出已识别的ID列表。养成习惯每次编译后花两分钟扫一眼ID列表能提前发现很多低级错误。6. 排查实录ICL报错里最常见的五类问题6.1 “port not connected”明明连了为什么还报错这类报错最常见的原因是端口名拼写不一致。ICL里端口匹配是精确字符串匹配哪怕是多了个下划线也会报未连接。另一个容易被忽略的原因是大小写工具对大小写敏感写错一个字母就找不到端口。排查时优先用文本对比工具检查两端端口名是否完全一致比肉眼盯屏幕可靠得多。还有一种情况是端口在子模块中定义了但在ICL_MODEL对应的模块描述里没有对应声明。此时工具认为该端口不存在自然报not connected。这多半是模块版本不一致造成的检查IP交付包里ICL文件是不是和RTL版本配套。6.2 “TDR_ADDR重复”该怎么定位TDR_ADDR重复时工具会直接拒绝编译。定位方法是先看报错中提示的两个实例属于哪个父SIB再检查它们是否在同一层。同一层的TDR地址必须唯一不同层的则可以复用。如果工具没有给出明确实例名可以临时注释掉部分TDR_ADDR用二分法缩小范围。我排查时还会额外检查地址格式。比如0x00和0x0看起来一样但在某些版本中可能被解析成不同值。统一使用相同位宽的十六进制表达不要一会儿4位一会儿8位。6.3 为什么TDR在扫描链里“看不见”TDR已经实例化ICL也编译通过但后续生成的扫描链里就是找不到这个TDR。这种问题多出在连接关系不完整比如TDR的scan_in或scan_out没有连到上层SIB工具在追踪扫描通路时链路中断TDR自然进不了链。查看Tessent报告里的扫描路径列表找到断开位置基本能定位是哪个端口没接。还有一种可能是TDR所在的SIB没有被成功使能。ICL里SIB和TDR的地址匹配关系如果对应不上TDR路径便不会被激活表现为“在链里看不见”。6.4 多TAP场景下工具识别错了主TAP多TAP设计里工具识别错主TAP通常和ICL顶层实例化顺序有关也可能是因为多个TAP模块都定义了ICL_TAP_STATE_MACHINE工具默认取了第一个。解决办法是在顶层模块中显式声明主从关系或者在实例化时用参数标记主TAP。如果Tessent版本支持TAP连接关系声明优先使用它不要依赖文件中的出现顺序。这类问题很容易被忽视因为单独编译每个TAP文件都正常但合并后行为就变了。合并前先明确设计意图哪个TAP是外部唯一入口哪些TAP是内部从属然后再写连接关系。6.5 不同Tessent版本之间的ICL语法差异Tessent不同版本对ICL的支持程度和关键字略有差异。老版本可能不支持某些模板新版本可能对端口的默认行为做了调整。最稳妥的做法是固定一个团队统一使用的Tessent版本并且把官方ICL参考手册的版本号记录在项目文档里。升级工具前先跑一遍全量ICL编译回归确认语法兼容性。错误现象常见原因快速排查方法port not connected端口名拼写或大小写不一致对比两端的端口名确认完全一致TDR_ADDR重复同一父节点下地址冲突检查报错实例的父SIB二分法定位TDR在链中不可见scan_in/scan_out连接中断查看扫描路径报告寻找断开点多TAP识别错主实例化顺序或未声明主从显式声明主TAP指定TAP连接关系版本语法差异工具版本升级导致统一版本升级前做全量ICL编译回归我个人的体会是ICL语法本身不难难点在于“语义一致性”。你必须时刻记得ICL描述的是一张意图层面的接线图它要和RTL实现严丝合缝。工具不会替你做这个检查它只是忠实地按照你的描述干活。所以每写完一个模块我都会问自己三个问题地址对不对端口连全了吗和RTL命名一致吗这套自检习惯帮我避免过太多在ATE上才发现的问题。最后再分享一个小技巧写完ICL不要急着往下走花五分钟用Tessent的lint/check功能跑一遍再花十分钟把报告里的warning逐个过目。磨刀不误砍柴工后面做pattern retargeting、做诊断分析时你就知道这一步的投入有多值。
返回列表