EDA関連のVideo

英語の勉強をしないと後がないぞ、と言われました。でも、リスニング目的で興味のないような話を聞いても、すぐに意識が別の方に飛んじゃうんですよねぇ〜。と言うことで、興味が持てるEDA関係のビデオサイトを集めてみました。これで、英語も仕事も一挙両得ですよ〜

とりあえずこんなもんかな。他にもあれば教えて下さい。

Thanks to @, @, @

[EDA][20nm] Q&A: A Look at 20nm Design Challenges and Solutions

(この記事は、Q&A: A Look at 20nm Design Challenges and Solutions超訳です。)

By Richard Goering on September 11, 2011

プロセスノードが20nmになると、電力・性能・集積度に格段の進歩をもたらす一方で、非常に困難な設計の課題が見えている。例えば、タイミングや電力のばらつき、複雑なレイアウトルール、大量のIPを含んだとてつもなく巨大なデザイン、である。また、20nmで起きる新たな課題は、既存のリソグラフィ技術を活用するために、余計なマスク(ダブルパターニング)が必要になることである。

20nmでの設計の課題やEDAツールの性能・デザインを成功させるためのフローについて、CadenceのプロダクトマーケティングディレクターのRahul Deokarにインタビューを行った。さらに詳しい話は、CadenceのWhitepaperにある(White Paper, Summary)。

Q: 20nmに移行のためのメリットは何でしょう? また、あなたが一番関心を持っているのは何ですか?

A: セットメーカや半導体ベンダが20nmを考えるのには、3つの理由があると考えています。一つ目は、微細化することで得られる性能です。二つ目は1チップに集積できるIPの数とトランジスタの量。3つ目は消費電力の問題です。

最近では、スマートフォン、タブレット、コンシュマーデバイスに搭載される、ワイヤレス技術に興味を持っている顧客がいます。このような市場では、異なった視点に立たないといけません。そのようなデバイスは高速に動作し、インターネットにアクセスしたり、と言う機能がありますが、全ては、バッテリーに頼らずに低電力でできなければなりません。また、我々は、20nmと言うプロセスには、GPUコンピューティングのようなニーズもあると考えています。

Q: 全体的に見て、20nmでの設計の課題は何だと考えていますか?

A: 3つの課題があります。一つ目は、複雑なレイアウトルール下において、歩留まりを最大化し、製造効率を高めることです。20nmになると、扱わないといけないルールの数が爆発的に増加します。例えば、メタル層に対してだけで、ルールの数が400個にも登る上、ダブルパターニングによる複雑性も加わってきます。

2番目の課題は、タイミングと電力のばらつきを扱うことに関してです。たとえデザインが動いたとしても、意図した通りの性能や電力にならないかもしれない。20nmプロセスには、たくさんの変動要因がある。メタルのピッチが100nmから80nm, 64nmとなるにつれて、配線間のカップリングが増加した。また、インターコネクトの増加によって、デバイスモデリングで考慮しないといけない寄生の効果も増加した。さらに、セル間の距離が小さくなっているため、セル間のレイアウト依存効果もタイミングと電力のばらつきの要因になっている。

3つ目の課題は、顧客が20nmに移行することにより、より大規模なデザインを扱わないといけないことである。EDAツールは、20nm世代でのデザインの規模と複雑性を扱えないといけない。つまり、指数関数的に増大するIPとSoC全体を扱える能力がEDAツールに求められている。設計者もSoC全体で電力管理をしなければならないし、必要な時間内にサインオフ検証を終えないといけない。

Q: 20nmでダブルパターニング技術が必要になるのは誰でしょうか? また、何層に及ぶでしょうか?

A: 20nm世代に移行したら、現在のリソグラフィ技術では、配線が切れなくなるので、みんな必要になるでしょう。ダブルパターニングなしで露光したら、光の拡散によりレイアウトパターンは失くなってしまうでしょう。ダブルパターニング技術は、既存のリソグラフィ技術を延命するものである。良いニュースとしては、ダブルパターニングは全てのメタル層には不要である、と言うものです。ファウンダリやIDMメーカーが実験したところ、低層のメタル層よりも下のレイヤーのパターンのみダブルパターニングで対応するば良いようです。例えば5層やそれ以上の高層メタル層には不要である。

