Cadence Skillメモ

個人用備忘録です。

### 公式掲示板

https://community.cadence.com/cadence_technology_forums/f/custom-ic-skill/

簡単な〇〇がやりたい、というのはこちらで調べる。
直接利用できなくても、部分的に参考になるのがとても役立つ。

### 日本語wiki

https://wikiwiki.jp/aiou/

あまり情報量は多くないが取っ掛かりにはよいかも。

### API Finder

CIWメニューのToolsからSKILL API Finderを選択。
用途のわからない関数はとりあえずこれで調べる。
上の公式掲示板でそれらしい関数を見つけて検索するとよさげ。

### データ構造
変数(SKILLでは"symbol"や"variable"と呼ばれる)は
- Print name
- Value
- Function binding
- Property list
という要素を持っている。valueとproperty listを同時に持つ、ということが可能。
valueとfunction bindingを同時に持つことは推奨されない。

### Disembodied Property List
変数のvalueに入れることのできるproperty list。
通常nilで始まり、name/valueペアが続くリストで表される。

### Association Table
RubyのHash、PythonのDictionaryのようにkey/valueペアでデータを保持する。
Property Listのkeyはsymbolしか使えないが、Association Tableのkeyはinteger, float, stringなどが使える。

### setq

変数を代入する関数

```lisp
(setq x 100)
x
;=> 100
```

### setof

Pythonのリスト内包表記に似た機能。戻り値がフィルターされた後のリストになる。
setofのみでは変数はセットされない。
foreachでも同じことができる。

```lisp
x = setof(x '(1 2 3 4) (x > 2))
x
;=> (3 4)

x = foreach(mapcan x '(1 2 3 4) if(x > 2 list(x)))
x
;=> (3 4)
```

### Arrow operator`->`
変数のvalueがsymbolであるときに、symbolのproperty listに間接的にアクセスする。

```lisp
designator = 'U235
U235.x = 200 
U235.y = 300
designator->x ;=> 200
designator->y ;=> 300
```
`U235.x = 200`の`.`はproperty listの要素にアクセスする演算子。
また、変数の値がdisembodied listの場合はその要素にアクセスする。

```lisp
loc = '(nil x 100 y 200) ;=> (nil x 100 y 200)
loc->x ;=> 100

```


### `~>`と`->`の違い

https://community.cadence.com/cadence_technology_forums/f/custom-ic-skill/25523/what-is-the-difference-between-and--

### procedure

関数定義用

```lisp
procedure( myadd(a b)
	a + b
)
myadd(2 3)
;=> 5
```

### split
parseString()が使える

```lisp
s = "aaa/bbb/ccc"

parseString(s "/")
=> ("aaa" "bbb" "ccc")
```

### append

リスト末尾に他のリストを加える

```lisp
l = list()
l = append(l '(1 2))
l = append(l '(4 5))
l
;=> (1 2 4 5)
```

`append()`はnon-destractiveなので`procedure()`内からリストを操作するには使えない。

```lisp
l = '(1 2)

procedure(myappend(list)
	list = append(list '("a" "b"))
)

myappend(l)
print(l)
;=> (1 2) : myappend関数内でappendされたリストは関数外には反映されない
```

### lconc

`lconc()`を使うとdestracticveにリストに要素を追加できる。
一旦`tconc()`でリストのような構造を作ってから、`lconc()`を使って要素を追加、その後`car()`を使って取り出す。

```lisp
x = tconc(nil 1)      ; x is initialized ((1) 1)
lconc(x '(2 3 4))     ; x is now ((1 2 3 4) 4)
lconc(x nil)          ; Nothing is added to x.
lconc(x '(5))         ; x is now ((1 2 3 4 5) 5)
x = car( x )          ; x is now (1 2 3 4 5)
```

### pop
末尾にアクセスするには…
popと違い非破壊的

```lisp
l = '(1 2 3 4)
reverse(cdr(reverse(l)))
=> (1 2 3)
```

### list to string

```lisp
buildString( '("test" "il") ".")      => "test.il"
```

### if
```lisp
if( 条件文 then
    Trueのときの処理1
    Trueのときの処理2
    ...
    else
    Falseのときの処理1
    Falseのときの処理2
    ...
)
```

リストに要素がふくまれているかどうかで条件分岐
`member()`を使う

```lisp
if(member(1 '(1 2 3)) then 
         println("true"))
```

### foreach
foreach内で使った変数は外では参照されない

```lisp
i=100
foreach(i '(1 2 3 4) println(i))
;1
;2
;3
;4
println(i)
;100
```

### zip
pythonのzipに相当する操作はforeachでできる
foreachのマニュアルに書かれているので参照するとよい

```lisp
(foreach (x y) '(1 2 3) '(4 5 6) (println x+y))
5
7
9
=> (1 2 3)
```

### map

