最近在整理PCB设计文件时经常需要将某个特定元器件比如一个复杂的BGA或连接器的封装、走线、过孔等信息单独导出用于给结构工程师核对或进行专项仿真。如果每次都手动框选、复制、新建文件不仅效率低下还容易遗漏关联的走线和过孔。同时在选型或做封装检查时快速统计一个封装上的引脚总数也是高频需求。本文将围绕Cadence Allegro的SKILL语言手把手教你实现两个非常实用的功能一是将PCB设计中的单颗零件及其所有相关元素走线、过孔、铜皮、丝印完整导出为一个独立的.brd文件二是快速统计指定封装或当前设计中零件的引脚数量。无论你是正在学习SKILL的PCB工程师还是希望提升设计效率的资深开发者这套脚本都能直接集成到你的工作流中。1. 背景与核心概念为什么需要SKILL脚本在高速PCB设计领域Cadence Allegro是行业标准工具之一。然而其原生功能虽然强大但在处理一些特定、重复性的任务时界面操作可能不够灵活或高效。例如设计复用与协作需要将某个关键芯片如CPU、DDR颗粒的局部布局布线提供给SI/PI工程师进行仿真或者与结构工程师确认器件轮廓和禁布区。封装检查与验证在导入新封装或比较不同封装时需要快速确认引脚数量、名称排序是否与Datasheet一致。设计数据提取为生成生产文件、装配图或物料清单BOM提供更细粒度的数据。SKILL是Cadence平台内置的基于Lisp的编程语言它允许用户直接与Allegro数据库交互自动化执行复杂操作。通过编写SKILL脚本我们可以将上述手动、易错的过程转化为一键式的可靠操作极大提升设计效率和准确性。本文目标即使你没有深厚的编程背景也能跟随步骤创建并运行这两个脚本掌握其原理并能根据自身需求进行修改。2. 环境准备与版本说明在开始编写和运行SKILL脚本之前需要确保你的环境已就绪。2.1 软件环境PCB设计工具Cadence Allegro PCB Designer。本文示例基于Allegro 17.4版本编写其SKILL API在17.2、16.6等常见版本中基本兼容但部分函数可能存在细微差异。建议使用17.2及以上版本以获得最佳兼容性。文本编辑器用于编写SKILL脚本.il文件。推荐使用支持语法高亮的编辑器如Notepad、Visual Studio Code、或Allegro自带的cdsSkill编辑器在Allegro命令行输入cdsSkill打开。2.2 SKILL脚本基础认知文件格式SKILL脚本文件通常以.il为扩展名。加载方式在Allegro的Command窗口或称为Console中使用命令load “脚本文件的完整路径.il”来加载并执行脚本。也可以将脚本放入Allegro的搜索路径通过自定义菜单或快捷键触发。调试可以使用printf函数输出调试信息到Command窗口。2.3 示例项目结构假设我们有一个名为demo_project.brd的PCB文件里面有一个位号U1的BGA封装。我们将在此文件上演示脚本功能。 脚本文件我们将创建两个export_single_part.il- 导出单颗零件count_pins.il- 统计引脚数量3. 核心语法与原理拆解在编写具体脚本前需要理解几个关键的SKILL函数和概念。3.1 数据库对象与选择Allegro中的所有元素零件、走线、过孔、形状都是数据库对象。SKILL通过函数来获取和操作它们。axlDBGetDesign(): 获取当前设计数据库对象。axlSelectByName(): 通过名称如位号U1选择对象。axlSetFindFilter(): 设置选择过滤器例如只选择comp零件或cline走线。3.2 遍历与几何搜索要找到一个零件周围的所有走线和过孔我们需要找到该零件的轮廓bBox。以这个轮廓为基础向外扩展一定距离offset创建一个搜索区域。在这个区域内遍历所有走线cline和过孔via对象判断它们是否与零件关联例如走线的一端连接到该零件的引脚上。axlPolyFromDB(): 从数据库对象生成多边形数据。axlGeoExpandPoly(): 将多边形向外扩展。axlDBGetShapes(): 在指定区域内获取形状可用于获取铜皮。axlClearSelSet()/axlAddSelSet(): 用于管理选择集。3.3 新建与保存设计文件导出功能的核心是创建一个新的设计文件并将选中的对象复制进去。axlDMOpenDesign(): 以指定名称和路径创建一个新的设计文件。axlCopyObject(): 将对象从一个设计复制到另一个设计需要处理跨设计上下文。axlDMSave(): 保存当前设计。更实用的方法是在原设计中选中所有需要导出的对象然后使用File - Export - Placement或File - Export - Sub-drawing的功能底层命令。但通过SKILL我们可以更精确地控制选中哪些对象。3.4 引脚统计原理零件的引脚信息存储在其封装symbol定义中。我们需要通过零件找到其对应的封装名。通过封装名从设计库或当前设计中加载封装定义。遍历封装定义中的pin对象进行计数。axlDBGetPadStacks(): 对于已放置的零件也可以尝试通过其焊盘栈来间接统计但对于复杂的埋盲孔可能不准。更准确的方法是读取封装定义。dbOpenCellViewByType(): 通过库路径和单元名打开封装/符号视图。4. 完整实战案例编写与运行SKILL脚本下面我们分步实现这两个功能。4.1 功能一导出单颗零件及其关联对象步骤1创建脚本文件在你的工作目录下新建一个文本文件命名为export_single_part.il。步骤2编写脚本核心代码将以下代码复制到文件中。代码包含了详细注释解释了每一步的作用。; export_single_part.il ; 功能导出指定位号的单颗零件及其关联的走线、过孔、铜皮、丝印到新文件 ; 作者CSDN技术博主 ; 使用方法在Allegro命令行输入 load export_single_part.il然后执行函数 exportPart(U1) ; 定义主函数参数refDes为零件位号如U1, C10 procedure( exportPart(refDes) printf(开始导出零件 %s 及其关联对象...\n, refDes) ; 1. 检查当前是否有打开的设计 when(axlDMDesign() nil axlMsgPut(错误请先打开一个PCB设计文件) return(nil) ) ; 2. 通过位号选择零件 axlSetFindFilter(?enabled (NOALL COMPONENTS) ?onButtons (COMPONENTS)) axlClearSelSet() if(axlSelectByName(COMPONENT refDes) then printf(成功找到零件 %s\n, refDes) ; 获取选中的零件对象 selSet axlGetSelSet() targetComp car(selSet) ; 取选择集中的第一个也是唯一一个零件 else axlMsgPut(strcat(错误未找到位号为 refDes 的零件。)) return(nil) ) ; 3. 获取零件的轮廓边界框(Bounding Box) compBBox axlPolyFromDB(targetComp ?layer ALL ?endCapType ROUND) ; 将轮廓向外扩展一定距离例如20个设计单位可根据布线密度调整以包含附近的走线过孔 searchPoly axlGeoExpandPoly(compBBox 20.0) printf(已创建搜索区域。\n) ; 4. 设置过滤器准备选择关联对象 axlSetFindFilter(?enabled (NOALL CLINES VIAS SHAPES TEXT) ?onButtons (CLINES VIAS SHAPES TEXT)) axlClearSelSet() ; 5. 选择零件本身已在选择集中 axlAddSelSet(targetComp) ; 6. 在扩展区域内选择走线(Cline)和过孔(Via) ; 注意这里是一种简化方法会选择区域内的所有走线过孔。更精确的方法是判断网络是否与零件引脚相连。 clinesInArea axlDBGetShapes(searchPoly ?layer * ?objectType cline) viasInArea axlDBGetShapes(searchPoly ?layer * ?objectType via) foreach(cline clinesInArea axlAddSelSet(cline)) foreach(via viasInArea axlAddSelSet(via)) printf(已添加 %L 条走线和 %L 个过孔到选择集。\n length(clinesInArea) length(viasInArea)) ; 7. 选择与零件在同一层的静态铜皮可选根据需要开启 ; shapesInArea axlDBGetShapes(searchPoly ?layer ETCH/TOP ?objectType shape) ; 例如顶层 ; foreach(shape shapesInArea axlAddSelSet(shape)) ; 8. 选择零件的丝印Ref Des和Value axlSetFindFilter(?enabled (NOALL TEXT) ?onButtons (TEXT)) ; 可以选择零件周边的所有文本但更精确的是通过父子关系找到属于该零件的文本 ; 这里使用一个简单方法选择轮廓框内的文本 textsInArea axlDBGetShapes(searchPoly ?layer * ?objectType text) foreach(text textsInArea ; 简单判断文本是否在零件轮廓内或非常近 if(axlGeoPointInPoly(axlGetXY(text) compBBox) then axlAddSelSet(text) ) ) ; 9. 使用Allegro的导出子绘图(Sub-drawing)功能将选择集保存 ; 这是最可靠的方法可以保持对象属性 selCount length(axlGetSelSet()) printf(选择集内共有 %L 个对象。\n, selCount) if(selCount 0 then ; 生成导出文件名 outFileName strcat(refDes _export.clp) ; 执行导出命令 axlShell(strcat(subdrawing save outFileName)) axlMsgPut(strcat(成功导出到文件: outFileName)) printf(导出完成文件名为 %s。你可以通过 File - Import - Sub-drawing 将其导入到一个新的空白BRD文件中。\n, outFileName) else axlMsgPut(警告选择集为空未导出任何内容。) ) ; 10. 清理选择集 axlClearSelSet() printf(操作结束。\n) ) ; 提供一个带对话框的版本方便交互使用 procedure( exportPartWithUI() refDes axlUIPrompt(请输入要导出的零件位号例如 U1:) if(refDes ! then exportPart(refDes) ) )步骤3加载并运行脚本打开你的PCB设计文件demo_project.brd。在Allegro下方的Command窗口命令行中输入以下命令加载脚本请将路径替换为你的实际路径load D:/your_script_path/export_single_part.il如果加载成功命令行会显示t。执行带UI界面的函数exportPartWithUI()此时会弹出一个对话框输入你要导出的零件位号例如U1点击OK。脚本运行后会在当前设计文件所在目录生成一个U1_export.clp文件。这个文件包含了所有选中的对象。步骤4导入到新文件新建一个空白的PCB设计文件File - New...。在新文件中执行File - Import - Sub-drawing。选择刚才生成的U1_export.clp文件。指定导入原点通常点击0 0点即可。现在你就得到了一个只包含U1及其相关走线、过孔等元素的新设计文件。4.2 功能二统计零件引脚数量【Bonus Tip】步骤1创建脚本文件新建文本文件命名为count_pins.il。步骤2编写脚本核心代码; count_pins.il ; 功能统计指定封装或当前选中零件的引脚数量 ; 作者CSDN技术博主 ; 使用方法1统计封装 load count_pins.il - countPinsBySymbolName(smic55ll_bga484) ; 使用方法2交互式 load count_pins.il - countPinsUI() ; 方法一通过封装名Symbol Name统计引脚数 procedure( countPinsBySymbolName(symbolName) printf(正在统计封装 %s 的引脚数量...\n, symbolName) pinCount 0 ; 尝试从当前设计已加载的封装中查找 foreach(cv axlGetDesign()-components when(cv-name symbolName ; 找到该封装定义 foreach(pin cv-pins pinCount ) printf(封装 %s 的引脚总数为%d\n, symbolName, pinCount) return(pinCount) ) ) ; 如果当前设计未找到尝试从库路径读取此部分逻辑更复杂需要库路径管理 ; 此处为简化示例假设封装已存在于设计中 if(pinCount 0 then axlMsgPut(strcat(警告在当前设计中未找到封装 symbolName 。)) printf(提示请确保该封装已放置在设计图中或需要更复杂的库路径查找逻辑。\n) ) return(pinCount) ) ; 方法二统计当前选中零件的引脚数更实用 procedure( countPinsOfSelectedComp() axlSetFindFilter(?enabled (NOALL COMPONENTS) ?onButtons (COMPONENTS)) axlClearSelSet() axlSingleSelectPoint() ; 提示用户点击选择一个零件 selSet axlGetSelSet() if(selSet then targetComp car(selSet) compName targetComp-name ; 位号如U1 symbolName targetComp-symbol ; 封装名如BGA484 printf(选中零件%s, 封装%s\n, compName, symbolName) ; 通过封装名调用第一个函数进行统计 pinCount countPinsBySymbolName(symbolName) if(pinCount 0 then axlMsgPut(strcat(零件 compName ( symbolName ) 的引脚数为: sprintf(nil %d pinCount))) ) else axlMsgPut(未选中任何零件。) ) axlClearSelSet() ) ; 提供一个交互式UI入口 procedure( countPinsUI() printf(请选择操作模式\n) printf(1. 统计当前选中零件的引脚数\n) printf(2. 通过输入封装名统计引脚数\n) choice axlUIPrompt(请输入选项 (1 或 2):) when(choice 1 countPinsOfSelectedComp() ) when(choice 2 symName axlUIPrompt(请输入封装名称 (例如 smic55ll_bga484):) if(symName ! then countPinsBySymbolName(symName) ) ) when(choice ! 1 choice ! 2 axlMsgPut(输入无效操作取消。) ) )步骤3加载并运行脚本在Allegro Command窗口加载脚本load D:/your_script_path/count_pins.il执行交互式函数countPinsUI()根据提示选择模式1然后在PCB设计图上点击你想统计的零件。脚本会立即在命令行和弹出窗口中显示该零件的封装名和引脚总数。5. 常见问题与排查思路在编写和运行SKILL脚本时你可能会遇到以下问题问题现象常见原因解决思路加载脚本时提示E- *Error* load: error while loading file ...1. 脚本文件路径错误或包含中文/特殊字符。2. 脚本语法错误如括号不匹配、函数名拼写错误。3. 文件编码不是纯文本ANSI或UTF-8无BOM。1. 检查路径尽量使用英文路径和文件名。2. 使用文本编辑器的括号匹配功能检查。从最简单的printf(“hello”)脚本开始测试。3. 用Notepad等工具将文件编码转为UTF-8 without BOM或ANSI。运行exportPart函数后导出的.clp文件为空或缺少走线。1. 零件位号输入错误脚本未找到目标。2. 搜索区域扩展距离代码中的20.0太小未覆盖到关联走线。3. 选择过滤器设置不正确漏掉了某些对象类型。1. 使用axlDBGetDesign()-components查看所有位号确认。2. 根据设计密度增大扩展距离例如改为50.0或100.0。3. 检查axlSetFindFilter中的?objectType参数确保包含了cline和via。countPinsBySymbolName函数总是返回0或报未找到封装。1. 封装名输入错误注意大小写。2. 该封装未放置在当前设计文件中脚本无法从当前设计数据库中找到其定义。3. 脚本通过cv-pins遍历的方式可能不适用于某些特殊封装如机械孔。1. 在Allegro中使用Tools - Padstack - Modify Design Padstack查看准确的封装名。2. 可以先手动放置一个该封装的零件到设计图中再运行脚本。3. 更健壮的方法是使用axlDBGetPadStacks遍历零件的所有焊盘但需要过滤掉非引脚焊盘如散热焊盘。脚本运行导致Allegro无响应或崩溃。1. 脚本陷入死循环如遍历未正确终止。2. 操作了非常大的选择集内存消耗过大。3. SKILL函数使用不当破坏了数据库完整性。1. 在循环体内添加printf调试观察循环次数。2. 对于大型设计导出功能应谨慎使用可以先在小模块上测试。3. 操作前先保存设计。使用axlBeginOperation和axlEndOperation来包装数据库修改操作。导出的Sub-drawing文件导入新图后网络名丢失或属性不对。subdrawing save命令默认可能不包含所有属性。在导出前尝试在Allegro命令行直接执行set telsubdrawing查看相关设置或在脚本中使用axlShell(“subdrawing save -all_properties ...”)尝试包含所有属性。6. 最佳实践与工程建议将SKILL脚本用于生产环境时遵循以下建议可以提升脚本的可靠性、可维护性和易用性。6.1 脚本工程化模块化设计将通用功能如对象选择、文件操作写成独立的函数或库文件方便多个脚本调用。错误处理使用when、catch等语句进行异常捕获给用户明确的错误提示而不是让Allegro报晦涩的错误。日志记录除了在命令行printf可以将关键操作记录到外部文件便于追踪和调试。参数配置化将搜索偏移量、导出路径等变量放在脚本开头的配置区域而不是硬编码在函数内部。6.2 性能优化减少数据库遍历在大型设计上避免使用axlDBGet*遍历所有对象。尽量使用axlSelect*或基于区域的查询。及时清理选择集使用axlClearSelSet()释放内存。批量操作对于需要处理多个零件的任务考虑使用axlDBTransaction来批量提交修改提升效率。6.3 功能增强方向更精确的关联性判断当前的导出脚本是基于几何区域的。可以增强为基于电气网络的关联提取目标零件的所有引脚网络然后选中设计中所有属于这些网络的走线、过孔和铜皮。这需要使用axlDBGetNet等函数。支持多种导出格式除了Sub-drawing(.clp)还可以考虑导出为DXF给结构、PDF用于评审等格式。可以调用axlDXDExport或axlPDFExport命令。集成到Allegro菜单将脚本函数绑定到Allegro的自定义菜单或工具栏按钮上实现一键操作。这需要编辑allegro.menu或form文件。引脚统计增强区分信号引脚、电源引脚、地引脚、机械孔无网络。这需要解析封装的pin属性。6.4 安全与备份只读操作优先在编写修改数据库的脚本如移动、删除对象时先在副本或测试文件上验证。操作前备份在脚本关键操作前提示用户保存或自动备份当前设计。权限管理如果是团队共享的脚本应确保其不会执行未授权的文件读写或系统操作。掌握SKILL脚本的编写是从使用Allegro到驾驭Allegro的关键一步。它不仅能解决像“导出单颗零件”这样的具体痛点更能让你在面对任何重复、繁琐的设计任务时拥有创造自动化工具的能力。从这两个简单的脚本出发尝试修改参数添加新的功能比如导出时包含阻焊层、丝印层你会在实践中快速提升。