Cadence Allegro SKILL脚本实战:快速提取单颗元件封装、引脚与网络信息 1. 先搞清楚这个“汇出”到底能帮你解决什么问题在PCB设计尤其是复杂板卡的设计后期经常遇到一个很具体但很烦人的问题需要单独提取某个关键芯片或元件的封装、网络、属性等信息。比如你想把某个BGA的封装和引脚定义单独发给封装工程师核对或者想快速统计一个连接器上有多少引脚已经使用、多少悬空。手动在整板设计中一个个去数、去复制粘贴不仅效率低还容易出错。“利用SKILL汇出单颗零件”这个主题就是解决这个痛点的。它不是一个花哨的炫技而是一个能直接提升协作效率和设计自查精度的实用技能。最核心的价值就两点一是能快速、准确地“拆解”出你指定的任何一个元件生成一份独立的、包含所有关键信息的报告或文件二是能基于这份报告轻松完成像引脚数量统计这样的衍生任务。这篇文章适合所有使用Cadence Allegro进行PCB设计的工程师无论你是刚接触SKILL脚本的新手还是想寻找更高效设计检查方法的老手。我会从最基础的“如何选中目标零件”开始一步步拆解整个SKILL脚本的编写思路和关键代码最后附上一个非常实用的“BonusTip”——自动统计引脚数量。整个过程你会看到如何从一个具体的需求出发写出一个即拿即用的工具脚本而不是泛泛而谈SKILL语法。2. 动手前的准备理解“零件”在Allegro数据库中的样子在开始写代码之前我们必须先弄明白在Allegro的SKILL世界里我们想操作的“单颗零件”到底是什么以及怎么找到它。这是所有后续操作的基础跳过这一步代码就会像无头苍蝇。2.1 零件的标识RefDes 与 DBID在Allegro中每个元件Component最直观的标识就是它的位号Reference Designator比如U1C102J5。我们的脚本首先就要能通过这个位号找到目标。但是SKILL底层操作通常不直接使用字符串位号而是使用一个更底层的对象——DBID。你可以把DBID理解为Allegro数据库内部给每个对象线、过孔、元件、引脚分配的唯一身份证号。我们的脚本逻辑通常是用户输入位号 - 程序通过位号找到对应的元件DBID - 通过DBID获取该元件的所有详细信息。所以第一步技能就是如何通过位号获取元件的DBID。这里会用到axlDBGetDesign和axlSelectByName等函数。2.2 零件的“身体”封装、引脚与网络找到元件DBID之后我们需要“拆解”它。一个元件在PCB设计中主要包含以下几部分信息我们的“汇出”目标就是它们封装Package Symbol元件在板上的物理轮廓、焊盘形状和尺寸。这决定了制造和装配。引脚Pins每个引脚都有编号、坐标、所在的层TOP/BOTTOM。网络Net每个引脚连接到了哪个电气网络Net Name比如VCC_3V3GNDPCIE_TX0_P。这是电气连接的核心。属性Properties元件本身的属性如Value阻值/容值/型号、Tolerance、Part Number等。一个完整的“汇出”脚本应该能把这些信息有条理地提取出来。我一般会建议按这个顺序来思考和编写代码先确保能抓到元件再抓取它的引脚列表然后遍历每个引脚获取网络最后整理封装和属性信息。3. 核心实现分步编写“零件汇出”脚本下面我们抛开理论直接进入实战。我会把脚本拆成几个功能模块你可以像搭积木一样理解和组合它们。3.1 第一步让用户选择或输入目标零件有两种常见的交互方式一种是在命令行输入位号另一种是直接用鼠标在PCB设计界面上点选。对于“汇出单颗”这个场景鼠标点选更加直观和不易出错。; 方法一鼠标点选元件 axlClearSelSet() ; 先清空当前选择集 axlSetFindFilter(?enabled (NOALL COMPONENTS) ?onButtons (COMPONENTS)) printf(请在PCB设计界面点击选择需要汇出的元件...\n) selectedObj axlSelect()这段代码做了几件事axlClearSelSet(): 确保选择状态是干净的。axlSetFindFilter(...): 设置选择过滤器。?enabled参数里的“NOALL”表示先禁用所有类型“COMPONENTS”表示只启用元件类型。这样鼠标就只能选中元件不会误选到走线或过孔。axlSelect(): 弹出提示等待用户在图形界面点击。用户点击后被点击对象的DBID会返回给变量selectedObj。为什么先设置过滤器这是血泪教训。如果不设置用户很容易误点到一根线或一个文本导致后续代码处理完全错误的对象而报错。提前锁定目标类型是写出健壮脚本的好习惯。3.2 第二步校验与获取元件详细信息用户点击后selectedObj可能是一个元件也可能用户取消了选择返回nil。我们需要校验。; 检查是否成功选择 if( selectedObj nil then axlMsgPut(“未选择元件或选择已取消。”) return nil ; 脚本结束 ) ; 获取所选对象的类型再次确认它是元件 if( selectedObj-objType ! “COMPONENT” then axlMsgPut(“错误选择的对象不是元件。请重新运行脚本并选择元件。”) return nil ) ; 现在我们可以安全地获取这个元件的详细信息了 compDbid selectedObj compName compDbid-name ; 获取元件位号如 “U1” compSymbol compDbid-symbol ; 获取元件封装符号名称拿到compDbid后我们就拥有了打开这个元件信息宝库的钥匙。compName和compSymbol是最先要记录的信息。3.3 第三步遍历引脚并获取网络信息这是整个脚本最核心的部分。元件的引脚列表可以通过compDbid-pins来获取。然后我们需要遍历这个列表中的每一个引脚对象。; 初始化一个列表来存储引脚信息 pinInfoList nil ; 遍历元件的所有引脚 foreach( pinDbid compDbid-pins ; 获取引脚编号 pinNumber pinDbid-number ; 获取引脚坐标相对于元件原点 pinXY pinDbid-xy ; 关键获取此引脚所连接的网络 ; 注意一个引脚可能连接多段线Segment我们需要找到网络名 pinNet “NO NET” ; 先给一个默认值 sig car(axlGetSelSet(axlSelect(pinDbid))) ; 一种获取引脚信号对象的方法 if(sig ! nil sig-net ! nil then pinNet sig-net-name ) ; 将本条引脚信息组成一个属性列表存入总表 pinInfo list( list(‘number pinNumber) list(‘net pinNet) list(‘xy pinXY) ) pinInfoList cons(pinInfo, pinInfoList) ; 将新信息添加到列表头部 ) ; 因为上面是cons添加列表是反的反转回来 pinInfoList reverse(pinInfoList)这里有几个需要特别注意的坑点网络获取直接从pinDbid对象上可能没有直接的net属性。需要通过axlSelect或axlGetNet等函数先获取到与引脚关联的“信号”Signal对象再从信号对象上获取网络名。上面代码展示了一种常用方法。悬空引脚不是所有引脚都接了网络。对于未连接的引脚其网络名可能是nil或空。所以代码中先给pinNet一个默认值“NO NET”这样最终报告看起来更清晰。坐标系统pinDbid-xy获取的坐标是元件封装坐标系下的相对坐标。如果你需要PCB全局坐标需要进行坐标转换使用axlTransformPoint函数并传入元件的放置角度和位置。3.4 第四步生成并输出报告信息都收集好了现在需要把它们以人类可读的方式“汇出”。最简单的方式是生成一个文本文件。; 构建输出文件名例如 “U1_Export_20240515.txt” outFileName sprintf(nil “%s_Export_%s.txt” compName getCurrentTime()) outFile outfile(outFileName “w”) ; 以写入模式打开文件 ; 写入元件基本信息 fprintf(outFile “\n”) fprintf(outFile “Component Export Report\n”) fprintf(outFile “\n”) fprintf(outFile “Reference Designator: %s\n” compName) fprintf(outFile “Package Symbol: %s\n” compSymbol) fprintf(outFile “Export Time: %s\n” getCurrentTime()) fprintf(outFile “\n\n”) ; 写入引脚信息表头 fprintf(outFile “Pin NumbertNet NamettXttY\n”) fprintf(outFile “----------t----------tt---tt---\n”) ; 遍历引脚信息列表并写入文件 foreach(pinRecord pinInfoList pinNum cadr(assoc(‘number pinRecord)) pinNet cadr(assoc(‘net pinRecord)) pinXY cadr(assoc(‘xy pinRecord)) xCoord xCoord(pinXY) ; 假设pinXY是一个点对 (x . y) yCoord yCoord(pinXY) fprintf(outFile “%st%stt%st%t\n” pinNum pinNet xCoord yCoord) ) ; 关闭文件 close(outFile) axlMsgPut(sprintf(nil “元件 %s 信息已汇出至文件%s” compName outFileName))这个报告文件会保存在Allegro的当前工作目录下。你可以用任何文本编辑器打开它里面清晰地列出了元件的每一个引脚及其连接关系。这就是“汇出单颗零件”的核心成果。4. 【BonusTip】基于汇出数据实现引脚数量统计有了上面提取的pinInfoList实现引脚统计就是顺水推舟的事情。我们可以在生成报告的部分或者在文件之外直接进行数据分析。4.1 统计总引脚数和已连接/未连接数这是一个非常实用的设计检查点尤其是对于连接器、大型BGA芯片可以快速确认有没有漏连的引脚。; 初始化计数器 totalPins length(pinInfoList) connectedPins 0 unconnectedPins 0 ; 遍历统计 foreach(pinRecord pinInfoList pinNet cadr(assoc(‘net pinRecord)) if(pinNet “NO NET” then unconnectedPins else connectedPins ) ) ; 将统计结果追加到报告文件中或单独显示 fprintf(outFile “\n\n”) fprintf(outFile “Pin Count Summary\n”) fprintf(outFile “\n”) fprintf(outFile “Total Pins: %d\n” totalPins) fprintf(outFile “Connected Pins: %d\n” connectedPins) fprintf(outFile “Unconnected Pins: %d\n” unconnectedPins) fprintf(outFile “Connection Ratio: %.1f%%\n” (100.0 * connectedPins / totalPins))4.2 进阶统计按网络分组统计这对于电源芯片、去耦电容簇的检查特别有用。可以统计出VCC_CORE网络用了几个引脚GND用了几个引脚。; 创建一个哈希表property list来按网络名计数 netCountTable makeTable(“net counts” 0) foreach(pinRecord pinInfoList pinNet cadr(assoc(‘net pinRecord)) if(pinNet ! “NO NET” then ; 如果网络名已存在计数加1否则初始化为1 currentCount netCountTable[pinNet] netCountTable[pinNet] currentCount 1 ) ) ; 输出按网络统计的结果 fprintf(outFile “\n\n”) fprintf(outFile “Pin Count by Net (Connected Only)\n”) fprintf(outFile “\n”) foreach(netEntry netCountTable fprintf(outFile “Net: %-20s t Count: %d\n” car(netEntry) cdr(netEntry)) )这个“BonusTip”将简单的汇出工具升级为了一个初步的设计分析工具。你拿到报告不仅能看明细还能一眼看到关键统计信息。5. 脚本优化与生产环境使用建议把上面的代码模块组合起来就是一个可用的脚本。但要从“能用”到“好用”还需要考虑一些工程化细节。5.1 错误处理与鲁棒性前面的代码包含了基础校验但在生产环境中可能需要更完善文件路径指定一个固定的输出目录如./component_reports/避免文件散落各处。使用axlMkDir确保目录存在。文件名冲突如果多次汇出同一个元件上面的代码会用时间戳区分。你也可以让用户输入文件名后缀。用户取消在axlSelect()等待时用户按ESC取消要友好提示并退出而不是报错。5.2 输出格式的灵活性文本文件通用但有时需要Excel或HTML格式以便分享。CSV格式只需将报告中的制表符t改为逗号,文件后缀改为.csv就可以用Excel直接打开。HTML格式用fprintf输出table等HTML标签可以生成更美观、支持排序和过滤的网页报告。这对于引脚数成百上千的BGA芯片尤其有用。5.3 封装成Allegro菜单命令每次都在SKILL调试器里加载运行脚本太麻烦。你可以将脚本封装并添加到Allegro的菜单或工具栏上。创建.il文件将完整代码保存为一个.il文件例如export_component.il。定义命令在文件开头使用axlCmdRegister函数注册一个命令如“export_comp”。添加到菜单修改Allegro的allegro.men或通过axlUIMenuInsert函数动态添加一个菜单项其动作指向你注册的命令。这样你或你的同事就可以像使用其他Allegro内置功能一样通过点击菜单来运行这个汇出工具。5.4 性能考虑对于引脚数量极多例如超过2000个的元件遍历所有引脚并获取网络信息可能会稍慢。如果遇到性能问题可以检查是否在循环内执行了重复的、耗时的数据库查询尝试将其移到循环外。考虑是否需要获取所有信息。如果只统计数量可能不需要获取每个引脚的精确坐标。6. 常见问题排查思路当你按照上述步骤编写或运行脚本时可能会遇到一些问题。别急着怀疑脚本逻辑按这个顺序排查脚本加载失败提示语法错误先看错误信息指向哪一行。SKILL对括号匹配非常敏感99%的语法错误是括号()或引号“”不匹配。仔细检查特别是if和foreach语句的嵌套。再看是否使用了未定义的函数或变量。检查函数名拼写确保所有自定义变量都已赋值。运行后提示“选择的对象不是元件”确认你是否严格按照提示点击了元件如芯片、电阻、电容的图形而不是元件的位号丝印Ref Des文本或其它对象。检查脚本开头的axlSetFindFilter设置是否正确。确保“COMPONENTS”在启用列表中。生成的报告文件中所有引脚的网络名都是NO NET这是最常见的问题。说明获取网络的那段代码没有生效。调试在循环内添加一句printf(“Pin %s, Sig: %L\n” pinNumber sig)将sig变量打印到控制台。如果sig始终是nil说明axlSelect(pinDbid)这种方式在当前Allegro版本或环境下不适用。替代方案尝试使用axlGetPinNetName函数如果存在或者通过axlDBGetPin和net-name的属性链来获取。不同版本的Allegro SKILL API可能有细微差别需要查阅对应版本的文档或在线资源。坐标值看起来不对非常大或非常小确认你获取的是相对坐标相对于元件原点还是绝对坐标相对于PCB原点。pinDbid-xy通常是封装内的相对坐标。如果你需要PCB上的实际位置必须使用axlTransformPoint结合元件的放置位置和角度进行转换。脚本在大型设计上运行很慢定位在代码不同阶段添加时间戳打印找出耗时最长的部分。通常是网络获取或文件写入。优化对于网络获取确认没有在循环内进行全数据库扫描。对于文件写入确保文件打开/关闭操作在循环外。最后也是最关键的建议不要试图一次性写出完美脚本。我的习惯是先写一个最简单的版本只实现核心功能比如先只打印位号和封装名。跑通之后再像剥洋葱一样一层层加上引脚遍历、网络获取、文件输出、统计功能。每加一层都立刻测试这样能最快定位问题所在。这个“汇出单颗零件并统计引脚”的脚本就是一个绝佳的练习项目它能串起SKILL中对元件、引脚、网络、文件操作等多个核心概念。