从零上手SKILL脚本:在Virtuoso中实现版图绘制自动化
1. 为什么需要SKILL脚本自动化刚接触Virtuoso版图设计时我经常需要手动重复绘制相同的图形结构。比如画一个5×5的金属阵列就得重复25次画矩形-调整尺寸-移动位置的操作。这不仅效率低下还容易出错。后来发现Virtuoso内置的SKILL脚本语言可以完美解决这个问题。SKILL是Cadence自家开发的脚本语言专门用于EDA工具自动化。它就像给Virtuoso装了个机器人助手能记住你的操作步骤并自动重复执行。举个例子手动画一个20×20微米的矩形需要选择M1层按R键激活矩形工具点击确定起点(0,0)拖动到终点(20,20)而用SKILL脚本只需要一行代码dbCreateRect(deGetCellView() list(M1 drawing) list((0 0) (20 20)))2. 从手动操作到脚本的转换技巧2.1 抓取操作日志Virtuoso有个隐藏功能可以记录所有GUI操作对应的SKILL命令。具体操作菜单栏选择Options → Log Filter勾选\a(All)和\p(Prompt)选项正常进行版图操作所有命令都会显示在CIW(Command Interpreter Window)窗口比如用矩形工具画图时日志会显示leHiCreateRect() mouseAddPoint(0:0) mouseAddPoint(20:20)2.2 交互式与程序式函数转换日志中的leHiCreateRect是交互式函数不能直接用在脚本里。需要查《sklayoutref.pdf》手册找到对应的程序式函数。关键对照表交互式函数程序式函数leHiCreateRect()dbCreateRect()mouseAddPoint()直接使用坐标值转换后的脚本版本procedure(MyRect() dbCreateRect( deGetCellView() ; 获取当前单元视图 list(M1 drawing) ; 指定图层 list((0 0) (20 20)) ; 坐标对 ) )3. 核心函数深度解析3.1 dbCreateRect函数详解这个函数有3个关键参数dbCreateRect( d_cellView ; 单元视图对象 l_layerPurpose ; 图层用途列表 l_bBox ; 边界框坐标 )实际使用时要注意d_cellView建议用deGetCellView()动态获取避免硬编码l_layerPurpose格式为list(层名 用途)比如list(M1 drawing)l_bBox需要两个点的坐标格式为list((x1 y1) (x2 y2))3.2 坐标系统的坑新手常犯的错误是坐标格式不对。正确的写法; 正确写法使用符号防止求值 list((0 0) (10 10)) ; 错误写法直接写括号会被当作函数调用 list((0 0) (10 10)) ; 会报错4. 实现矩形阵列自动化4.1 基础循环结构SKILL支持多种循环画阵列最常用for循环for(i 1 5 println(i) ; 打印1到5 )4.2 完整阵列实现假设要画5×5阵列间距30微米procedure(CreateArray() let((x0 y0 step) x0 0 ; 起始X坐标 y0 0 ; 起始Y坐标 step 30 ; 间距 ; 双重循环 for(i 1 5 for(j 1 5 dbCreateRect( deGetCellView() list(M1 drawing) list( list(x0(i-1)*step y0(j-1)*step) list(x0(i-1)*step20 y0(j-1)*step20) ) ) ) ) ) )4.3 进阶技巧参数化设计把固定值改为变量方便复用procedure(CreateParamArray( l_layer ; 图层名 l_purpose ; 用途 x0 ; 起始X y0 ; 起始Y width ; 矩形宽 height ; 矩形高 x_step ; X间距 y_step ; Y间距 x_num ; X方向数量 y_num ; Y方向数量 ) for(i 1 x_num for(j 1 y_num dbCreateRect( deGetCellView() list(l_layer l_purpose) list( list(x0(i-1)*x_step y0(j-1)*y_step) list(x0(i-1)*x_stepwidth y0(j-1)*y_stepheight) ) ) ) ) )5. 调试与优化技巧5.1 常见错误排查函数未定义检查是否拼写错误比如dbCreatRect少了个e参数类型错误确保坐标是list类型图层是字符串作用域问题使用let绑定局部变量5.2 性能优化当处理大量图形时使用dbOpenCellViewByType提前获取cellview对象批量操作完成后调用geRedraw一次性刷新视图复杂图形考虑使用dbCreatePolygon替代多个矩形procedure(OptimizedArray() let((cv) cv deGetCellView() ; 只获取一次 for(i 1 100 ; 省略绘图代码... ) geRedraw() ; 最后统一刷新 ) )6. 实际工程应用案例6.1 匹配晶体管阵列在模拟电路设计中经常需要制作匹配的晶体管阵列。假设需要制作共中心匹配的4×4 NMOS阵列procedure(CreateMosArray() let((cv fingerWidth fingerLength totalWidth spacing) cv deGetCellView() fingerWidth 2e-6 ; 单位微米 fingerLength 1e-6 totalWidth 10e-6 spacing 3e-6 ; 画多晶硅栅极 for(i 1 4 dbCreateRect( cv list(POLY drawing) list( list(spacing(i-1)*(totalWidthspacing) 0) list(spacing(i-1)*(totalWidthspacing)fingerLength 4*(fingerWidthspacing)) ) ) ) ; 画有源区 for(i 1 4 for(j 1 4 dbCreateRect( cv list(DIFF drawing) list( list(0 (j-1)*(fingerWidthspacing)) list(4*(totalWidthspacing)fingerLength (j-1)*(fingerWidthspacing)fingerWidth) ) ) ) ) ) )6.2 自动打孔阵列在金属连线时经常需要制作规则的via阵列procedure(CreateViaArray( x_start y_start x_count y_count x_pitch y_pitch via_layer ) let((cv viaWidth viaHeight) cv deGetCellView() viaWidth 0.2e-6 viaHeight 0.2e-6 for(i 1 x_count for(j 1 y_count dbCreateRect( cv list(via_layer drawing) list( list( x_start(i-1)*x_pitch-viaWidth/2 y_start(j-1)*y_pitch-viaHeight/2 ) list( x_start(i-1)*x_pitchviaWidth/2 y_start(j-1)*y_pitchviaHeight/2 ) ) ) ) ) ) )7. 从脚本到自定义菜单当脚本成熟后可以将其集成到Virtuoso菜单中创建菜单定义文件customMenu.ilprocedure(MyCustomMenu() hiCreateMenu( MyMenu ; 菜单名 My Tools ; 菜单标题 ( (Create Array CreateArray()) (Create Via Array CreateViaArray(0 0 5 5 1e-6 1e-6 \VIA1\)) ) ) )在.cdsinit文件中添加加载命令load(customMenu.il) MyCustomMenu()重启Virtuoso后就能看到自定义菜单