☰
SKILL语言入门指南:从脚本原理到芯片设计自动化实践
2026/10/28 3:10:15 网站建设 项目流程

简介:面向集成电路设计自动化领域的 Cadence SKILL 语言中文使用指南,基于产品版本 6.1.6(2014 年 11 月)翻译整理,适合英语阅读较吃力但具备一定 C 语言基础的技术人员、版图与验证工程师入门查阅。内容从 SKILL 与 Lisp 的渊源讲起,先交代语法约定、数据类型标识符写法与节名含义,再依次说明安装步骤、环境变量配置与编译器选择,并延伸到编程指南中的实用技巧;文末还给出官方文档、社区论坛与技术支持的获取途径,便于读者按主题快速定位。压缩包内为 1 个 PDF 文件,体积约 68.23MB,目录层级清晰,支持关键词检索,也方便打印成册随时翻阅。目前已有 527 人学习下载,可作为中文环境下系统了解 SKILL 语言、编写定制化设计工具与排查环境问题的常备参考。

1. 先弄明白一件事:SKILL 语言到底是给谁用的脚本

很多人第一次听到 SKILL 语言,是在招聘要求或者部门内部培训通知里,看到「熟悉 SKILL 语言者优先」几个字,然后一头雾水:这又是什么编程语言,名字都没听过,零基础还学得会吗?说白了,它是一种跑在集成电路设计工具里的脚本语言,专门用来指挥那些画版图、做验证、跑仿真的大型软件干活。你不用拿它写网站、写 App,你要做的是把重复几十遍的鼠标点击,换成一句能反复执行的命令。这份中文使用指南把官方英文手册翻译成了中文,让英语一般的新手也能从头看懂语法、跑通第一个例子,这也是它最实在的价值。

2. 为什么值得学:SKILL 在芯片设计流程里到底管什么

刚接触这个领域的人,最容易犯的错是把它当成一门「要单独学的编程语言」,于是搬来一本讲变量和循环的通用教材从头啃,啃了两周发现和自己的工作完全对不上,兴趣就没了。更省力的做法是先搞清楚它在整个流程里站哪个位置,知道它替谁干活、解决哪类麻烦,再回头看语法,你会发现每一行代码都能对上具体场景。

2.1 它不写业务系统,它给设计工具装上「遥控器」

芯片设计工程师日常面对的,是版图编辑器、电路仿真器、规则检查工具这一类大型软件。这些软件出厂时功能是通用的,可每家公司的流程都不一样:有人习惯把某类器件按固定间距摆成一排,有人要在导出数据前统一改一遍命名,有人每天要检查几十个单元里有没有漏连的线。软件厂商不可能替每家客户把这些活都做进去,于是留了一套脚本接口,SKILL 语言就是操作这套接口的通用语言。

用生活里的东西打比方会更好懂。你买回家的微波炉,面板上只有几个固定按钮,可你真正想要的是「中火三分钟,再解冻两分钟」,那就得有办法把这些按钮自己组合起来。SKILL 就是这个组合按钮的东西,而且它比「录制宏」强得多:它有变量、有条件判断、有循环、能定义函数,可以写成真正的程序。

再换一个更贴近的例子:Excel 里的 VBA。SKILL 之于设计工具,就相当于 VBA 之于 Excel、AutoLISP 之于某些绘图软件。它们的套路一模一样——宿主软件提供对象,脚本语言负责批量读写这些对象。你只要理解过一次这种「宿主 + 脚本」的关系,以后再遇到别的工具,上手会快很多。

所以第一层认知要立住:它是工具的一部分,不是独立的应用开发语言。学它的目的不是造一个新软件,而是让手上这套软件按你的习惯干活。这个定位想明白了,后面的语法就不会学得那么飘。

2.2 和 Lisp 的血缘关系:为什么满屏都是括号

打开任何一份 SKILL 代码,第一眼看到的都是括号,一层套一层,新手的本能反应是「这玩意儿能读吗」。它是 Lisp 家族的方言,而 Lisp 这种语言最核心的想法叫「代码即数据」:所有东西都是列表,列表用括号包起来,括号里第一个位置写动作,后面写材料。