リストから`nil`を取り除く。
foreachのそれぞれのループで返る値はlistにする必要があるので注意。

```lisp
l = list("a" "b" nil "c")

foreach(mapcan s l if(s != nil list(s)))
; ("a" "b" "c")
```

### let

ブロック内でのみ有効な関数の宣言

```lisp
let( (x y)
    x = 3
    y = 5
    print(x + y)
)
; 8
x
; *Error* toplevel: undefined variable - x
```

### parseString

文字列を分割してリストを返す。

parseString( "Now is the time" )   => ("Now" "is" "the" "time")
parseString( "~/exp/test.il" "./") => ("~" "exp" "test" "il")
Both . and / are break characters.
parseString( "-abc-def--ghi-" "-" )
=> ("abc"  "def"  "ghi") 
parseString( "-abc-def--ghi-" "-" t )
=> (""  "abc"  "def"  ""  "ghi"  "") 

### cons

リストの先頭に要素を追加

cons( 
g_element 
l_list 
) 
=> l_result

###ファイル出力

https://community.cadence.com/cadence_technology_forums/f/custom-ic-skill/16394/print-result-of-skill-function-to-file/1340354#1340354

例

```lisp
cv = getCurrentWindow()~>cellView
tmpout = outfile("./inputPinList.txt")
foreach(terminal cv~>terminals if(terminal~>direction=="input" then fprintf(tmpout "%s\n" terminal~>name)))
close(tmpout)
```

### ciUtilsMakeUnique

リストの重複する要素を除いて返す

```lisp
ciUtilsMakeUnique('("a" "a" "b" "c" "a" "a" "b" "c"))
=> ("a" "b" "c") 
```


### 各種プロパティの値の取得

インスタンス名　`instance~>name`
セル名　`instance~>cellName`
CDFパラメータ `cdfGetInstCDF(instance)~>c~>value`
cellViewがRead-OnlyかEditableか　`cv~>mode`

### 正規表現オブジェクトの作成とマッチ
`pcreCompile()`で正規表現オブジェクトを作って、`pcreExecute()`でマッチするかどうか比較する。
　　PCRE(=Perl Compatible Regular Expression)

```lisp:example.il
let( (namePat)
  namePat = pcreCompile("^(dff|lat)") ;; name begins with either 'dff' or 'lat'
  foreach(cell ddGetObj("shem")~>cells
    when(pcreExecute(namePat cell~>name)
      ;; do your processing here
    ): when
  ); foreach
); let
```

参考
https://community.cadence.com/cadence_technology_forums/f/custom-ic-skill/36833/regular-expressions

### 正規表現　バックスラッシュについて
`pcreCompile("\\d")`のように特殊文字を使うときはバックスラッシュが2つ必要らしい。

参考
https://community.cadence.com/cadence_technology_forums/f/custom-ic-skill/37602/regular-expression-replace-with-backslash

### 正規表現　キャプチャ

```lisp
comPat = pcreCompile("^([a-z]+)_([a-z]+)")
pcreobj@0x3431b9a0
> 
pcreExecute(comPat "abc_def")
t
> 
pcreSubstitute("\\0")
"abc_def"
> 
pcreSubstitute("\\1")
"abc"
> 
pcreSubstitute("\\2")
"def"
> 
```

### Sort
セル名でソート。アルファベット順。

```lisp
insts = sort(insts (lambda (i1 i2) alphalessp(i1~>cellName i2~>cellName)))
```

### nilガード

```lisp
input = nil
nil
> 
s = (input || "")
""
> 
```

### built-ins
```lisp
dbFindMemInstByName()
dbGetAnyInstSwitchMaster()

dbFindSigByName()
dbFindTermByName()

dbProduceMemName()

;; cellViewオブジェクトからnetを探してオブジェクトを返す
net = dbFindNetByName(cv "net01")

;; cellViewオブジェクトからインスタンスを探してオブジェクトを返す
inst = dbGetInstByName(cv "INST1")  ;; maintained only for backward compatibility; you should now use dbFindAnyInstByName.

```

### Screenshot

```lisp
hiExportImage(?fileName "sample.png" ?window getCurrentWindow() ?bBox inst~>bBox ?scaleFactor 2)
```

### テキストファイル読み込み

```lisp
;; 関数定義
procedure( parseFile( file )
  let( ( table tokens fpFile )
    fpFile = infile( file )
    table = list()
    while( gets( line fpFile )
        tokens = parseString( line )
        tokens && ( table = cons( tokens table ) )
    );while
    close( fpFile )
    reverse( table )
  );let
);procedure

;tmp.txt
;0 aaa AAA
;1 bbb BBB
;2 ccc CCC

;; 各行が空白区切りでリストになって出てくる
parseFile("tmp.txt")
;(("0" "aaa" "AAA") 
;    ("1" "bbb" "BBB") 
;    ("2" "ccc" "CCC")
;)

```