Cadence skill 语言简介

EDA软件 0 1786 张长瑞 收藏

Cadence提供二次开发的SKILL语言,它是一种基于通用人工智能语言—Lisp的交互式高级编程语言(LISP即List Processing-表处理,是最早和最重要的符号处理编程语言之一,它于1958年由美国的J. McCarthy提出,LISP在人工智能AI方面获得广泛应用)。

SKILL语言支持一套类似C语言的语法,大大降低了初学者学习的难度,同时高水平的编程者可以选择使用类似Lisp语言的全部功能。所以SKILL语言既可以用作最简单的工具语言,也可以作为开发任何应用的、强大的编程语言。 SKILL可以与底层系统交互,也提供了访问Cadence各个工具的丰富接口。用户可以通过Skill语言来访问,并且可以开发自己的基于Cadence平台的工具。

1. Skill语言和Lisp语言的关系

Skill函数提供两种表示法,一种是代数表示法,现在大多数语言采取这种方式,即func( arg1 arg2 ...),另一种是前缀表示法,类似于Lisp语言,即(func arg1 arg2 ...)。这里举个例子作为对比:

1.代数表示法

procedure( fibonacci(n)
 if( (n == 1 || n == 2) then
  1
 else fibonacci(n-1) + fibonacci(n-2)
 )
)

2.前缀表示法

(defun fibonacci (n)
 (cond
  ((or (equal n 1) (equal n 2)) 1)
    (t (plus (fibonacci (difference n 1))
  (fibonacci (difference n 2))))
 )
)


这里可以看到类似Lisp语言的表示法后面有很多右括号,而且函数和参数容易混淆,所以一般推荐还是用常用的类C语言代数表示法

Skill程序就像一个list表,类似Lisp语言,程序的操作就像操作数据(list)一样,可以生成,修改,求值等

2. 关于Skill函数

SKILL语言支持一套类似C语言的语法,初学者有了一定的C语言基础,入门是很容易的。Cadence的工具可以通过CIW,Bindkey,Form,Menu等多种方式调用skill函数,送到skill语言的解释器来执行各种操作。

1.jpg

其中CIW(Command Interpreter Window),即启动Icfb的第一个窗口,包含一些常用的menu,一个输入行,以及一个输出区域,这里是常用的debug skill程序的地方,当然cadence也提供了Tools->Skill Development,有兴趣的话可以深入研究一下

2.1 Skill函数的查阅方法

Skill语言有n多函数,加上众多工具的接口函数,可以用成千上万来形容,初学者可能会感到晕头转向,无从下手。其实只要了解基本的变量,控制语句,输入输出以及一些常用工具的基本函数就可以了,大多数函数都可以用到再查阅。开始学习skill时可以仔细看看SKILL Language User Guide其他的可以用到时再查阅,这里列出几个经常会用到的文档:SKILL Language Reference -Skill语言相关的函数,Cadence User Interface SKILL Functions Reference -Cadence应用程序图形界面接口函数,Design Framework II SKILL Functions Reference,SKILL Custom Layout Reference,SKILL Schematic Composer Reference分别是Cadence的Design Framework II,版图,电路的接口函数。

当然还有其他众多工具的接口函数,因此Skill需要方便的函数查阅方法,这里列出3种:

1.最简单的方法,看~/CDS.log文件或者CIW的输出区域,把Options-> LogFilter都选上。这里一般可以查阅在图形界面下运行的函数,如图,我们可以看到画path线的函数以及输出结果等

2.jpg

2.在CIW里输入命令startFinder,或者在Terminal上输入cdsFinder& . Finder适用于至少知道函数名的一部分,这里可以查到函数的用法简介。例如上图我们看到画path的函数是leHiCreatePath(),但这是图形方式的函数,对应skill方式的函数呢用法呢,可以在Finder中输入CreatePath,这样我们就可以看到包含有CreatePath的所有函数,如图,leCreatePath即是我们想找的函数,这里可以看到简单的用法介绍

3.jpg

3.上面我们查到的关于函数用法的介绍很简单,如何知道其详细介绍呢。当然如果你知道函数在那个文档里,直接打开就行了,如果不知道,就需要打开help的search功能,这里可以查到详细的功能用法。

运行cdsdoc&, 点击Search打开Cadence help的搜索功能,工具会自动启动一个http服务,同时打开搜索网页,启动服务后,你也可以在windows的IE里输入http://hostname:9000/search.htm,同样可以打开搜索页面,需要注意的是,在C:\WINNT\system32\drivers\etc\hosts文件中需要加入hostname对应的ip,如:

127.0.0.1 localhost
10.0.10.2 host1

Cadence help的搜索功能默认是用Netscape打开搜索网页,如果没有装Netscape,可能会打不开网页。可以先打开firefox,mozila等浏览器,再启动cadence doc搜索http服务,这样就可以打开搜索网页了

3. Skill语言简介

Skill语言的很多地方和C语言差不多,如变量,函数,控制结构,输入输出等,详细的介绍可以参考User Guide,这里只作简单介绍。