; 括号里第一个词是函数名,后面的都是参数 (+ 1 2) ; 结果是 3 (list 1 2 3) ; 结果是 (1 2 3) (car '(9 8 7)) ; 取第一个,结果是 9

这种写法叫前缀表达式。好处是语法极少:没有运算符优先级要背,没有一堆关键字要记,加两个参数和加十个参数写法完全一样,读代码时一眼就能看出谁在调用谁。坏处也很直接:第一次看像天书,括号多到眼花,少写一个右括号整段就跑不起来。

新手只要记住一条口诀就够用了:括号里第一个词是动作,后面的都是材料。「动作」就是函数,「材料」就是参数。看到(printf "hello\n"),你就读成「执行 printf 这个动作,材料是这串文字」;看到(setq width 10),就读成「执行 setq 这个动作,材料是变量名 width 和数值 10」。用这个读法去扫代码,哪怕语法还不熟,也能猜出七八成意思。

顺带说一句,SKILL 在 Lisp 基础上做了不少贴合设计场景的改造,比如它支持中缀写法,也内置了大量直接操作图形对象的函数。手册前言里专门有一节讲它和 Lisp 的关系,第一遍读不懂没关系,等你在窗口里敲过几十行再回头看,那节会变得非常清楚。

2.3 学会之后能干的四类活

很多人学着学着就放弃,是因为不知道学完能干嘛。按实际工作场景归归类,SKILL 用得最多的是这四类事。

第一类是参数化单元。同一个器件,栅宽改一下图形就得跟着重画,靠手动画既慢又容易错。写成参数化单元之后,只需要改一个数值,图形自动重算,这是用得最广、也最值得先学的一块。

第二类是批量修改。比如选中两百个对象,统一把某一层改成另一层,或者统一给命名加个前缀。手工点两百次一定会出错,脚本一遍过,还能重复用。

第三类是自动化检查。跑一遍自己的规则,把不合规的项收集成一张表打印出来,比人眼一个个找靠谱得多,这种脚本写一次能用一整年。

第四类是数据导出与整理。把设计里的尺寸、坐标、属性导成文本或表格,交给别人做分析。工具自带的导出往往不贴合你要的格式,脚本能按你要的样子排。

2.4 零基础该有的心理预期

手册前言里提到,这份文档面向的是「有一定 C 语言基础」的读者。看到这句别慌,它的意思只是希望你听过变量、函数、返回值这些概念,不是要你会写 C。真的一点编程经验都没有,也能学,只是前面两三章要多花点时间。

还有一件事要提前打好预防针:SKILL 是「遥控器」,你得先知道电视在哪。也就是说,你至少要熟悉手上那套设计工具的基本操作——知道单元在哪、图形怎么选、属性在哪看。完全不熟悉工具的人,先花一周把工具用熟,再回来学脚本,效率反而高。

时间上给个参考:每天抽一小时,两三周能看懂别人写的简单脚本,一个月能照着改,两三个月能独立写小工具。这个节奏对零基础的人是现实的,别信「三天精通」那种话。

至于这份中文手册怎么读,我的建议是别从头读到尾。第一遍只看目录加前三章,建立整体印象;之后带着具体问题回去查,比如「怎么判断两个数大小」就翻控制流程那章,「怎么把结果写进文件」就翻文件输入输出那章。手册是工具书,不是小说。

3. 第一步怎么迈:第一行 SKILL 代码怎么敲、怎么看结果

前面讲的都是概念,这一章开始动手。我要先说明一点:下面所有例子都跑在工具自带的交互式命令行窗口里,不同版本的窗口名字可能叫控制台、解释器或者 SKILL 命令行,界面长得也不完全一样,但「你敲一句、它回一句」这个模式是一样的。看到你手上的窗口和截图有差别,不要怀疑自己,这是版本差异。

3.1 打开那个能对话的窗口

在工具菜单里找到命令行入口,点开之后会看到一个提示符,光标在后面闪。这个窗口的本质是一个「读入—求值—打印」的循环,行业里简称 REPL:你输入一段代码,它立刻算出结果,再把结果打印出来,然后等你输入下一段。它最大的好处是即时反馈,写错立刻报错,不用编译、不用保存、不用重启。

新手最该做的第一件事,不是去读语法章节,而是在这个窗口里乱敲十分钟。敲错了顶多出一行报错,不会把工具弄坏,也不会影响你打开的设计数据。把这个心理负担卸掉,后面才敢试。我第一次接触这类窗口的时候,光是反复敲加减法就玩了一晚上,那种「我说什么它就做什么」的感觉,比看十页文档建立信心快得多。

需要提醒的是:在窗口里敲的代码默认只存在于当前会话,关掉窗口就没了。所以真正有用的代码,后面要存成文件。这一章先玩窗口,下一章再学存文件。

3.2 第一个例子:让工具回你一句话

把下面这行敲进去,然后回车。

; println 是输出函数,双引号里是任意一段文字 (println "Hello, SKILL")

敲完回车,窗口下面应该出现一行Hello, SKILL,紧接着可能还会冒出一个返回值。逐项拆开看:最外层的一对括号表示「这里要执行一个动作」;println是动作的名字,意思是打印一行;双引号里的内容是要打印的材料,字符串必须用双引号包住,中文、英文、符号都行。

如果你敲完没反应,或者弹出一行红字,先别急着重敲,看三件事:左右括号是不是成对、双引号是不是英文半角、println 有没有拼错。这三件事能解决新手九成以上的报错。

3.3 第二个例子:算个数、存进变量

只会打印一句话没什么用,接着让工具算点东西。

; setq 是赋值函数:第一个参数是变量名,第二个是它的值 (setq width 10) (setq height 5) ; * 是乘法函数,可以接两个以上的参数 (setq area (* width height)) ; 把结果打印出来 (println area)

一行一行读:第一行把 10 存进名叫width的变量,第二行把 5 存进height。第三行先算括号里的(* width height),得到 50,再把这个 50 存进area。第四行打印area,窗口回你一个 50。

这里的setq值得多说两句。它是赋值函数,第一个参数写变量名(注意不加引号,这一点和后面讲列表时会形成对比),第二个参数写值。SKILL 里变量不需要提前声明类型,你把一个数存进去它就是数,把一段文字存进去它就是字符串,这一点比 C 语言宽松,对新手很友好。

再补一个更实用的写法。如果想把结果拼进一句话里打印,用printf:

; %d 是整数占位符,\n 表示换行 (printf "area = %d\n" area)

printf的第一个参数是格式串,里面的%d会被后面的area替换掉,\n是换行符。这种写法在实际脚本里出现频率极高,因为日志要让人看懂,光打印一个数字没法定位是哪一步出的问题。

3.4 报错了先看这三处

第一次动手必然会遇到报错,这很正常,不用觉得自己不适合学。SKILL 的报错信息通常以*Error*开头,后面跟着一段英文说明,比如「函数未定义」「参数个数不对」。看不懂那段英文也没关系,按顺序排查这三处,大部分问题当场就能解决。

第一处是括号。SKILL 里括号是唯一的语法结构,少一个右括号,工具会一直以为你还没写完,光标停在那里等;多一个右括号,直接报语法错误。排查办法是从最内层往外数,一层一层配对。

第二处是引号。字符串必须用英文半角双引号包住,中文全角引号看起来几乎一样,但工具不认。这种事在抄别人代码时特别容易发生,翻车过一次之后你就会记住。

第三处是函数名和参数个数。函数名拼错一个字母,工具就找不到它;参数给多了给少了,也会报错。手册里每个函数都有固定的参数说明,遇到不确定的就回去查那一节,别凭感觉猜。

4. 基础动作练四样:数字、字符串、列表、判断

窗口玩熟了,接下来要把基本功打扎实。SKILL 的数据类型看着不少,但对新手来说,真正每天要打交道的就四样:数字、字符串、列表、判断与循环。把这四样练到不用查手册,你就能读懂大部分简单脚本了。这里我会把每一段代码都拆开讲清楚参数和返回值,你照着敲一遍,比看十遍强。

4.1 数字和字符串:最不容易出错的热身

数字分整数和小数,写法跟日常一样。加减乘除对应+、-、*、/,都是前缀式,而且都支持两个以上参数:(+ 1 2 3)直接得 6,不用写成两次加法。

(+ 1 2) ; 3 (* 2 3 4) ; 24,乘法可以接多个参数 (/ 10 3) ; 整数相除,结果可能被截断成 3 (/ 10.0 3) ; 其中一个写成小数,结果就是 3.333...

最后两行是个小坑,值得单独记一下:整数和整数相除,很多版本会直接截断小数部分。你要精确结果,就把其中一个数写成带小数点的形式。这个差别在做尺寸换算的时候会突然冒出来,让人怀疑工具算错了。

字符串用双引号包住,拼接用strcat,取长度用strlen。

; strcat 把多段字符串接成一段 (setq name (strcat "cell_" "001")) (println name) ; 输出 cell_001 ; strlen 返回字符个数 (println (strlen name)) ; 输出 8

strcat的参数个数不固定,想接几段接几段,这一点在拼接命名规则时特别方便。需要注意它只能接字符串,你硬塞一个数字进去会报错,得先用格式化的方式把数字转成文字。

4.2 列表:SKILL 里最核心的一坨数据

列表是这门语言的心脏。为什么这么说?因为你调用工具的函数去查东西,返回的几乎都是列表:查一个单元里所有器件,回来的是一个器件列表;查一个图形的所有顶点,回来的是一个坐标列表。不会处理列表,就等于不会用这门语言。

造一个列表有三种常见写法。第一种用list函数现场拼;第二种用单引号'直接写出来,这叫引用,意思是「原样当成数据,别当代码执行」;第三种用cons往已有列表前面接一个元素。

(list 1 2 3) ; 得到 (1 2 3) '(1 2 3) ; 同样得到 (1 2 3),单引号表示原样对待 (cons 0 '(1 2 3)) ; 得到 (0 1 2 3),把 0 接到最前面

