ARTICLE DETAIL

资讯详情

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

Chroma转爱德万V93000:Pattern转换脚本实战与踩坑总结

Chroma转爱德万V93000:Pattern转换脚本实战与踩坑总结 做IC测试的人多少都碰到过这种尴尬一套测试程序在Chroma平台上跑得好好的良率、稳定性都验证过了结果客户或封测厂一句“换到爱德万平台”整个测试程序就得推倒重来。最让人头疼的还不是那些measurement条件而是pattern——成千上万行的数字向量靠手工根本没法搬。这篇就从我去年做过的一个实际项目说起写一个脚本把Chroma测试机的pattern文件转换成爱德万V93000能识别的pattern格式。整个过程涉及格式解析、时序映射、电平映射、校验回归踩了不少坑也积累了一些方法论分享给同样在跟pattern迁移较劲的测试工程师。1. 为什么必须写这个脚本Chroma转爱德万的现实困境1.1 测试平台切换不是少数派需求很多人以为测试程序写好了就能在一个平台上用到老实际根本不是这么回事。芯片量产过程中封测厂产能调配、客户指定第二供应商、多site并行扩产任何一个环节变动都可能导致测试平台切换。以我遇到的这个项目为例产品原本在Chroma的机型上做量产测试程序、硬件、良率数据都齐了。结果客户那边要求增加一个备用封测厂而那个厂的主力机型是爱德万V93000。于是整个测试程序——包括pattern、timing、levels、测试flow——全部要迁移过去。这种跨平台迁移里pattern是最底层的硬骨头。它能直接决定一颗芯片能不能被正确激励和判断动一个bit都可能影响测试结果。所以转换脚本不是“能转就行”而是要保证转换后的pattern在逻辑行为、时序关系、电平定义上和原来完全一致。1.2 手动转换为什么不可行有人可能觉得pattern不就是一堆0和1吗复制粘贴不就行了。真的上手做一次就知道太天真了。一个中等规模的数字IC测试pattern动辄几万行向量还夹杂着循环、子程序、macro调用、时序组切换。Chroma导出的格式和爱德万用的格式在引脚顺序、波形定义、数据类型标识上都对不上。手工转的话眼神再好也扛不住几万行的扫描转完也不敢保证没抄错。而且这个工作量不是一次性投入。产品版本更新pattern跟着改同一个产品多个测试方案pattern又要有不同版本。每来一版都靠手转等于把自己变成人肉转换器。所以写一个脚本把转换过程自动化、可重复、可校验是唯一靠谱的路子。这也是我把整个方案定位成“脚本工具”而不是“一次性的转换作业”的原因。2. Pattern文件拆解两种格式到底差在哪2.1 Chroma pattern导出格式的典型结构要写转换脚本第一步是吃透两边格式。先说Chroma这边。不同型号、不同软件版本导出的pattern格式不完全一样但我接触到的主流导出文件核心结构基本可以拆成四块文件头和注释区记录产品名、生成时间、软件版本、测试项目名称等信息通常是//或者;开头。引脚定义区声明pattern里用到的所有引脚名称以及它们在向量中的排列顺序。这跟后面向量每一列对应谁直接相关。时序定义区包括测试周期period、各信号波形的边沿位置、采样点strobe位置等。向量数据区真正的主干部分每一行代表一个周期的激励和期望值。以一个简化过的Chroma导出文本为例大致长这样// Chroma Pattern Export PIN: A0 A1 A2 A3 DIN CLK OUT1 OUT2 PERIOD: 100ns LEVEL: VIH3.3 VIL0 VOH1.5 VOL0 VECTOR: 0000 000 1 L 0001 001 1 H 0010 010 0 Z 0011 011 0 L这里的向量行前四位是地址信号接着是数据输入再往后是时钟和输出期望值。L和H一般表示期望输出为低或高Z表示高阻X表示不关心。当然真实产品的pattern要复杂得多还有repeat循环、label跳转、match loop这些控制结构。但不管多复杂解析的时候都是先找结构再逐段处理。2.2 Advantest V93000的pattern格式要求爱德万V93000这边的pattern格式就要“讲究”一些。V93000上常用的pattern描述方式有原生格式也有通过STIL、WGL这类标准语言导入。实际量产中SmarTest软件加载pattern后最终会把它编译成测试机能直接执行的二进制形式。脚本要做的是生成一个SmarTest能正确导入的文本pattern文件。V93000的pattern文件核心内容也可以分成几块PATTERN头声明pattern名字有时还带版本、注释。PIN声明列出当前pattern用到的所有引脚一般用测试机通道名或DUT引脚名。TIMING/WAVEFORM区定义测试周期、各引脚在不同操作时刻的波形边沿位置。LEVEL区定义各信号的高电平值、低电平值、期望电平、负载条件等。VECTOR区按周期排列的激励和期望值每列对应一个引脚。有个关键点要特别注意V93000的vector区通常不是简单的一列一个bit而是按“每个引脚一个字符位”的方式排布且引脚顺序必须和PIN声明一致。转换脚本如果只搬运数据、不处理引脚顺序结果就是SmarTest导入时报pin count mismatch或者数据错位。2.3 转换前必做的字段差异对照两类格式拆解完先别急着写代码把差异列成一张对照表后面每一步都对着它来能避免很多低级错误。对比项Chroma导出格式以我接触的版本为例Advantest V93000 pattern格式文件头//注释信息较随意有严格的PATTERN声明块引脚顺序按导出时设置的顺序必须与PIN声明块严格一致周期定义单独PERIOD字段通常放在TIMING/WAVEFORM区逻辑值符号0/1/L/H/Z/X按波形格式映射可能用0/1/0/1/Z/X或自定义字符期望值表示L/H直接标在向量里需要区分drive和compare常通过波形格式体现循环控制文件内文本形式展开或macro调用有专门的loop/repeat语法这张表看起来简单但每一条背后都有坑。比如期望值表示这一条Chroma里可能在向量位直接写L表示期望低电平而V93000里需要通过波形格式来区分激励和比较时刻。如果脚本直接把L原样输出导入后可能被当成当前时刻的驱动值而不是比较值功能测试必然失败。3. 转换脚本的实现思路与关键代码3.1 脚本语言选型和整体框架设计这个转换任务本质上是“文本解析数据重排文本生成”用Python最合适。原因很简单字符串处理方便、正则表达式成熟、不用编译、改起来快。而且测试工程师大多能看懂Python后续维护不需要额外学习成本。脚本整体架构我设计成四个模块各管一段方便单独调试解析模块读入Chroma原始pattern文件把引脚、时序、电平、向量数据抽出来存成统一的内存结构。映射模块把Chroma的引脚名映射到爱德万的测试通道名把时序参数、电平参数按规则转换成V93000的对应描述。转换模块把中间结构的向量数据按V93000的引脚顺序和波形格式重排生成目标pattern内容。校验模块对转换前后的文件做静态一致性检查包括引脚数量、向量行数、关键时序值等。这种模块化设计最大的好处是即使后面碰到一个新的Chroma导出格式变体只需要改解析模块里的解析规则其他部分基本不动。3.2 解析模块把Chroma原始文件读成中间结构解析的关键是识别“结构边界”。不能一上来就逐行处理向量得先找到引脚定义在哪里结束、时序定义在哪里结束、向量数据从哪里开始。我建议用“状态机正则”的方式一行一行扫过去通过关键字把文件分成几个区段。下面是我用的核心解析代码骨架去掉了一些跟具体产品绑定的细节保留框架逻辑import re from dataclasses import dataclass, field dataclass class PatternData: pins: list field(default_factorylist) period_ns: float 0.0 levels: dict field(default_factorydict) vectors: list field(default_factorylist) # 每项是[0000, 000, 1, L] def parse_chroma_pattern(filepath): pat PatternData() section None with open(filepath, r, encodingutf-8, errorsignore) as f: for raw_line in f: line raw_line.strip() if not line or line.startswith(//): continue if line.startswith(PIN): section pin pat.pins line.split()[2:] # 去掉 PIN: 两个字符 continue if line.startswith(PERIOD): m re.search(r([\d.])\s*(ns|us|ps)?, line) if m: value float(m.group(1)) unit m.group(2) or ns if unit us: value * 1000 elif unit ps: value / 1000 pat.period_ns value continue if line.startswith(LEVEL): section level continue if line.startswith(VECTOR): section vector continue if section level: for item in line.split(): if in item: k, v item.split() pat.levels[k] float(v) elif section vector: parts line.split() if parts: pat.vectors.append(parts) return pat这段代码做的事情很朴素识别关键字把数据放进统一的PatternData结构里。但有几个细节值得说说。第一errorsignore是必须的因为很多从测试机导出的文本文件编码不一定干净里面可能混着特殊字符。第二向量数据我保留成字符串列表不做数值转换。原因很实际address这一列可能是十六进制表示的也可能带负数偏移做repeat循环如果一进来就转int后面处理反而麻烦。3.3 映射模块引脚、时序、电平三件套解析只是第一步真正的转换难点在映射。这里说的映射包含三个层面引脚映射、时序映射、电平映射。引脚映射是最容易出错的。Chroma导出文件里的引脚名比如A0, A1, DIN, CLK在爱德万测试机上对应的是通道名比如CH001, CH002这一类的物理通道也可能是测试程序里重新定义过的逻辑引脚名。转换脚本里必须有一张映射表把两边对应关系列清楚。我建议把这张映射表放到一个独立的配置文件里而不是硬编码在脚本中。因为不同项目的硬件接口不一样引脚映射关系几乎必然不同。def map_pins(chroma_pins, pin_map_config): 根据配置文件把Chroma引脚名映射为Advantest引脚名 mapped [] for p in chroma_pins: if p not in pin_map_config: raise ValueError(f引脚 {p} 没有在映射表中定义) mapped.append(pin_map_config[p]) return mapped时序映射这个东西听着抽象说穿了就是“周期和波形边沿怎么从Chroma的表示变成V93000的表示”。比如Chroma里定义了一个时钟信号上升沿在周期的20%位置下降沿在40%位置采样点在60%位置。到了V93000里需要把这些百分比或绝对时间值填到对应的波形定义里。这里有个容易忽视的点时延基准不同。Chroma的边沿位置有时候是相对整个周期开始的有时候是相对某个参考信号的沿。转换前一定要确认清楚否则差半拍是常态。电平映射相对简单但也不能轻视。VIH/VIL/VOH/VOL这些值两边单位通常都是伏特直接搬就行。但要注意Chroma导出的电平值可能带电压档位描述、过冲参数、负载电流等附加信息这些在V93000的level区里不一定有对应的字段需要决定是忽略还是转换成合理默认值。我的做法是凡是目标格式里没有明确对应关系的字段统一在输出文件里用注释标注出来人工确认一遍绝不让脚本自作主张丢掉。3.4 输出模块生成爱德万可识别的pattern文件输出模块负责把中间结构的数据按照V93000的格式要求写出去。这里我直接给出一个简化但结构完整的输出示例实际生产环境里SmarTest导入时需要的头字段比我这个要多但基本骨架是一致的def write_advantest_pattern(pat, mapped_pins, outpath): with open(outpath, w, encodingutf-8) as f: f.write(PATTERN %s;\n % pat.name) f.write(PIN: %s;\n % .join(mapped_pins)) f.write(TIMING:\n) f.write( PERIOD %sns;\n % pat.period_ns) # 这里按实际项目需要逐pin写波形格式 for pin in mapped_pins: f.write( WAVE %s: DRIVE0 0ns, DRIVE1 25ns, COMB 60ns;\n % pin) f.write(LEVEL:\n) for k, v in pat.levels.items(): f.write( %s %sV;\n % (k, v)) f.write(VECTOR:\n) for vec in pat.vectors: # 按mapped_pins顺序重排每列数据 reordered reorder_vector(vec, pat.pins, mapped_pins) f.write( %s\n % .join(reordered))reorder_vector这个函数是整个转换正确性的核心。它的逻辑是拿到Chroma原始向量里的每一列根据原始引脚顺序找到对应的逻辑信号名再根据映射后的引脚顺序放回新的位置。说白了就是把“按Chroma引脚顺序排的数据”重排成“按V93000引脚顺序排的数据”。这一步做对了转换工作就完成了大半。输出格式这块我有句经验之谈不要试图一次生成最终完美格式。第一次跑通脚本先输出一个简化版pattern能导入SmarTest就行。然后逐步补齐字段每补一个字段就跑一次SmarTest的编译检查。这样比一次性生成完整文件再回头排查要高效得多。4. 转换后的校验与回归测试怎么做4.1 静态校验内容对得上不等于能用脚本跑完第一反应肯定是打开转换后的文件看一眼。但我建议别急着人工看数据先跑静态校验脚本来做几项硬性检查。第一项是引脚数量和顺序。Chroma原始引脚数必须等于映射后的引脚数且顺序必须严格按映射表排列。第二项是向量行数。转换前后去掉注释和空白行后向量总数要一致。第三项是特殊符号集检查。把所有向量数据里出现过的字符收集起来跟目标格式允许的逻辑值符号集合做比对一旦出现目标格式不认识的字符直接报错。静态校验脚本我一般这么写def static_check(src_pat, dst_pat, mapping): errors [] if len(src_pat.pins) ! len(dst_pat.pins): errors.append(引脚数量不一致: %d - %d % (len(src_pat.pins), len(dst_pat.pins))) if len(src_pat.vectors) ! len(dst_pat.vectors): errors.append(向量行数不一致: %d - %d % (len(src_pat.vectors), len(dst_pat.vectors))) allowed_chars set(01LHZX) for i, vec in enumerate(dst_pat.vectors): for token in vec: for ch in token: if ch.upper() not in allowed_chars: errors.append(第%d行出现非法符号: %s % (i 1, ch)) break return errors这些校验全通过只能说明“文件结构上内容对得上”不能说明“测试结果会一致”。接下来还得做更接近真实行为的验证。4.2 动态验证模拟比对与上机回归动态验证我分成两步走。第一步是模拟比对。如果你的测试环境里有EDA仿真工具可以把转换前后的pattern分别喂给同一个DUT仿真模型比对仿真输出是否一致。这一步能在上机前拦掉大部分功能性错误尤其是向量重排导致的信号错位问题。没有仿真环境的项目退而求其次可以写一个简单的pattern diff工具逐行对比转换前后的向量但要把“合法变化”排除掉比如引脚顺序变化、字符大小写变化、注释位置变化。第二步是上机回归。上机验证不是随便跑一遍看着pass就完事。正确的做法是在Chroma和爱德万上分别跑同一个DUT尽量用同一批芯片把每一颗的pass/fail结果、关键测量值记录下来做一致性对比。尤其要关注边界条件附近的芯片——在Chroma上fail边缘的芯片在爱德万上如果变成pass或是反过来都说明转换后的timing或level跟原平台有细微差异。这种差异在上机数据里是藏不住的。我还习惯做一步“反向抽样”验证从转换后的爱德万pattern里随机抽几十行手工跟Chroma原始文件比对。随机抽样别看只查几十行它能在最短时间内暴露系统性错误比如整体偏移一位、某几列数据串位这种问题。5. 转换过程中最常见的5个坑与排查方法5.1 Pattern mismatch最常见的起因转换上线后最常被测试工程师挂在嘴边的问题就是“pattern mismatch”。这个词听着吓人其实九成以上的mismatch在转换脚本里都有明确出处。我排查mismatch问题时不会一上来就怀疑脚本算法而是先做三件事查第一列向量、查引脚映射表、查复位序列。很多pattern的第一行是复位或初始化序列里面的值往往跟后续功能向量长得不一样。如果转换脚本对首行的特殊处理不到位第一行错了后面全部连锁错误。检查完第一行再看引脚映射表有没有配错。我遇到过最阴的错是两个引脚名在映射表里写反了导致A0和A1数据整个交换所有向量在边界情况下就不停mismatch。最后是通过随机抽样比对才发现规律。5.2 时序边沿差一拍的问题还有一个高频坑是时序边沿“差半拍”。Chroma里波形边沿如果是相对时钟下降沿定义的而V93000里默认是相对周期起点或者某个参考沿那么转换后所有信号的建立时间、保持时间都会偏差。症状就是功能测试低频pass、高频fail或者在不同温度条件下不稳定。排查这类问题要把转换前后的波形定义打印出来逐参数比对特别关注三类数据时钟上升沿和下降沿的位置、数据信号相对时钟的建立保持时间、输出采样点的位置。任何一个参数在多平台间对不上都可能导致边缘性mismatch。5.3 电平值没按要求映射电平问题也容易踩。比如DUT的输出是开漏结构期望高阻态ZChroma里对应位可能是Z但转换脚本如果没把Z正确映射到V93000的波形格式里可能被解释成X不比较或者强行驱动低电平结果就是输出对比异常。另外常见的是VOH/VOL和VOL/VOH写反。两个平台的level区字段顺序不同直接从Chroma里搬过去如果不加映射逻辑很容易把高低电平值对调。这种错误在静态校验里很难发现因为数值都在、字段也都在只有在低频测试里看到输出逻辑反了才暴露。5.4 循环和子程序展开丢失再讲一个更隐蔽的坑循环和子程序。Chroma里如果pattern用了repeat 100这样的循环结构而转换脚本没有做展开转换那转换后的总向量行数跟原始逻辑行数对不上。行数对不上静态校验立刻能报错这反而好查。怕的是脚本做了展开但展开次数计算错了。展开次数这种问题建议不要用眼睛数直接在解析模块里把循环展开后的逻辑向量总数打印出来跟原始文件里的循环声明交叉验证。比如原始文件里写了repeat 100展开后至少要比不展开多99行这个数差可以自动检查。5.5 排查速查表把踩过的坑整理成一张速查表遇到问题先对着查比盲目翻代码高效得多。异常现象优先排查方向检查方法从第一个向量开始mismatch复位/初始化序列手动比对转换前后前10行固定某一列或某几列数据错误引脚映射表抽查映射表反向查回原始文件低频pass高频fail时序边沿定义对比波形参数确认基准沿输出逻辑整体反相电平映射VOH/VOL核查level区字段顺序vector行数不一致循环/子程序展开打印展开前后统计数字SmarTest导入报错头字段缺失或语法错逐段检查PATTERN/PIN/TIMING块6. 把脚本做成能复用的工具我的几点体会6.1 接口设计成可配置项目做完脚本能跑只是及格线。真正让它值钱的是能不能在下一次接到类似转换需求时直接复用。我的经验是把所有跟具体项目相关的参数都抽出来做成配置文件引脚映射表、电平字段映射规则、时序基准定义、输出格式模板全部外部化。脚本主体保持“纯逻辑”不写死任何一个项目专属的值。这样换一个产品、换一台测试机改配置文件就行不用动代码。6.2 保留日志和diff能力第二个建议是脚本一定要留完整日志。我最初版本只管转换、不管记录结果出问题时根本想不起来当时跑了什么参数。后来加了日志模块每次转换自动生成一个带时间戳的diff报告记录原始文件名、配置文件版本、映射表内容、转换后的校验结果。这个习惯救了我好几次客户说“这个pattern好像有问题”我能直接调出当时的转换日志跟他对。6.3 后续扩展方向这个脚本后续还能往几个方向扩展。一是支持更多格式很多Chroma导出文件实际上是STIL或WGL变体可以让脚本直接支持导入STIL、导出STIL这样对接其他平台也方便。二是增加批量转换能力一个产品通常有几十个pattern文件批量跑完统一输出一份汇总报告。三是接入测试程序版本管理转换脚本跟测试程序一起入版本库每版pattern变更都能追踪到。我个人在写完这个脚本之后最大的体会是跨平台pattern转换这件事难点从来不在“0和1怎么搬”而在“搬的时候那些看不到的约定怎么处理”。引脚顺序、时序基准、电平映射、循环展开每一个细节都藏着坑。把规则明确到配置文件里把校验做进脚本流程里再用上机数据兜底验证这套思路不仅适用于Chroma转爱德万也适用于任何两个ATE平台之间的pattern迁移。希望这篇能帮后来的人少走几步弯路。
返回列表