3.1. Skill的变量不需要事先声明,Skill第一次用到是会自动生成变量。变量可以由字符、数字、“_” 和 “?” 组成,注意第一个字符不能是数字和”?”。由于Cadence所开发的Skill中的变量、函数都是第一个字母小写,以_为开头的是Cadence的专用函数,为了避免冲突,建议大家函数和变量命名都以大写字母开头。

3.2. Skill的函数的调用方式有三种,

strcat( "Hello" "," " everyone" "!" ) ;常见的类C格式
( strcat "Hello" "," " everyone" "!" ) ;类Lisp语言的格式
strcat "Hello" "," " everyone" "!" ;上面的括号可以省略

返回的结果都是=> "Hello, everyone!"

推荐使用第一种方式,需要注意的是函数和第一个括号之间没有空格,否则会报错

如: s

trcat ( "Hello" "," " everyone" "!" )
=> *Error* eval: not a function - "Hello"

这是调用skill函数的一个常见问题,其它的问题还有:

a. 软件没响应,比如在CIW中输入段代码,软件没有反映,什么结果也没有,一般是因为( )或者” “不成对造成的,一般可以通过键入 ] 来解决,它表示补充完不对称的括号(可以代替任意多个右括号),如果还没有响应,键入 “] 这时大部分情况下,系统会有响应

b. 数据类型不匹配,如:

strcat( "Mary had a" 5 )
=>*Error* strcat: argument #2 should be either a string
or a symbol (type template = "S") – 5

3.3. Skill List是Skill基于Lisp(List Processing)语言的表现,它是skill数据对象的一个有序集合,skill数据甚至程序本身都可以看作是一个list,这是C语言中所没有的概念。下面是skill list的简单例子

List                     Explanation

(1 2 3)         A list containing the integer constants 1, 2, and 3

(1)               A list containing the single element 1

( )                An empty list (same as the special atom nil)

(1 (2 3) 4)    A list containing another list as its second element

A). 创建list有以下几种基本的方法:

􀂾 Specify all the elements of the list literally with the single quote ( ‘ ) operator.

􀂾 Specify all the elements as evaluated arguments to the list function.

􀂾 Add an element to an existing list with the cons function.

􀂾 Merge two lists with the append function.

1).用 ' 和 list 定义一个list,注意两者的差别

a = 1                                          => 1

b = 2                                         => 2

'( a b 3 )                                     => ( a b 3 )

list( a b 3 )                                 => ( 1 2 3 )

2).用cons命令添加一个元素到一个list的头部

result = '( 2 3 )                         => ( 2 3 )

result = cons( 1 result )            => ( 1 2 3 )

3).用append命令合并两个list

Lista = '( 4 5 6 )                         => ( 4 5 6 )

Listb = '( 1 2 3 )                         => ( 1 2 3 )

Listc = append( Lista Listb)       => ( 4 5 6 1 2 3 )

B). 访问list或者list中某些元素的方法:

car访问list的第一个元素

numbers = '( 1 2 3 )                 => ( 1 2 3 )

car( numbers )                         => 1

cdr访问list除了第一个元素外的其他元素,注意返回仍然是个list

numbers = '( 1 2 3 )                 => ( 1 2 3 )

cdr( numbers )                         => ( 2 3 )

nth用索引访问list的某个元素,注意索引从0开始

numbers = '( 1 2 3 )                 => ( 1 2 3 )

nth( 1 numbers )                      => 2

member检查指定的元素是否在指定的list中,它只检查顶层元素的元素,返回值是从搜到值开始到结尾的list

numbers = '( 1 2 3 )                 => ( 1 2 3 )

member( 4 numbers )              => nil

member( 2 numbers )              => ( 2 3 )

length计算list所包含元素的个数

numbers = '( 1 2 3 )                 => ( 1 2 3 )

length( numbers )                    => 3

C). 关于xy坐标或者bBox边界list的访问

在版图设计中,关于坐标的list是最长见的,它是一组2维的list,常见的表示方法有:

用 : 表示一个坐标的list,其结果和list命令一样,用xCoord和yCoord命令可以访问xy坐标

xValue = 300
yValue = 400
aCoordinate = xValue:yValue => ( 300 400 )
xCoord( aCoordinate ) => 300
yCoord( aCoordinate ) => 400

用list命令和 ' 来表示一个bBox,list命令先计算变量或者表达式,然后赋给list,' 表示的list和字面的一样,不会计算变量或者表达式的值

bBox = list( 300:400 500:450 ) ;含有 : 的bBox

含有变量用list

lowerLeft = 300:400

upperRight = 500:450

bBox = list( lowerLeft upperRight )

' 表示的list严格按字面意思

bBox = '(( 300 400 ) ( 500 450 ))

通过car和cdr的组合可以访问bBox每一个元素,而且有相关的简化函数,如下表:

6.jpg

List的相关操作有很多,这里就不详细介绍了,可以参考User Guide里的Advanced List Operations

3.4. Skill的输入输出

1). 输出显示数据:

print 和println 函数都可以用来显示单个数据,println可以在显示的数据后多加一个回车