Q: ダブルパターニングによって、どのような設計課題がもたらされるのでしょうか?

A: いくつかあります。まず、ダブルパターニングはセル設計やライブラリ設計に影響を与えます。IP設計時には、ダブルパターニングがもたらすデザインルールに従う必要があるでしょう。特に、ダブルパターニングは、セル間の配置関係を強く考慮する必要があります。我々は自動的に配置を交互にする*1技術を持っています。それにより、混雑度を低く保つことができるでしょう。そして、混雑度が低ければ、タイミングと電力の要求を満たせやすくなります。

そして、配線工程においても大きなインパクトがあります。配線工程が終わった後に、セルを分離することなどできないため、ダブルパターニングは配線時に考慮される必要があります。我々は、ダブルパターニングの制約をセル設計やIP設計から抽出し、配線工程時に制約として使用します。そして、最終的に物理検証をサインオフに導きます。この制約を考慮した配線工程によって、デザインを早期に収束させることができます。また、質も向上させることができるでしょう。

Q: あなたは複雑性に触れましたが、20nm世代には何個のトランジスタが集積されると考えているでしょうか? また、EDAツールはどのようにサポートするのでしょうか?

A: 20nm世代では、8〜12億のトランジスタが集積されることになるでしょう。とてつもなく巨大なデザインです。集積度は一気に2倍になり、性能が50%改善されます。このような巨大なデザインを扱うために必要なことは、抽象化技術です。我々は、Flex Modelと言われる技術を開発しています。これは、大きなマクロやブロックを抽象化する技術です。これにより、ツールが扱えるぐらいまでネットリストを自動的に縮小し、結果として、デザインをより速く収束させることができます。

Q: 40nmや32nm世代では、すでにバラツキが大きな問題になってます。20nm世代ではより状況は悪くなるのでしょうか?

A: ある面ではより悪くなるでしょう。それは、レイアウト依存効果として現れます。20nmのセル間は、より密接な距離になります。そのため、異なったセル間近接効果やインターコネクトは、タイミングとパワーにより悪い影響を及ぼすでしょう。リソグラフィやストレスによるレイアウト依存効果は、キャラクタライズされる必要があります。そして、コンテキストドリブン配置や最適化が必要となるでしょう。

EDIシステムには配置配線時に、セル同士がどのような相互作用をもたらすか検証したり、一つのレイアウトパターンをタイミングやパワーの面で他の候補と比較したりする機能があります。これにより、タイミングやパワーを最適化する隣接セルの組み合わせを実現することができます。

Q: Azuroから最近獲得したクロック同時最適化技術ccoptは、20nmではどのような役割を果たすのですか?

A: 大きな役割になるだろう。クロック網は40nm, 28nm世代でも十分に複雑になっている。20nm世代ではもっとたくさんのクロック種が必要となるだろう。電力遮断のために、クロックゲーティングが使われるため、たくさんのモードとコーナーが発生してしまう。古典的なクロック設計手法では、設計することができなくなるだろう。新しいアーキテクチャをイチから作り上げる必要が有るだろう。

古典的なクロック設計手法では、クロックは工程の後から設計されていた。20nm世代では、ロジックや物理設計と共にクロックが設計されなければならない。スキューを上手にマネージングすることで、(これはAzuroと共に開発した技術だが)性能や消費電力、面積でいい結果を得ることができる。

Q: 20nm世代では、どのような設計ツール・フローが必要になるでしょうか? また、ポイントツールは機能するでしょうか?

A: ポイントツールや役に立たないだろう。我々Cadenceは2つのゴールを目指している。一つは、20nmでのデザインリスクを下げること、もう一つは、顧客の20nmでの設計期間短縮をサポートすることである。どちらのゴールにしても、デザインの最初から最後までサポートできるフローでなければならない。IPのキャラクタライズ、配置配線、最終のサインオフといったデザインフロー全体にわたって、ダブルパターニングやクロックデザイン、レイアウト依存効果といったものを考慮できるものでなければならない。

Q: EDIは20nm世代に対応する準備ができていますか?

