Cadence skill語言簡介
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語言的解釋器來執行各種操作。
其中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.在CIW裏輸入命令startFinder,或者在Terminal上輸入cdsFinder& . Finder適用於至少知道函數名的一部分,這裏可以查到函數的用法簡介。例如上圖我們看到畫path的函數是leHiCreatePath(),但這是圖形方式的函數,對應skill方式的函數呢用法呢,可以在Finder中輸入CreatePath,這樣我們就可以看到包含有CreatePath的所有函數,如圖,leCreatePath即是我們想找的函數,這裏可以看到簡單的用法介紹
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!"
推薦使用第一種方式,需要注意的是函數和第一個括弧之間沒有空格,否則會報錯
如: strcat ( "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每一個元素,而且有相關的簡化函數,如下表:
Using car and cdr with Bounding Boxes |
|||
Functions |
Meaning |
Example |
Expression |
car |
car( ... ) |
lower left corner |
ll = car( bBox) |
cadr |
car( cdr( ... ) ) |
upper right corner |
ur = cadr( bBox) |
caar |
car( car( ... ) ) |
x-coord of lower left corner |
llx = caar( bBox) |
cadar |
car( cdr( car( ... ) ) ) |
y-coord of lower left corner |
lly = cadar( bBox) |
caadr |
car( car( cdr( ... ) ) ) |
x-coord of upper right corner |
urx = caadr( bBox) |
cadadr |
car( cdr( car( cdr( ...] |
y-coord of upper right corner |
ury = cadadr( bBox) |
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). 關係操作符,如下表:
Sample Relational Operators |
||||
Operator |
Arguments |
Function |
Example |
Return Value |
< |
numeric |
lessp |
3 < 5 |
t |
3 < 2 |
nil |
|||
<= |
numeric |
leqp |
3 <= 4 |
t |
> |
numeric |
greaterp |
5 > 3 |
t |
>= |
numeric |
geqp |
4 >=3 |
t |
== |
numeric |
equal |
3.0 == 3 |
t |
string list |
abc == "ABc" |
nil |
||
!= |
numeric |
nequal |
abc != "ABc" |
t |
string list |
2). 邏輯操作符,如下表:
Sample Logical Operators |
||||
Operator |
Arguments |
Function |
Example |
Return Value |
&& |
general |
and |
3 && 5 |
5 |
5 && 3 |
3 |
|||
t && nil |
nil |
|||
nil && t |
nil |
|||
|| |
general |
or |
3 || 5 |
3 |
5 || 3 |
5 |
|||
t || nil |
t |
|||
nil || t |
t |
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" )
4. Skill語言中常用知識匯總列表
上面對skill語言作了一個大概的介紹,當然學習skill需要瞭解的很多,這裏就不再一一作詳細的介紹了,只是對一些需要注意的地方做一下總結,具體的還是要學習User Guide
1)Skill中的特殊字元(除了字母數位以及 _ 以外的其他字元)都有各自的含義,見下表,如果要用到這些字元的話,用\ 可以去掉其特殊含義。
留言列表