>トップ
SFLメモ
SFLに関する覚書とか
SFLチュートリアル
SFLのチュートリアル(NSLにも対応)を公開中です。
nsl.vim を vim.org に登録しました
http://www.vim.org/scripts/script.php?script_id=3904
こちらのほうが最新版で、変更を加えてあるかもしれません → https://github.com/metanest/nsl_vim
少しでも何か気付かれたことなどありましたら、なんでもお知らせください
NSL について
マニュアルやドキュメント類には記述がないが、Verilog HDLのシステムタスク $write
相当として _write
が使える。
NSL( http://www.overtone.co.jp/products/about_nsl/ )における SFL からの変更点について主なものをまとめる
- ワンホット型構造(複数起動できる)のシーケンサの起動機能の付随による大幅な機能アップ(SFL ではステージとステートを併用する必要があり、さらに、アサートと同時の第 0 クロックの動作と以降の動作の記述が泣き別れるので禁止的に記述が難しかった。またステージのステートではマルチスレッド的な動作はできなかった)
- 理論の用語を使うと、従来はムーア・マシンの記述は素直に書けたが、ミーリ・マシンでは面倒な場合があった
- 名前の変更 (Verilog HDL に合わせる形の変更も多い)
- instr_* が func_* に
- bidirect が inout に
- 他(把握し切っていないです)
- 入出力の記述はモジュール宣言の側のみとし、モジュール定義の側の入出力の記述をオミットするなど、構文的に可能な範囲で重複した記述を不要化
- モジュールへのステートの追加
- 「数」と「定数」の区別が無くなった
- ステージ機能のプロシジャへの名前の変更と機能の整理
- タスク機能の削除
- セグメント機能の削除(かわりにプロシジャやシーケンサからの、プロシジャの起動と戻りの機能がある)
- 「キーワード」から「予約語」への、仕様中の用語の変更
- 構造展開機能の追加
- システムタスク機能の追加
- Verilog 風構文も利用可能になったり、Verilog 風構文に変更されたりしたものがある
- SFL においてバグの元凶となりやすかった仕様の削除(だいたい sfl2vl で削除されていた仕様と同様だが、ビットの逆順切り出しは Verilog に似せたためか復活した)
- ブロック指向のコメントのネストの禁止( C言語などと同様になった)、ライン指向の // コメントの追加
- NSL Core には入力の構文として SFL を受け付けるオプションがある。GUI インタフェースでは "SFL syntax" オプション
- 名前に使えない綴りとして、NSL 自身のキーワードなどの他、 SFL や Verilog HDL や VHDL や SystemC のそれぞれで使えない名前も、同様に使えない
- カウント型 for では十進の数値しか書けない( ← 20130126 版から、幅のある定数(16進とか)も使えるようになっています)
- 実験的な機能などが入っている最新版は http://blog.goo.ne.jp/ip-arch/e/22103c0bc3f58d0959e01e90c9a32ff8 のようにブログにアナウンスが出ることがある。「experimental扱い」であることに注意
その他メモ
- ビットリダクション演算子の対象を直接ビット連結式にすることは構文上できないらしいので |({a, b}) のようにする(この仕様は Verilog の構文と異なる。おそらく SFL の仕様のなごりである。SFL の文法ではビットリダクションの対象は「単項式」であり、ビット連結式は構文的に単項式より上の非終端記号である「式」であったのだが、それは SFL の構文ではビット連結はカッコのない演算子式であったためと思われる)
- 定数からのビット切り出しでも同様。(0x1)[0] のようにする(プリプロセッサで処理させているとこういうコードが必要なことがある)。
- 値を保持するものは reg で、保持しないものは wire という名前だが、これは名前は Verilog 由来である(あろう)。しかし内実としては SFL の reg と、sel と bus の区別をしないもの、である(なお大昔の SFL も、やはり sel と bus の区別がなく、tmp という一種類だったようである)。Verilog の reg と wire は、しばしば FF に合成されるものとされないもの、であるかのように思われているが、正しくは assign 文内の代入の左辺と、 always@ 文などの中の代入の左辺、というように考えたほうが良い( wire でも FF が合成されうる)。一方 NSL の reg と wire は、どちらもそれぞれ必ず、FF が作られるか作られないかは確定している
作ったもの
他人の作ったもの
研究会仕様書の仕様に関するメモ
- 用語「キーワード」の用法があいまい(「予約語」の説明で「キーワードとして」とあるが、キーワードはキーワードで別のもの。「構文図の説明」には、「キーワードの扱いに準ずる」とある)
- インクルードとマクロについて、仕様書では触れられていない
- 「数」の定義は、先頭に冗長な 0 を許しているがそれで良いのか
- モジュール定義、機能回路定義中のモジュール宣言はなんのためにあるのか(古い仕様の名残り?)
- 空白、タブ、改行が区切り文字として指定されているが、改行の CR・CRLF・LF について未詳。また、改頁も区切り文字として認識されたほうが便利であろう
- 3shou_14 には名前空間について簡単なまとめがあるが、研究会仕様書にはない
古い仕様と現行(研究会仕様書)の変更点
- http://www-lab09.kuee.kyoto-u.ac.jp/parthenon/NTT/html/faq.htm#Q28
- submod キーワードがなくなり、いきなり直接モジュール名を書いてサブモジュールを定義するようになった
- キーワードと同じ綴りの名前は使えなくなった (new.sfl に if や mem という名前が使われている例がある)
- コメントは空白扱いになった(cf.『はじめてのPARTHENON』3.15)
- 3shou_14 の定義では _ ではじまる名前を許しているが、研究会仕様書では許されない(Verilog や VHDL への変換で処理系が生成する名前に使うためか?)
- 「定数」で繰り返しの定義が冗長(3shou_14 のほうは問題ない。研究会の仕様書では、8 進数字の中で 2 進数字を参照するが、その際に (term*)* のような冗長な繰り返しをひきおこしている)
- 古い仕様では、モジュール定義中にネストしてモジュール定義を書くことができた模様。PARTHENON の最終バージョンに付属している SFL2Verilog および SFL2VHDL について「SFL 記述の階層を取り払う」とはこのことを指しているので、現行の仕様に従っている SFL では気にしなくてよい。トップレベルだけでなく、定義中にも宣言を書くことができる今の仕様は、この古い仕様の名残りか
記述上の注意点
- (SFL の内部端子の sel と bus は元々はこれの区別を意図したものだったようだが)基本的に、端子が駆動されていない時に Hi-Z となるか don't care で Low と High の任意になるかは、通常の端子では定義されず、制御端子以外ではインアクティブになることが保証されない。NSL でも基本的にそれを引き継いでいる(wire という Verilog と共通のキーワードを使っているが違うものと考えたほうが良い)。NSL で inout の端子については(どちらかというと実装の都合上という気もするが)Hi-Z になる
- 式文は存在しない。最小の文(動作)は(「空文」を別にすると)「単位動作」
- 代入(出力)は文
- 端子への出力とレジスタやメモリへの書き込みは別
- レジスタやメモリへの書き込みとその結果の反映は、Verilog のノンブロッキング代入のようなふるまいになる。端子への出力は、同じクロック内の現象として、前後関係なく通り抜けるような動作
- 数と定数は別物。定数は式中の任意の回路要素と交換可能であり、数は構文中の特定の場所でしか使えない。数と定数は交換不可能
- 定数にはビット幅の概念がある。0b0 は 1 ビット、0o0 は 3 ビット、0x0000 は 16 ビット
- 数は十進で書く。定数は 2/8/16 進で書く
- モジュール定義中等の記述の順序に注意。順序は決まっている
- セグメント定義では構文的に「 1 回以上出現」等が定められている
- ビット切り出しは式で、出力や書き込みの先は式にできないので、ビットを切り出しての出力や書き込みはできない
- C 言語などと違い、コメントのネストが許されている
- 演算子の優先順位は基本的に1レベル。2項<単項、常に右結合(構文上は右結合だが意味上もそうなっているということでいいのだろうか?)
- 基本的に、動作をともなうのは文だが(「なんの動作もしない」空文を除く)、例外的に、[サブモジュール名.]制御端子名([実引き数{,実引き数}]).端子名 の形で、式(要素)中にも、「制御端子の起動」の動作をともなう記述がある
- ステージにおいて、複数個のタスクを同時にアクティブにしようとするようなことをしてはいけないことになっている(あるタスクが終了するクロックにおいて、起動をかけることは問題ない(アクティブになるのは次のクロックだから))。仕様書には、『ステージとタスクと仮引数の定義』の解説に「一旦始動したステージは、その動作を終了するまでは別のタスクを指定して再始動させることは許されない」、『ジョブの生成』の解説に「同一のステージに対し、異なるタスクで同時動作させるような指示を行ってはならない」とある。同一タスクであっても起動してはいけない、というように扱うべきだろう
ex. a & b | c == a & (b | c)
a | b & c == a | (b & c)
定数表記の Tips
たとえば 10 ビットの定数を 16 進と 2 進で交ぜ書きする場合 0x00ob01 のように書く。2 進プレフィックスの b が 16 進表記に呑まれないためにダミーの o を置く(このような記法は sfl2vl や NSL ではできなくなっている)。
any alt の使用例
ガードの条件が排他的なら any
/* セレクタ */
input i<4>;
input s<2>;
output o;
instrin do;
instruct do any {
s == 0b00 : o = i<0>;
s == 0b01 : o = i<1>;
s == 0b10 : o = i<2>;
s == 0b11 : o = i<3>;
}
ガードの条件が独立なら any
/* to be written */
alt のガードの記述順を利用する例
/* プライオリティエンコーダ */
input i<4>;
output o<2>;
instrin do;
instruct do alt {
i<3> : o = 0b11; /* i == 0b1??? */
i<2> : o = 0b10; /* i == 0b01?? */
i<1> : o = 0b01; /* i == 0b001? */
i<0> : o = 0b00; /* i == 0b0001 */
}
else の利用例
/* to be written */
par と any と alt は代用可能
仮に par と any と alt のどれかが無かったとしても、残りを使い、次のようにして記述は可能である(読み書きしにくいが)
par
par {
stmt1
stmt2
stmt3
...
}
これは以下と同等である。たとえば、ネストを深くしたくない時にこの書き換えは利用できる
any {
0b1 : stmt1
0b1 : stmt2
0b1 : stmt3
...
}
any
any {
cond1 : stmt1
cond2 : stmt2
cond3 : stmt3
...
}
これは以下と同等である
par {
alt {
cond1 : stmt1
}
alt {
cond2 : stmt2
}
alt {
cond3 : stmt3
}
...
}
alt
alt {
cond1 : stmt1
cond2 : stmt2
cond3 : stmt3
...
}
これは以下と同等である
any {
cond1 : stmt1
^cond1 & cond2 : stmt2
^cond1 & ^cond2 & cond3 : stmt3
...
}
文法が LALR(2)
alu32 という名前のモジュールがあるとする
declare alu32 {
...
}
module foo {
alu32 alu32; ← 左の alu32 は、この時点では構成要素の定義(サブモジュール)
右の alu32 は、名前空間がモジュール名とサブモジュール名で
分かれているので(?)合法。
alu32 ?????? ← この alu32 は、構成要素の定義(サブモジュール)の開始か、
共通動作の定義の一部か ?????? を読まないとわからない。
?????? が名前なら構成要素の定義(サブモジュール)、
. なら共通動作の定義の一部(サブモジュールの参照)。
LALR(1) パーサジェネレータでは shift/reduce conflict になる。
デフォルト(shift)では、 サブモジュールの定義とみなされ、共通動作のつもりだと次の記号で名前の出現を期待しているため構文エラーとなる。回避のためには共通動作を par { alu32.〜; } のようにくくってやればよい。
(なお、NSL Core ではこのような名前のかぶらせかたをするとウォーニングが出る)
その他
- SFLパーサー配布で配布されているパーサの中に入っている SFL で、test_scr/normal/operator.sfl の 106 行目 b8=b16<15:2><15:8> は SFL 仕様に則っていない。ビット切り出しは、「要素」の右側に付くが、ビット切り出しそれ自体は「要素」ではなく「単項式」なので、さらにビット切り出しを適用するには、b8=(b16<15:2>)<15:8> のようにかっこで囲む必要がある
- PARTHENON に付属している、ベンダ名 DEMO 、ライブラリ名 demo のライブラリは「DEMO 社 demo ライブラリ」と呼ばれている(デザインコンテストなどで)
実装に関するメモ
- 順序回路(たとえば RS フリップフロップ)を直接記述してしまうと
- PARTHENON の合成系ではスタックオーバーフローエラーになって合成できない
- SECONDS では、循環によりエラーというメッセージが出る
- ( sfl2vl では assign 文にそのまま書き換えられる: 次の NSL の場合も参考に)
- NSL でもループは想定していない。NSL Core に -verbose オプションを付ければチェックが行われる(付けないとそのまま通してしまうが)
sfl2vl
- 昔の SFL の term, tmp による内部端子、submod_class による宣言をサポートしていない
- (submod_class による宣言は、あるバージョン以降(詳細不明)の PARTHENON の合成系でもエラーになる)
- 逆順になるビット切り出しはサポートしていない
- 0b1x0 のような基数の混在する定数はサポートしていないので (0b1 || 0x0) のようにする
- Verilog や VHDL のキーワードや予約語が、予約語扱いになっている
- (sfl2vl が従っている言語仕様 (厳密な記述ではない) は、sflvl サポートページの「SFL言語チュートリアル」というリンクの先の PDF「SFLによるLSI設計入門」の附録 A にある)
Links
その他メモ
Quote
http://www.am.ics.keio.ac.jp/pocobook/verilog.htm から引用「本当のことを言うと、個人的には、もっとも優れたハードウェア記述言語はSFLだと思っている。これは、本書の最初の版で設計用言語として使ったものであり、NTTにより設計された純国産製で、美しいシンタックスを持っている。残念ながらもう現場では使われていないが、VerilogやVHDLのおっさんたちだけを見て、ハードウェア言語ってこんなもんか、と思われるのは、本当は困るのである。一面、ハードウェア設計者は、僕も含めて言語なんて問題ではなく、本当に問題なのはそれで書く設計対象である、と思っているので、これが結果として、変なおっさんたちをはびこらせる結果となるのかもしれない。」
(注: 言語マニアとしてコメントすると、キモはシンタックス(構文)よりセマンティクス(意味)じゃないかという気もする)