单引号这个符号是新手第一个大坑,后面避坑章会专门讲,这里先记住一句话:不加引号的列表会被当成代码去执行,加了引号才是数据。你写(1 2 3),工具会以为你要调用一个叫 1 的函数,直接报错;写成'(1 2 3)才是你想要的那个列表。

取值用car和cdr,这一对是 Lisp 家族的传统名字,第一次见会觉得很怪,用两次就顺了。car取第一个元素,cdr取除了第一个之外剩下的部分。

(setq nums '(10 20 30)) (car nums) ; 10 (cdr nums) ; (20 30) (length nums) ; 3,元素个数

把car和cdr套起来用,就能取到任意位置的元素,比如(car (cdr nums))得到 20。套得太深不好读,实际写代码时更常用nth:(nth 1 nums)同样得到 20,注意它从 0 开始数。

4.3 判断和循环:让脚本自己跑起来

只会顺序执行的脚本价值有限,真正省时间的是「按条件做不同的事」和「对一堆东西重复做同一件事」。

条件判断最常用的是if,三个参数:条件、条件成立时做什么、不成立时做什么。

(setq w 12) (if (> w 10) (printf "too wide\n") (printf "ok\n") )

>是大于比较,返回成立或不成立。if的返回值就是被选中的那一支的结果,这个特性在赋值时会用到。

当只有「成立才做」而没有「不成立做什么」时,用when更省事;反过来「不成立才做」用unless。这两个函数身上省掉的括号,写多了你会感谢它们。

; 只有条件成立才执行,不成立就跳过 (when (> w 10) (printf "wide: %L\n" w) )

循环里最常用的是foreach,它遍历一个列表,对每个元素执行一次。这个函数你几乎每天都会用到,因为工具返回的东西都是列表。

(setq widths '(1.0 2.0 3.5)) (foreach w widths (when (> w 3) (printf "big one: %L\n" w) ) )

这段的意思是:从widths里逐个取出元素,每次叫它w;如果w大于 3,就打印一行。%L是格式化占位符,能打印任意类型的值,调试的时候用它最省心,不用管当前是数字还是列表。

如果只是想按次数循环,用for:(for i 1 5 (println i)),从 1 数到 5,每次打印。这个写法在「重复执行固定次数」时比foreach直观。

4.4 把它存成文件再加载:从敲一行到有一个自己的库

窗口里敲的代码关掉就没了,所以真正的脚本要存成文件。SKILL 脚本文件一般用.il后缀,用任何纯文本编辑器都能写,注意别用会插入格式的富文本编辑器。

写好的文件用load加载:

; 加载一个脚本文件,路径用双引号包住 (load "/home/user/mytools/area.il")

路径建议一开始就写绝对路径,相对路径在不同工作目录下会找不到文件,这是新手最常见的翻车点之一。

文件里可以只放一堆函数定义,加载之后这些函数就能在窗口里直接调用。定义一个函数用procedure:

; 定义函数 rectArea,接收两个参数 w 和 h (procedure (rectArea w h) (let ((a (* w h))) ; let 声明局部变量 a,只在这个函数里有效 (printf "area = %L\n" a) a ; 函数最后一句的值就是返回值 ) )

拆开看:procedure后面第一对括号里,第一个词是函数名,后面是参数名;函数体里用let声明了一个局部变量a,它的作用域只在这个函数内部,函数执行完就消失,不会污染外面的同名变量;最后一行单独写了个a,它的值就是这个函数的返回值。

存好文件、加载、然后在窗口里敲(rectArea 10 5),应该看到输出area = 50,同时返回值也是 50。这一步跑通,你就算是真正迈过门槛了——从「敲一行算一行」变成「有一个自己的小工具库」。

5. 避坑与常见问题:新手最容易翻车的五个地方

这一章单独拿出来讲,是因为下面这几件事几乎每个新手都会遇到,而且它们每次出现时都显得特别莫名其妙。我把现象、原因、解决按顺序写清楚,你对号入座就行。

5.1 敲完回车没反应,光标一直等

现象:输完一行回车,工具不报错也不返回结果,光标就停在那里等下一行。

原因:括号没配平,通常是少了一个右括号。SKILL 靠括号判断一段代码有没有写完,它认为你还在输入,自然不会执行。

解决:把光标移到这段代码上,从最内层括号开始往外数,看看每一层是不是都有对应的右括号。用带括号配对的编辑器写脚本,能省掉大量这种麻烦。实在找不到,就把这段代码单独粘到窗口逐行回车,哪一行之后还在等,问题就出在哪一行。

5.2 变量明明赋过值,用的时候却是空的

现象:前面刚setq过,后面打印出来却是空值,或者报「未定义」。

原因:多半是加载文件的顺序问题,或者变量名拼写不一致。还有一种情况是用let声明的局部变量,出了函数体就失效了,你在外面用当然取不到。

解决:先确认赋值那一行确实执行过,在它后面立刻加一句打印做验证。变量名统一风格,别一会儿大写一会儿小写混着拼。需要跨函数共用的话,就得用全局变量,别用let。

5.3 列表一写就报错,说函数不存在

现象:写(1 2 3)想表达一个列表,结果工具报错说找不到叫 1 的函数。

原因:没加引号。不加引号的列表会被当成函数调用,括号里第一个位置会被当成函数名,1当然不是函数。

解决:想表达「这就是一份数据」,前面加单引号,写成'(1 2 3)。或者干脆用(list 1 2 3),语义更明确,不容易被自己看错。

5.4 函数改了,跑起来还是老结果

现象:明明改了文件里的函数体,重新执行还是旧的行为。

原因:文件改了但没重新加载,工具内存里跑的还是旧定义。

解决:改完文件必须再load一次。想确认当前到底加载了哪个版本,可以在函数里加一句打印版本号,一跑就知道是不是新的。这个习惯看着笨,但排查问题时能省下大量时间。

5.5 拿翻译文档当唯一标准,术语对不上

现象:手册里写的函数名或者说法,和你实际敲的不一样,或者你按手册的术语去搜索,什么都搜不到。

原因:这份文档是中文译本,术语翻译可能和社区里的常见叫法有出入,个别地方还带着机器翻译的痕迹;另外手册对应的是特定版本,不同版本之间函数行为可能有细微差别。

解决:遇到关键函数,把中文说法和括号里的英文原名一起记住,搜索时用英文原名。和实际行为对不上时,直接在窗口里敲一遍验证,以运行结果为准,不要和文档较劲。

6. 下一步学什么:从会写一行到能做出一个小工具

走到这里,你已经能在窗口里算数、处理列表、写循环、把函数存成文件加载。接下来最忌讳的是回头把手册从第一页读到最后一页,那样很容易读一半就停了。更有效的路子是带着一个具体的小需求往前推。

6.1 按这个顺序往下学

阶段学什么大概花多久检验标准
第一阶段函数参数写法:@rest、@optional、@key三天能写出参数可省略的函数
第二阶段文件读写:把结果写进文本、再从文本读回来一周能导出一份自己的报表
第三阶段命名规范与源码维护:函数前缀、注释、拆分文件一周别人能看懂你的脚本
第四阶段操作图形对象:选中、改属性、批量处理两到三周能写一个批量改名工具

@optional这一组参数写法,是我认为性价比最高的一个知识点。学会之后你写的函数就能带默认值,调用的人少传一个参数也不会报错,给别人用的工具立刻规范起来。

6.2 一个能立刻用上的技巧

调试脚本时,别指望一次性写对。我的习惯是每写三五行就单独执行一次,把中间结果打印出来看看形状对不对:

; 调试时随手打印中间结果,确认数据形状 (setq items '(1 2 3)) (printf "count = %L\n" (length items)) (printf "first = %L\n" (car items))

两行打印,能让你立刻知道拿到的到底是列表还是单个值,是空表还是有内容。很多所谓的「玄学 bug」,其实就是数据类型和你想的不一样。

6.3 给自己定一个小目标

不要以「学完手册」为目标,那玩意没有终点。给自己定一个具体的小工具,比如「把选中图形的名字统一加前缀」,两周做出来,你就彻底入门了。做出来的东西哪怕只有二十行,也比看完十章强。

我第一次写这类脚本的时候,图省事跳过了验证那一步,直接把一个改了属性的函数跑在整份设计数据上,结果把一批不该动的对象也改了,花了半天回滚。从那以后我每次写完改数据的脚本,都强制先在一个小单元上跑一遍,确认输出和预期一致,再放大到整份数据。这个习惯看着慢,其实是唯一能让你不返工的办法。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询