西尾さんのFPGAでライフゲームを作りましたに反応しました。
ライフゲームの生死判定を3通りの方法で書いて、合成、比較してみました。生死判定の前後にレジスタが入っているのは動作速度を比較したかったためです。結論を先に書いておくと、どう書いてもたいした違いは無かったです。好きな書き方を選べば良いと思います。
case 文を並べる。
元のソースの記述方法です。
https://github.com/natsutan/lifegame/blob/master/case/case.v
これを合成するとこのような回路になります。
入力をアドレスとしたテーブル引きになっています。
使用ロジックエレメントは12個です。
ROMを使う
Quartus II でROMを作りました。
https://github.com/natsutan/lifegame/blob/master/rom/rom.v
ROMの中身は上のcase文バージョンと同じ内容をmifファイルに書いています。
https://github.com/natsutan/lifegame/blob/master/rom/arom.mif
ソースがすっきりするのがメリットですが、mifファイルというVerilogじゃないファイルが管理対象に入ってしまうのがデメリットです。Xilinxへ移植するときは、そのまま持って行くことができません。ライフゲームのルールをいじったりするように、生死判定をいろいろ変えたい時はmifファイルだけ差し替えれば良いのでそこはメリットになります。
functionで書く
普通にそのまま書けばどうなるかと思い、functionでロジックを書いてみました。ライフゲームのロジックをそのまま書いています。
function is_live; input [8:0] n; integer cnt; begin cnt = n[0] + n[1] + n[2] + n[3] + n[5] + n[6] + n[7] + n[8]; if ( n[4] == 1 ) is_live = (cnt == 2) || (cnt == 3); else is_live = (cnt == 3); end endfunction
全体のソースはこちら
https://github.com/natsutan/lifegame/blob/master/add/add.v
使用ロジックエレメントは、16まで増えています。これを、case文で書いたときと比べて1.5倍になったと思うか、全体のLE数からみれば誤差と思うかは状況次第です。今回の場合であれば誤差の範囲ですね。
まとめ
ライフゲームの処理を3つの方法で書きましたが、使用リソースはたいした違いはありませんでした。気になる動作速度(fmax)は、最後のfunctionバージョンが一番速かったです。
実装 | LE数 | 使用メモリ | fmax | |
---|---|---|---|---|
case文 | 12 | 0 | 326Mhz | |
rom | 0 | 512 bit | 357MHz | |
function | 16 | 0 | 612MHz |
私が仕事で使うならcase文か、ROMで実装します。functionはロジックが複雑になってきたときに速度低下の具合が良く読めないのにたいし、テーブル引きならどれだけロジックが複雑になっても一定の処理時間で終わる事が見えるからです。実行速度が読めないのは単に私のスキル不足なので、そこがクリアーできるなら最初からfunctionで書くのも良いです。