ARTICLE DETAIL

资讯详情

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

Allegro泪滴自动化:SKILL脚本开发与批量处理实战

Allegro泪滴自动化:SKILL脚本开发与批量处理实战 《Allegro泪滴自动化SKILL脚本开发与批量处理实战》在Allegro里给过孔加泪滴这件事单板、几十个过孔时就是个顺手操作可一旦板子上有成百上千个过孔或者手头躺着十来块结构相似、网表不同的板卡等着发板手工点鼠标的路子就彻底走不通了。我写下这篇博客是因为我在这条路上踩了不少坑也想把用SKILL脚本做泪滴自动化、再把单板脚本扩展到目录级批量处理的完整思路整理出来。如果你也用Cadence Allegro画PCB被泪滴的一致性、重复劳动和发板前的夜间检查折磨过这篇文章就是写给你看的。1. 为什么我对泪滴死磕到底电路、工艺与制造的三层账很多刚入行的工程师觉得泪滴就是个装饰画上去“好看点”而已。实际上泪滴是焊盘和走线之间的过渡铜箔它解决的是从机械可靠性到制造良率的一整条链路问题。我见过不少板子在振动测试时过孔拉裂最后查下来就是泪滴没加、走线到焊盘之间是直角过渡应力全集中在那一小块铜上。第一层账是机械可靠性。过孔焊盘和走线连接处是一个典型的应力集中点热胀冷缩、振动、跌落冲击都会在这个位置反复施加应力。如果没有泪滴走线从窄变宽是突变应力会集中在拐角有了泪滴截面逐渐过渡应力梯度被摊薄疲劳寿命明显不一样。车规、工控、通信设备这类需要过可靠性测试的板子泪滴几乎是硬性要求。第二层账是制造容差。钻孔有钻偏蚀刻有侧蚀如果焊盘到走线的连接宽度本来就只有6mil制造端稍微偏一点就可能出现“虚连”甚至“开路”。泪滴相当于给这条连接加了一道保险把接触宽度做大把制造偏差的冗余做足。板厂DFM审核时,很多工厂也会主动提醒你哪些位置建议加泪滴原因就是他们的良率统计里无泪滴板子的开路缺陷率明显偏高。第三层账才轮到电气。走线宽度突变会产生局部阻抗不连续高频信号经过时会形成反射。泪滴是一个渐变过渡结构比突变台阶的反射要小。另外在大电流通道上泪滴还能平滑电流密度分布减小局部过热点。当然这里有个前提——泪滴尺寸必须合适。我做过的DDR4、PCIE这类高速板泪滴参数反而要调小甚至局部区域不加因为过渡区域本身在高频段就是一个不连续点泪滴越大等效于多了一小段寄生电容。还有一个容易被忽略的点泪滴不是“加得越多越好”。射频走线、严格阻抗控制的差分线、BGA扇出细线区都建议谨慎处理。我的经验是先在项目规则里定清楚“哪些网络必须加、哪些网络绝对不加”再让脚本去执行规则而不是靠每个工程师打开板子凭感觉发挥。场景是否加泪滴原因高可靠工业/车规/通信板加应力、温度循环、振动可靠性普通电源板加大电流平滑过渡制造容差冗余DDR/PCIE等高速信号选择性加参数调小避免寄生电容和阻抗突变BGA扇出细线区选择性加线宽太小泪滴容易挤占间距50Ω射频走线基本不加任何形状突变都可能破坏阻抗连续性2. Allegro原生泪滴工具到底差在哪三个典型场景先说句公道话Allegro原生泪滴工具本身不弱。菜单路径是Route Teardrop命令行直接敲teardrop也能调出来。它能选引脚、选过孔、按网络过滤形状有SMOOTH、FILLED等选项还有一个比例参数控制泪滴大小。单板、几十个过孔的场景下我用原生工具三五分钟就搞定了完全没毛病。但原生工具在三个典型场景下会让人抓狂。第一个是BGA扇出的板子。一颗大BGA扇出后少说几百个微过孔整板加起来动辄两三千个过孔。原生工具虽然能全选但它的交互逻辑是按“当前选中对象”来处理的你要么全选之后统一加结果就是连不该加的电源、地网络的过孔也全加了要么分组选择一次又一次地框选、过滤、应用,一晚上就耗在鼠标上了。更麻烦的是加完之后你会发现有些过孔因为层叠关系、网络属性差异,泪滴形状不一致,又得手动微调。第二个是产品线多块板卡的一致性问题。在我待过的团队里经常是同一套硬件方案衍生出七八个型号板子结构相似但网表不同。工程师A加泪滴用25%的比例工程师B觉得30%更饱满,最后每块板的泪滴风格都不一样。发板前的评审会上这种细节就会被翻出来说。这不是某个人画板水平的问题是缺少一个统一、可重复的执行工具。第三个是ECO之后的重做。结构改版、换器件、调走线之后泪滴不会自动跟着新走线重新生成。老的泪滴还在那里新加的走线又缺泪滴这个时候你要先删掉受影响的泪滴再对改动区域重新加。手工做这件事漏几个点是必然的而且很难通过目检完整地查出来——你自己根本记不清之前哪个过孔加过哪个没加过。这三个场景叠加在一起我就决定写SKILL脚本了。脚本的好处是规则写死、执行一致、重复跑不累、还能纳入版本管理。同一个脚本今天跑、下周跑、换个人跑出来的板子是一样的。3. SKILL开发前的接口选型与环境准备SKILL是Cadence平台自己的脚本语言语法类似Lisp但封装了大量AXL数据库访问接口。做泪滴自动化我们直接操作的是Allegro的数据库对象:引脚、过孔、网络、铜箔,所以核心是搞清楚用哪一层接口。常见的路子有两条。一条是axlShell也就是在SKILL里模拟用户在命令窗口输入原生命令比如axlShell(teardrop)然后试图用表单自动化去操作界面。这条路的优点是接口稳定、不涉及底层数据结构缺点是极度脆弱——Allegro的界面表单、焦点、版本差异随便一个变化都能让脚本失效而且速度慢、没有返回值可以判断成功失败。我早期试过后来放弃了。另一条路是直接调用AXL数据库API也就是axlDB*系列函数。这类函数直接读写数据库对象能拿到引脚、过孔的dbid能查询网络属性能调用添加/删除泪滴的接口。它的优点是逻辑清晰、可判断成功失败、不依赖界面焦点性能也好得多。缺点是需要翻SKILL Function Reference不同版本之间函数签名确实有差异。我的建议很明确用AXL路线别碰界面模拟。开发环境准备方面最简单的用法是在Allegro命令窗口执行skill load(C:/skill/tear_drop_auto.il)然后在命令行执行脚本里定义的命令。load是SKILL加载文件的标准函数路径里的斜杠用正斜杠反斜杠在SKILL字符串里会被当作转义字符容易出问题。如果想让脚本在每次启动Allegro时自动加载就把load语句写进用户目录下的allegro.ilinit文件。这个文件是Allegro启动时自动加载的SKILL初始化文件很多第三方skill插件都是这样挂载的。我个人的习惯是开发阶段手动load调试稳定之后再考虑写进ilinit避免脚本有问题时连Allegro都启动不了。还有一件必须做的事核对版本函数签名。Allegro 16.6、17.2、17.4的AXL接口存在差异,同一个axlDBAddTearDrop在不同版本里参数顺序、关键字参数写法可能都不一样。我不会在文章里把每个版本的签名背一遍因为那样太容易过时。正确做法是打开你安装目录下的SKILL Function Reference PDF搜TearDrop相关条目或者在一个测试副本板子上先跑一个最小函数验证。这个习惯能帮你避开八成以上的版本坑。轻量验证一下环境是否正常skill axlDBGetPins()如果返回一个列表哪怕列表是空的说明AXL接口已经在这个会话里可用。如果报错先检查是否在PCB Editor环境里启动的SKILL而不是在别的Cadence工具的SKILL环境。4. 核心脚本拆解单板泪滴自动化的完整实现下面这个脚本是整条流水线的心脏干的事就三件拿到板子上所有引脚和过孔按过滤条件筛出需要处理的对象逐个添加泪滴并统计成功失败数。我用的是Allegro 17.2环境下的AXL接口写法16.6和17.4请按前面说的方法核对签名。; tear_drop_auto.il ; 单板泪滴自动化脚本 ; 用法: ; skill load(C:/skill/tear_drop_auto.il) ; td-auto ; 全板加泪滴 ; td-auto FILLED 30.0 (TOP BOTTOM) (GND POWER5V0) ; ; 只给指定网络加指定层 ; td-clear ; 删除板子上所有泪滴 (defun td-add-single (obj layer shape size) (axlDBAddTearDrop obj ?layer layer ?shape shape ?size size)) (defun td-filter-by-net (objList netFilter) (let (out) (foreach obj objList (when (and obj-net (member obj-net-name netFilter)) (setq out (cons obj out)))) (reverse out))) (defun td-auto (optional (shape SMOOTH) (size 25.0) (layers (TOP BOTTOM)) (netFilter nil)) (let (objList cnt fail ok) (setq objList (append (axlDBGetPins) (axlDBGetVias))) (setq cnt 0) (setq fail 0) (when netFilter (setq objList (td-filter-by-net objList netFilter))) (foreach obj objList (setq ok t) (foreach layer layers (when ok (if (errset (td-add-single obj layer shape size)) (setq cnt ( cnt 1)) (setq ok nil)))) (unless ok (setq fail ( fail 1)))) (printf Tear drop done. Added%d Failed%d\n cnt fail))) (defun td-clear (optional (layers (TOP BOTTOM))) (let (objList cnt) (setq objList (append (axlDBGetPins) (axlDBGetVias))) (setq cnt 0) (foreach obj objList (foreach layer layers (when (errset (axlDBDeleteTearDrop obj ?layer layer)) (setq cnt ( cnt 1))))) (printf Tear drop cleared%d\n cnt)))我逐段说下为什么这样写。td-add-single是真正调用泪滴API的封装。把它单独拆出来的原因是万一版本接口签名变化只需要改这一个函数不需要动外层逻辑。axlDBAddTearDrop的入参里我用了?layer、?shape、?size这种关键字参数这是SKILL风格里比较常见的写法。shape传字符串“SMOOTH”或“FILLED”size我传25这个值含义是泪滴的延伸比例具体数值对应的实际尺寸和你界面上看到的参数一致。td-filter-by-net做网络过滤。Allegro的引脚和过孔对象都有-net属性取到网络dbid之后再用-name拿网络名。这里有个容易忽略的细节如果引脚或过孔不在任何网络上obj-net是nil直接用obj-net-name会报错所以前面必须有and obj-net做短路保护。member做字符串列表匹配返回值用reverse倒回来是为了保持原来的对象顺序方便后面调试时对照。td-auto是主入口用optional定义可选参数。不传参数时默认给TOP和BOTTOM两层加SMOOTH形状、size 25的泪滴全板对象都处理。axlDBGetPins和axlDBGetVias分别拿所有引脚和所有过孔append拼成一个列表。这里我特意把引脚和过孔合在一起遍历因为对于脚本来说它们的处理方式完全一样没必要写两份循环。错误隔离是这段代码里我最看重的部分。errset会把表达式执行过程中的错误捕获住不中断整个脚本。如果一个对象加泪滴失败我只把fail计数加一然后继续处理下一个对象。没有这个保护遇上某个异形焊盘导致API报错脚本会在中途直接死掉后面的对象全部没处理而且你根本不知道死在哪。删除函数td-clear的逻辑和添加是对称的。我在实际项目里经常反复“先清再加”因为ECO改版后旧的泪滴可能和新的走线冲突直接在上面叠加会得到很难看的形状。所以我的脚本使用习惯是重做泪滴之前先跑一次td-clear再跑td-auto确保是从干净状态开始的。还有一点要提醒跑脚本之前一定另存一个副本。我自己曾经在批量处理时因为某个版本接口行为异常泪滴形状整批不对如果没有备份那一次改动就全废了。后来我养成了习惯任何自动化处理之前先复制一份.brd脚本跑完确认没问题再删备份。这个习惯成本很低但能救命。5. 批量处理实战多块板卡流水线化单板脚本能跑通之后真正解放生产力的是批量处理。我的场景是发板前把所有待发布的板卡全部过一遍统一的泪滴规则。这里最大的障碍不是SKILL本身而是Allegro的会话机制——一个进程里通常只能正常处理一个设计文件你要是让一个SKILL会话连续开多个板子内存和数据库状态都可能出问题。所以我的批量方案是外部循环负责遍历板卡每块板卡启动一个独立的Allegro批处理进程进程内只处理这一块板处理完保存、退出、写日志。SKILL这边的批量入口函数长这样(defun td-append-log (file line) (let (fh) (setq fh (open file a)) (when fh (fprintf fh %s\n line) (close fh)))) (defun td-batch-main () (let (brdPath logPath line) (setq brdPath (getenv TD_BOARD)) (setq logPath (getenv TD_LOG)) (when (not brdPath) (error TD_BOARD not set)) (when (axlOpenDesign brdPath) (printf Processing %s\n brdPath) (td-auto) ; 版本差异点保存接口请按你的Allegro版本核对 (axlSaveDesign ?mode incremental) (axlCloseDesign) (sprintf line %s OK brdPath) (when logPath (td-append-log logPath line))))) ; 只有当批处理环境变量存在时才会自动进入批处理模式 (when (and (getenv TD_BOARD) (getenv TD_BATCH)) (td-batch-main))这个脚本里有两个关键设计。第一个是环境变量传参。外部批处理通过设置TD_BOARD环境变量告诉SKILL“这次要处理哪块板”通过TD_LOG告诉它日志写到哪去。SKILL里的getenv能直接读到进程环境变量不需要搞命令行参数解析那一套。同时我用TD_BATCH这个环境变量作为“是否进入批处理模式”的开关——如果不加这个开关脚本在交互环境下load时只要TD_BOARD碰巧存在就会莫名其妙地自动跑批很烦人。第二个是日志。批量处理最怕的就是跑了一晚上第二天早上发现某块板失败但你不知道是哪块、为什么失败。这里我把每块板的处理结果追加写到一个CSV日志文件里每一行就是一块板的结果。外部批处理每启动一个Allegro进程处理一块板进程退出后回到外层循环继续下一块日志贯穿整个过程。对应的Windows批处理脚本echo off set TD_BATCH1 set TD_BOARD_DIRD:\release\boards set TD_LOGD:\release\td_result.csv set SKILL_FILEC:\skill\tear_drop_auto.il if exist %TD_LOG% del %TD_LOG% for %%f in (%TD_BOARD_DIR%\*.brd) do ( set TD_BOARD%%f echo Processing %%f C:\Cadence\SPB_17.4\tools\bin\allegro.exe -batch -runskill %SKILL_FILE% )这个方案的核心思路是“每块板一个独立进程”。好处有三个一是单块板处理失败不会拖垮后续板卡外层for循环会继续下一块二是内存和数据库状态天然隔离不会因为连续打开多个设计产生脏状态三是配合日志哪块板处理了多少个泪滴、成功失败数一目了然。关于-batch -runskill这两个参数不同Allegro版本写法有差异尤其是16.6和17.x之间。如果你们的版本不支持这种启动方式退路是外部批处理用allegro.exe 板子.brd把板子打开然后通过一个.scr播放文件触发脚本.scr里就两行内容skill load(C:/skill/tear_drop_auto.il) td-auto再用replay命令播放。这个方法虽然不那么优雅但在老版本环境下稳定可靠。我的观点是批处理的外壳可以迁就版本但SKILL脚本本身的逻辑要稳定统一因为那才是规则的核心。还有一点操作层面的建议批处理跑的时候不要手动再用Allegro打开同一块板子。设计文件被一个进程打开时另一个进程再打开会触发文件锁或者只读模式保存时会出问题。我在发板前的流程里都是晚上下班前挂上批处理第二天来收日志中间不碰任何设计文件。6. 踩坑实录脚本跑起来之后才遇到的五个问题脚本写完只是开始真正让人头大的是在真实板卡上跑的时候遇到的各种意外。我挑五个最有代表性的坑说。第一个坑是重复运行脚本导致泪滴叠加。第一次跑td-auto全板成功然后你改了走线又跑一次第二次跑的时候有些过孔上已经存在泪滴再添加一次就会出现形状怪异、尺寸异常甚至DRC报错的泪滴。我的解决办法前面说过了批处理流程里先td-clear再td-auto保证每次都是从干净状态开始。宁可先删再加也不要让脚本去做“是否已存在”的判断因为不同版本里判断泪滴是否存在的API行为不一致多做一步判断反而更容易出错。第二个坑是电源和地的网络。全板遍历时GND和电源网络上的过孔往往连接大片铜皮本身已经有足够宽的连接通道强行加泪滴反而会产生尖锐夹角成了新的应力隐患。另外内电层上的过孔通常连接电源平面泪滴加在平面和过孔之间经常形成奇怪的形状。后来我在脚本里加了netFilter参数默认跑全板但电源网络上会明确排除或者单独跑一个“只处理信号网络”的过滤版本。处理完之后再人工快速扫一遍电源网络区域基本就稳了。第三个坑是高速信号线上的泪滴尺寸。我刚把脚本应用到DDR4板卡时用的还是25的size结果发现走线靠近过孔的区域明显变粗阻抗一致性受影响。后来对高速网络做了一版专门规则要么不处理要么用很小的size只在TOP/BOTTOM外层加。这里我的建议是脚本只负责“按规则执行”规则本身必须是硬件工程师在项目前期定好的。泪滴自动化不是让你闭着眼给全板所有过孔加一遍而是让你闭着眼也能按既定规则精确执行。第四个坑是批处理环境的隐藏依赖。有的SKILL脚本会在运行时读取用户在图形界面里设置过的环境变量、用户偏好文件、菜单配置这些东西在批处理模式下可能根本没加载。我遇到过脚本在交互式Allegro里跑得好好的一到批处理就跑挂最后发现是脚本里用到了某个只在交互会话初始化的全局变量。解决方法是把脚本写成“不依赖任何交互状态”所有参数显式传入所有环境变量用getenv获取绝不引用界面里的隐含状态。第五个坑是路径。Windows路径里的反斜杠在SKILL字符串里是转义字符D:\release\boards这种写法在SKILL里会把\r、\b解析成奇怪的东西。我统一在SKILL里用正斜杠写路径批处理里的环境变量值同样在设置时就转成正斜杠或者用set命令赋值时把反斜杠改成双反斜杠。这个问题排查起来特别隐蔽因为有时候只在特定的目录名组合下才触发。脚本跑完之后的验证同样重要我每次都会做三件事。第一看脚本输出的Added/Failed计数Failed应该为0不为0就说明有对象处理失败需要定位。第二跑一遍DRC对比处理前后的DRC报告新增的错误里如果集中在泪滴区域那就是参数或者范围的问题。第三打开板子随机抽查若干过孔尤其看BGA区域和连接器区域的泪滴形状是否饱满、均匀。批量场景下我会把日志文件拉出来确认每一块板的成功失败数都在预期范围内。最后一个我自己的使用窍门脚本文件一定要纳入版本管理和板子、原理图一样提交。泪滴规则不是一次定死就永远不变的随着产品迭代、工艺能力变化、板厂反馈参数会调整。有版本管理你才能知道哪一版脚本应对的是哪一批板的处理结果出了问题也能回溯。我在实际工作中见过不少“脚本躺在个人电脑里、人走了规则就没了”的情况这种事落在发板环节真的很伤。
返回列表