A: できている。我々は、長い間、20nmのパートナーと密接に共同開発してきた。そして、我々は早い段階から20nmの開発に関与してきた。実際、20nm世代での技術的な課題やインターフェースを定義した。そして今や、我々の開発したモデルや抽象化、フローの正しさを確認するために設計した複数のテストチップをテープアウトしようとしている。ただし、20nm世代のデザインを製品化するためには、まだ幾つか課題が残っており、ツールやメソドロジにチューニングが必要だと考えている。そして、我々はその準備がすでにできている。

Richard Goering

*1:ダブルパターニングで交互にパターンを配置する、ということ?

[EDA][SKILL] SKILL for the Skilled: Introduction to Classes -- Part 1

By Jim Newton on August 15, 2011

(この記事は、SKILL for the Skilled: Introduction to Classes -- Part 1超訳です。)

これまでの"SKILL for the Skilled"シリーズでは、SKILL++の特徴を見てきた。例えば、局所定義関数、高階関数、レキシカルスコーピングである。しかし、まだSKILL++のオブジェクトシステムについては、説明していない。これはSKILLアプリをオブジェクト指向風に実装する標準的な方法である。

Object Orientation -- オブジェクト指向 --

オブジェクトシステムとは、プログラマがオブジェクトグループの特性や振る舞いを制御するための手法である。ある種の問題は、この方法を使用することで簡単に解くことができる。

もし、C++, Javaや他の言語に詳しければ、C++/Javaなどのオブジェクト指向と同じように考えてしまうかもしれない。私は、そのような限定的な誤ったコンセプトは捨てて欲しい、と思っている。1970年代に言語にオブジェクト指向を取り入れた最初の言語の一つとして、Lispがある。これは、C++Javaが現れるよりも以前のことである。SKILL++のオブジェクトシステムは、Lispのアプローチを基にしている。今後の記事で、SKILLのオブジェクトの指向の強力さやエレガントさに気づいてもらえるはずだ。

The SKILL++ Object System -- SKILL++でのオブジェクトシステム --

SKILL++は、オブジェクトシステムに動的性とリフレクションを加えようとした。これは、実行中のVMイメージに対して、クラスやメソッドを加えることができたり、それらの内部を調査・デバッグしたり、編集・再定義できたりすることを意味している。SKILL++を知れば知るほど、動的オブジェクト指向言語の強力さに驚くだろう。

SKILL++オブジェクトシステムについて、一言で説明すると、SKILLプログラマが構造や定義・振る舞いを共有するためにオブジェクトのクラスを定義することである。クラスは、インスタンスがどのように構造化されるか、を定義したものである。それに対して、総称関数におけるメソッドは、クラスから生成したインスタンスがどのように振る舞い、相互に影響を及ぼすか、と言うのを定義している。

SKILL++オブジェクトシステムは、上記のようなクラスとメソッドを実現することができる。そして、プログラマはクラスとメソッドが独立に作用するのか、それとも相互に影響を及ぼしあうものにするか、選択することができる。つまり、クラスやインスタンスを理解するために、総称関数やメソッドを理解する必要はない、ということである。次からのシリーズで、数独パズルを解くためにクラスをツールとして使用する方法を説明する。

The Sudoku puzzle -- 数独パズル --

まず、数独パズルとは何であろうか? 数独パズルは、9x9のグリッドに分割されたマス目を3x3で9つにグループ化したものを使う。空いたマス目には、{1, 2, 3, 4, 5, 6, 7, 8, 9}のいずれかを、縦、横、そして3x3のブロック内に一つだけ配置する。この暗黙のルールにより、縦、横、3x3のブロック内には、1-9が一度しか現れない。

Sudoku in SKILL++ -- SKILL++での数独

では、下の例のように数独パズルを解くSKILL関数SkuSolveを実装していこう。この例は、Wikipedia数独のエントリから採ってきたものだ。

SkuSolve、並びにサポート関数を実装できたら、下の例のように、数独パズルを解くことができるだろう。