for( i 1 3 print( "hello" )) ;Prints hello three times.
"hello""hello""hello"
for( i 1 3 println( "hello" )) ;Prints hello three times.
"hello"
"hello"
"hello"

printf 函数是格式化的输出,下面的例子是一定格式输出图形层的统计

printf( "\n%-15s %-15s %-10d %-10d %-10d %-10d"
layerName purpose rectCount labelCount lineCount miscCount
)

对应参数的意义如下,printf需要注意输出类型的对应

%[-][width][.precision]conversion_code
[-] = left justify
[width] = minimum number of character positions
[.precision] = number of characters to be printed
conversion_code :
d - decimal(integer)
f - floating point
s - string or symbol
c - character
n - numeric
L - list (Ignores width and precision fields.)
P - point list (Ignores width and precision fields.)
B - Bounding box list (Ignores width and precision.)

2). 输出数据到一个文件:outfile定义输出接口文件,print println fprintf输出到接口文件, close关闭打开的接口,见下面的例子

myPort = outfile( "/tmp/myFile1" )
for( i 1 3
println( list( "Number:" i) myPort )
)
close( myPort )

输出到文件/tmp/myFile1.

("Number:" 1)
("Number:" 2)
("Number:" 3)


myPort = outfile( "/tmp/myFile2" )
for( i 1 3
fprintf( myPort "Number: %d\n" i ) ;注意printf函数不能输出到port
)
close( myPort )

输出到文件/tmp/myFile2.

Number: 1
Number: 2
Number: 3

3). 从文件读取数据:intfile定义输入接口文件,gets一次从接口文件读取一行字符串,fscanf根据指定的格式从接口文件读取,close关闭打开的接口

打开~/.cshrc,输出文件的每一行

inPort = infile( "~/.cshrc" )
 when( inPort
  while( gets( nextLine inPort )
   println( nextLine )
  )
 close( inPort )
)

打开~/.cshrc,输出文件中的每一个字符串

inPort = infile( "~/.cshrc" )
  when( inPort
    while( fscanf( inPort "%s" word )
      println( word )
   )
  close( inPort )
)

3.5. Skill的控制结构

1). 关系操作符,如下表:

7.jpg

2). 逻辑操作符,如下表:

8.jpg

SKILL中只有nil 是假(FALSE),其余的任何值都是真(TRUE)。

与/或逻辑操作只有在需要计算第二个表达式时,才计算第二个表表达式,比如&&操作,当第一个表达时为假时,就不会再计算第二个表达式,|| 操作,当第一个表达时为假时,才会再计算第二个表达式。

返回的结果是最后一个计算的表达式,因此与/或逻辑操作可以代替繁琐的if / when等控制语句,例如:C语言中的操作符, a>b ? c=a : c=b; 即c取a b中较大的一个Skill中没有类似的操作符,可以用下面语句来完成此操作:

if( a>b then
 c=a
  else
 c=b
)

也可以用逻辑操作符:

c = (a>b)&&a || (a<b)&&b

当然Skill还提供的有max(a b …)的函数,举这个例子是为了说明&& || 可以代替if then else之类的控制语句

3). 控制语句:if(…then…else….),when,unless,case,cond,循环语句for,forecah等,控制语句和C语言类似,都是先判断某个变量或者表达式是否为真,然后执行下面的操作,需要注意的是:

􀂾 关键词(其实也是skill的函数)和左括号之间不能有空格,

􀂾 if…then…else的then是不能省略的(除了只有一个if,没有else的情况),

􀂾 case的判断可以是数字和字符串,也可以是它们组成的list,但不支持变量和表达式

􀂾 如果有很多判断语句,用cond代替if…then…else组合,代码比较清晰而且执行效率比较高,下面的两种代码是等效的。

􀂾 把最可能出现的情况放在最前面,如果出现的几率都一样,把计算量最大的放在最后面,这样可以有效的提高代码效率。

cond(
 ( condition1 exp11 exp12 ... )
 ( condition2 exp21 exp22 ... )
 ( condition3 exp31 exp32 ... )
 ...
 ( t expN1 expN2 ... )
) ; cond
if condition1 then exp11 exp12 ...
 else if condition2 then exp21 exp22 ...
  else if condition3 then exp31 exp32 ...
   ...
  else expN1expN2 ....

for和foreach是循环控制语句,for和C语言中的基本一样,foreach经常用于对list的每个元素作循环操作,每个循环依次把各个元素的值赋给一个变量,如下面的例子,你会注意到foreach的返回值是循环的list

rectCount = lineCount = polygonCount = 0
shapeTypeList = '( "rect" "polygon" "rect" "line" )
foreach( shapeType shapeTypeList
 case( shapeType
  ( "rect" ++rectCount )
   ( "line" ++lineCount )
   ( "polygon" ++polygonCount )
  ( t ++miscCount )
 ) ;case
) ; foreach
=> ( "rect" "polygon" "rect" "line" )


相关推荐:

网友留言:

您需要 登录账户 后才能发表评论

我要评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。
验证码