(SkuSolve '((5 3 ?   ? 7 ?   ? ? ?)
            (6 ? ?   1 9 5   ? ? ?)
            (? 9 8   ? ? ?   ? 6 ?)

            (8 ? ?   ? 6 ?   ? ? 3)
            (4 ? ?   8 ? 3   ? ? 1)
            (7 ? ?   ? 2 ?   ? ? 6)

            (? 6 ?   ? ? ?   2 8 ?)
            (? ? ?   4 1 9   ? ? 5)
            (? ? ?   ? 8 ?   ? 7 9)))

この問題に対して、次のように出力されるプログラムである。

starting with:

5 3 7
6 1 9 5
9 8 6
8 6 3
4 8 3 1
7 2 6
6 2 8
4 1 9 5
8 7 9

found solution:

5 3 4 6 7 8 9 1 2
6 7 2 1 9 5 3 4 8
1 9 8 3 4 2 5 6 7
8 5 9 7 6 1 4 2 3
4 2 6 8 5 3 7 9 1
7 1 3 9 2 4 8 5 6
9 6 1 5 3 7 2 8 4
2 8 7 4 1 9 6 3 5
3 4 5 2 8 6 1 7 9

Preview

次回以降、次のように話を進める予定である。

Jim Newton

SKILL for the Skilled: Sorting With SKILL++

By Jim Newton on May 3, 2011

(この記事は、SKILL for the Skilled: Sorting With SKILL++超訳です)

前回までのSKILL for the Skilledコラムでは、SKILL++の関数内ローカルな関数、高階関数、レキシカルスコープの特徴を見てきた。このコラムでは、さらに実践的な例をお見せした。

Functions are first class -- 第1級関数

SKILL言語では、関数は第1級のオブジェクトである。すなわち、関数は動的に生成され、関数自体を他の関数の引数として渡すことができる。次からの例で、関数を生成する関数をどうやって書くか、また、なぜそれが必要になるか、ということについて示そう。

Review of the SKILL sort function -- SKILLでのsort関数を振り返る

SKILLに組み込まれているsort関数は二つの引数を取る。最初の引数はソートされるべきリストで、2番目の引数は、二つの値をどのように比較するか、と言うことを示した比較関数である。比較関数は、TRUEもしくはFALSEを返す関数である。sort関数で指定する比較関数は、二つの引数を取り、この二つの値でどちらが優先されるべきか、と言うのを判定し、Boolean値を返す関数である。この比較関数には、SKILLのビルトイン関数が使える他、ユーザ定義の関数を使用することもできる。5.1の例は、比較関数にSKILLのビルトイン関数であるalphalesspを使用した例である。この例では、文字列のリストがアルファベット順にソートされる。

Sorting with built-in sort predicates -- 述語関数にビルトイン関数を用いた時のソーティング

;; Example 5.1
(sort (list "this" "is" "a" "list" "of" "words")
      'alphalessp)
  ==> ("a" "is" "list" "of" "this" "words")

前回の記事で見たように、もしSKILL++で書いているならば、alphalesspの関数名をそのまま渡してやればよい。

;; Example 5.2
(inScheme
  (sort (list "this" "is" "a" "list" "of" "words")
        alphalessp))
  ==> ("a" "is" "list" "of" "this" "words")

これから先の記事には、全て(inScheme ...)が付いていると思って欲しい。

Implementing SKILL++ sort predicates -- SKILL++での比較関数の実装

sort関数の述語比較関数は、関数オブジェクト(ファンクタ)かもしれない。実際、SKILLでは、いつかのオブジェクトが関数オブジェクトである。alphalesspのように、関数としてすでに存在しているか、もしくは、自動的にロードされるようなシンボルはcallable(ファンクタ?)である。また、lambdaによって作られる関数オブジェクトもcallable(ファンクタ)である。

グローバル関数は、procedureもしくはdefunを使用して、定義することができる。また、以前の例で見たように、fletやlabelsを使用して、関数をローカルに定義することもできる。また、lambdaを使って無名関数を作ることもできる。

例5.3のコードは、ファイルサイズを比較するfileLenghtLessp関数を定義している。

;; Example 5.3
(defun fileLengthLessp (f1 f2)
  (lessp (fileLength f1)
         (fileLength f2)))

例5.4は、fileLengthpが呼ばれた時と同様のことを行う無名関数である。この関数を動かす場合、変数に値をダイレクトに挿入するか、sort関数の引数として渡してやる場合のように、値をパッシングしてやる必要がある。

;; Example 5.4
(lambda (f1 f2)
  (lessp (fileLength f1)
         (fileLength f2)))

5.5, 5.6, 5.7の例では、ファイル名のリストをファイルサイズに応じてソートする方法である。SKILLには、ファイルサイズを返すビルトイン関数はあるが、ファイルサイズを比較するビルトイン関数はない。しかしながら、例5.3のfileLengthLessp関数をsort関数の引数とすることで可能である。

;; Example 5.5
(sort (getDirFiles ".")
      fileLengthLessp)

例5.6のように、無名関数を使うこともできる。

;; Example 5.6
(sort (getDirFiles ".")
      (lambda (f1 f2)
         (lessp (fileLength f1)
                (fileLength f2))))

また、例5.7のように、flet関数を使用してもできる。

;; Example 5.7
(flet ((lesspFileLength (f1 f2)
         (lessp (fileLength f1)
                (fileLength f2))))
  (sort (getDirFiles ".")
        lesspFileLength))

Reversing the sort order -- 逆順ソート

さらに二つの例を見てみよう。例5.8は、文字列のリストを降順に並べる方法である。

;; Example 5.8
(sort list_of_strings
      (lambda (a b)
         (greaterp (strlen a)
                   (strlen b))))

例5.9はリストのリストを要素数の降順に並べる方法である。

;; Example 5.9
(sort list_of_lists
      (lambda (a b)
         (greaterp (length a)
                   (length b))))

Components of the sort predicate -- ソートの述語関数

上であげた5.6, 5.8, 5.9のコードは同じような構造をしている。比較関数を抜き出して見てみよう。

  • test: 関係性を表す関数。例えば、数値の大小を比較するgreaterp, lesspやアルファべティックに文字を比較するalphalesspなどである。
  • key: 比較したいものから要素値を抜き出す関数。例えば、length, strlen, fileLength, identity.

The identity function

後ほど必要となるidentity関数をここで定義しておく。この関数は、引数をそのまま返す単項の関数である。例5.10で定義しているidentity関数は、加法に対しては0を返す関数、乗算に対しては、1を返す関数と言うように働く。

;; Example 5.10
(defun identity (x)
  x)

Higher order functions -- calculating a sort predicate: 高階関数 -- ソート述語関数を返す

SKILL++を使って、ソート関数に渡す比較関数を返す関数を作ることができる。SKILL++を使えば、関数を返す関数を作ることは容易である。

;; Example 5.11
(defun genCmpFunction (@key (test lessp)
                            (key  identity)) ;; see example 5.10
   (lambda (A B)
      (test (key A)
            (key B))))

例5.11で定義されるgenCmpFunctionは、キーワード引数?test, ?keyを使って呼び出され、ソート関数に適用できる関数を返す関数である。すなわち、sortの述語関数になる比較関数を返す関数である。引数のnameとkeyは標準的すぎて、混乱させてしまうかもしれない。例5.12に使用例を示す。デフォルトでは、keyにはidentity関数が、testにはlessp関数がセットされている。

Using the higher order function -- 高階関数を使う

この述語関数生成関数を使用することで、sort関数をより汎用的なものにできる。例5.5, 5.6, 5.7を書き換えたのが以下のコードである。

;; Example 5.12

;; reimplementation of example 5.6
;; sort a list of file names by increasing file size
(sort (getDirFiles ".")
      (genCmpFunction ?key fileLength))

;; reimplementation of example 5.8
;; sort a list of strings by decreasing string length
(sort list_of_strings
      (genCmpFunction ?key strlen
                      ?test greaterp))

;; reimplementation of example 5.9
;; sort a list of sub-lists by decreasing list length
(sort list_of_lists
      (genCmpFunction ?key length
                      ?test greaterp))

Reimplementing the sortcar function -- sortcar関数の再実装

もし、SKILLにsortcar*1ビルトイン関数がないとしても、次の例のように簡単に実装することができる。

;; Example 5.13
(defun sortcar (list predicate)
  (sort list
        (genCmpFunction ?test predicate
                        ?key car)))

Sorting objects from the Cadence Database -- Cadenceデータベースのオブジェクトをソートする

genCmpFunctionは、様々なクライテリアに従って、データベースをソートするための述語関数を生成することができる。例5.14では、Virtuoso Layoutのシェープ図形をtop edge*2の座標値順でソートするための関数である。

;; Example 5.14
(sort (geGetEditCellView)->shapes
      (genCmpFunction ?test greaterp
                      ?key  topEdge))

例5.15では、回路図中のインスタンスをアルファベット順に並べるための関数である。この例では、?key引数にdb-instanceの名前を取得するための無名関数を割り当てている。

;; Example 5.15
(sort (geGetEditCellView)->instances
      (genCmpFunction ?test alphalessp
                      ?key (lambda (i) i->name)))

Review

この記事では、以下のコンセプトについて概観した。

  • SKILLビルトインsort関数
  • 文字列をアルファベット順にソートする方法(例5.1, 5.2)
  • ファイルサイズに応じてファイル名をソートする方法(例5.5, 5.6, 5.7)
  • ソート述語関数を返す関数(例5.11)
  • ソート述語生成関数を用いて、sortcarを実装する方法
  • 高階関数を使用して、文字列やデータベースをソートする方法

To Be Continued

次の記事では、Virtuosoでの高階関数の使用例を示したい。例えば、セルの中にあるピン図形を時計回り順に並べたりする方法、である。さらに、genCmpFunctionを拡張して、2番目、3番目のソートクライテリアを与えられるようにする予定である。

Jim Newton

*1:リストのリストを第1要素順に並べ替える

*2:おそらく左端のこと

SystemC Japan 2011に来ています

http://www.systemcjapan.com/SCJ2011/index.html

あまり業務とは関係ないのですが、5〜10年先の種を見つけようと思ってやってきました。

今のところ午前二つの講演を聞いただけですが、

  • ESLが流行るまでにずいぶんかかったよなぁ。
  • そこに到達するまでには、混沌とした世界(ESLでの様々な抽象レベル、HDLでの様々な抽象レベル)があったのだろう
  • 適切な抽象度を選択することが大事。アナログ/ミックスドシグナルでは欠けている視点

というような事を思いました。

特に、3つめの適切な抽象度を選択して、と言うのが非常に重要だと思っています。アナログ回路設計の場合、主には、スケマティックエントリを使用して、回路図を作成しますが、この段階で既にトランジスタレベルと言う抽象度からは逃れられない宿命にあります。

次に高い抽象度と言うと、Verilog-AMSと言うことになるのですが、インタラクティブな環境から、言語ベースの設計になってしまい、非常にハードルの高さを感じてしまいます。

何となくアナログ設計の抽象度を上げる重要なポイントは、言語ベース設計の壁を如何に取っ払うか、と言うような気もします。ひょっとすると、LabViewのような設計環境の方が受け入れられやすいかもしれませんね。

その前に、アナログの場合、トップダウン設計するメリットがほとんどないことの方が重要な問題なのですが。。。

SKILL++に移行しましょう

SKILL++と言うと、よく知らない人は、オブジェクト指向SKILLだ〜、とさらによくわからなくなるような事を言うのだが、単にSchemeをベースにしたSKILLと言うだけのことです。オブジェクト指向とかは、タダの付録なわけですね。

ちなみにSKILLオリジナルは、Common Lisp以前のFrantz Lisp(って言うんでしたっけ?)をベースにした言語です。

さて、このSKILLとSKILL++の最大の違いは、先のオブジェクト指向云々の問題ではなく、スコープが異なっていることです。

  • SKILL: ダイナミックスコープ
  • SKILL++: レキシカルスコープ


それぞれの言葉の意味は、On Lisp辺りを見てもらうことにして、ここでは、実際にどういう差があるか、と言うのを見ていきます。

ダイナミックスコープはローカル変数を大域環境で書き換えることができる

次のSKILLプログラムは、あるフォームを表示させて、ユーザの入力を待つものです。

(defun mySkillFunc ()
 (let (listBox form (mes "hoge"))
  (setq listBox (hiCreateListBoxField ?name (gensym) ?choices nil))
  (setq form (hiCreateAppForm ?name (gensym) ?fields (list listBox) ?buttonLayout 'OKCancel))
  (hiDisplayForm form)
  (println mes)))

ここで、mesと言うローカル変数を作っておきます。"hoge"と言う値で初期化しておきます。

さて、こいつをCIW(Command Interpreter Window)にloadさせて、実行させたときの結果が以下です。

\i (load "skill.il")     ; SKILLプログラムをロード
\t t                     ; ロード完了
\i (mySkillFunc)         ; SKILL関数実行 -> フォームが立ち上がり、ユーザ入力待ちになる。
\i mes                   ; 大域環境から、mesと言う変数にアクセスしてみる。
\t "hoge"                ; えっ、見えるの? ( ´・ω・`)
\p > 
\i mes = "hage"          ; んでは、試しにmesを書き換えてやろう。
\t "hage"                ; お前は"hage"だ〜。
\p >                     ; フォームをクローズ。
\o "hage"                ; 元のSKILLと関数内の(println mes)の副作用。えっ、値が変わってるΣ(゚д゚) 
\t nil

と言う感じで、内部でローカル変数を使っていても、実行時にダイナミックに値を変更することができ、さらに、変更したことにより、プログラムが影響を受けてしまいます。

これは非常に危険です。ユーザの入力を待っているSKILLプログラムがいる状態で、他のSKILLプログラムがたまたま値を書き換えてしまうことで、容易に再現しづらいバグを引き起こしてしまいます。

一方、レキシカルスコープのSKILL++ではどうだ?

同じプログラムを拡張子".ils"で保存すると、CIW君は自動的にSKILL++のプログラムとしてロードしてくれます。

では、CIWの応答を見てみましょう。

\i (load "skill.ils")           ; SKILL++のプログラムとしてロード
\t t
\i (mySkillFunc)                ; フォームを立ち上げる。
\p >
\i mes                          ; さて、mesの値は。。。トップレベルにはそんなシンボルがない!!
\e *Error* toplevel: undefined variable - mes
\p >
\i mes = "hage"                 ; では、トップレベルにmesと言うシンボルを作ってやる!!
\t "hage"
\p >                            ; フォームをクローズ。さて、mesは影響を受けているか?
\o "hoge"                       ; 元の値"hoge"が表示されてる(^ω^)
\t nil
\p >
\i mes                          ; グローバルのmesはあいかわらず"hage"だ。
\t "hage"
\p >

というような感じになり、おそらくはプログラマが意図した通りの結果になります。

SKILLを書く人間

最近、よく感じることですが、SKILLを書いている人間は、このような事を知って書いているのでしょうか? おそらくは知らないでしょう。ひょっとすると、元がLispであることすら知らずにコーディングしている人もいる気がします。

そして、最近のプログラミング言語はレキシカルスコープを採用しているのがほとんどなので、このような現象にぶち当たっときには、慌てふためくことになるのでしょう。

ということで、最近のプログラマはSKILLよりもSKILL++に移行した方がよいでしょう。理由はオブジェクト指向が使えるから、というものや、変数と関数の名前空間が同一である、とかそういうコトではなく、このスコープの一点につきます。

普段、レキシカルスコープの言語に慣れている人間から見ると、ダイナミックスコープの言語の挙動は予想がつかないことが多いです。その予想がつかない挙動に悩まされるぐらいだったら、SKILL++に移行してしまった方がよいでしょうね。

SKILL for the Skilled: Making Programs Clear and Concise

By Jim Newton on November 8, 2010

(この記事は、SKILL for the Skilled: Making Programs Clear and Concise超訳です。SKILLに興味がある方は、ぜひ。)

SKILLは、Cadenceのコアツール(VirtuosoやAllegro)の機能性をアップすることができるプログラミング言語である。また、Cadence内部の製品開発部門だけでなく、サービスを提供する部門にとっても、重要な言語である。SKILLには、設計環境をカスタマイズしたり、使い勝手を良くしたりすることが可能できるように、value, power, 柔軟性, エレガント性を持っている。これは、SKILL言語がCadenceプラットフォームに蜜に結びついているから可能になっていることである。

この記事では、"SKILL for the Skilled"シリーズの紹介記事である。このシリーズでは、ユーザがSKILLに楽しみや興味を持ってもらい、さらに、SKILLの強力さ、エレガントさを利用してもらおうと思っている。

警告: これから読もうとしている記事は、非常に独断的なものである!

SKILL Functions: Short and Clear

SKILLプログラムは、通常関数によって構成される。関数は短く、簡潔で、その中でも意図が表現されなければならない。しばしば、プログラミング言語は、プログラマに対して、言語が問題に合っているかどうかではなく、問題が言語で表現出来る範囲かどうか、を強いることがある。そして、このような問題はC言語風に書かれたSKILLプログラムに何度も見られるものである。この問題については、これ以降の記事でも取り上げたい。

Example Program

関数は簡潔にしておくべきである、と言う事を示すために、同じ関数を異なる思想で実装した例を見てもらおう。読みにくい例(#1)は命令的に書いたものである。このようなスタイルはなくすべきだ。次の例(#2)は、関数型のスタイルで書いたものである。命令型では9行も費やしているのに対して、関数型では明快さを犠牲にすることなく、2行で収まっている。当然のことであるが、関数型のスタイルの方が、デバッグが容易であり、計算効率もよい、また、大規模化にも対応しやすい。

Implementation #1 -- needlessly confusing (不必要に混乱している例)
procedure( abs_less_than_100(x)
  prog( (value)
    value = abs(x)
    if( value < 100
      then return(t)
      else return(nil)
    ) ; if
  ) ; prog
) ; procedure
Implementation #2 -- clear and simple
(procedure (abs_less_than_100 x)
  (abs x) < 100)

What were the programmers thinking? -- プログラマは何を考えているか?

#1のコードの問題点は何だろうか? #1を書いたプログラマの思想はどういう物なのだろうか? おそらく彼はノイマン型のマシン(結果が得られるまで、算術演算とレジスタ間の移動を繰り返す)の思考をしたのであろう。それに対して、#2のプログラマは数学的な思考でコードを書いたはずである。

A more natural way to think -- より自然な思考

私は、レジスタ間の値を移動させると言う不器用な思考をするよりも、数学的な思考の方が人間に取って、より自然であり、より簡単である、と言いたい。問題をそれ以上に複雑にさせてはいけないのである。

Some mistakes to avoid

二つの実装の思考方法から少し離れて、#1のコードの問題点をさらに眺めてみよう。

  • 役に立たない変数valueの宣言。一度しか使われない変数を宣言する必要などない。
  • 役に立たないprog/returnの使用。もし、コードの最後に値を返したいならば、prog/returnを使う必要などない。
  • 役に立たないif/then/elseの使用。TRUE/FALSEを評価する式を書いているのに、わざわざif/then/else構文の中でTRUE/FALSEを生成しているなんて、意味不明。
  • 閉じカッコだけで、コードの半分を占めている。複数行にわたって、カッコを置く必要なんてない。それよりも、インデントを強制するエディタを使え。
  • コメントが冗長なだけでなく、そもそも悪くしている。誰かがこの関数を編集して、コメントをメンテする事を忘れてしまったら、すぐにこのコメントの意味などなくなるであろう。

SKILL is easy, flexible, powerful, and elegant

SKILL言語は、学ぶのが容易な言語であり、書き捨てのスクリプトにも使える言語である*1。また一方で、SKILLの強力さと柔軟性は、熟練プログラマが高品質なソフトウェアを開発していることから、明らかである。SKILLのエレガンス性については、しばしば低い評価を受けることがある。しかし、キレイに書かれたSKILLプログラムは理解するのが簡単で、わずかな行で実装することができ、他の言語で作るよりも短い時間で作ることができ、作ろうとしているプログラムを理解しやすい言語である。

これまで、SKILLに関する洞察力のある記事を見つけることは困難であった。また、今日の問題に対して、どのようにSKILLで立ち向かうか、と言う記事を見つけることも難しかった。私は、このシリーズを通して、SKILLプログラミングの利点と楽しさを提供していこうと思う。

Jim Newton

*1:訳注: ウソつけーw