はじめに
FPGA 設計者には多種多様なスキルが求められます。もちろん、それらを 1 ページで説明し尽くせるものではありません。ただ、この仕事に特に当てはまる一般的な指針がいくつかあります。それらを FPGA 設計における五つの黄金律としてまとめてみました。
ルール #1: 自分のやっていることを理解する
これは最初のルールであり、最も実践が難しいルールです。コードの各行、制約、コンフィギュレーションコマンドがそれぞれ何を意味し、どのような影響を及ぼすかを理解することです。論理設計の根底にある理論を理解し、設計ツールが私たちに与えられた入力にどう応答するかを理解することでもあります。
それは、試行錯誤で進める作業の対極にあります。ハイテク開発ツールのベンダー各社は、デバッガやシミュレータ、そして「かんたんにできます」と宣伝する大量のツールを提供することによって、暗に試行錯誤を推奨しているのです。
ソフトウェア開発では、何かをざっと書き、デバッガでテスト実行し、結果を見て直し、また繰り返す、という進め方は珍しくありません。ときには、インターネットのサンプルで見つけたコード片をコピー&ペーストすることもあるでしょう。この反復的な作業スタイルは、ウェブサイトやスマートフォンアプリの開発のような単純なソフトウェアであれば、それなりに有効です。小さなバグはそれほど深刻ではなく、出現したときに直せばよい、というのが一般的な態度だからです。
しかし、ソフトウェアが高度になればなるほど、この方法はすぐに行き詰まります。FPGA 設計になると、反復的な開発手法は、あっという間に、そして手痛い仕返しをしてきます。FPGA 設計ツールは、重大なミスを防いだり警告したりといった点では、まったく役に立ちません。あなたが完全にしくじることをツールは大歓迎しており、一切邪魔をしません。
ルール #2: 動作することを保証する
つまり、「動いている」では不十分なのです。
FPGA は電子回路そのものであり、コンピュータではありません。それでも、一定の設計原則に従って設計されていれば、FPGA はきちんと再現性があり、信頼できます(ルール #1 参照)。そうでなければ、理由の有無にかかわらず、意地悪な動作をしてくることも十分あり得ます。
目に見えるバグがないからといって、問題がないことの証明にはなりません。これはどの分野でも同じです。たとえば、配管工が作業を終え、パイプから水が漏れていなかったとしても、その仕事が正しかったとは限りません。水圧が上がったり、誰かが誤って触れたりして、後から漏れ始めるかもしれません。
それでも私たちは皆、手早いテストか、もう少し念入りなテストを行い、すべてがうまくいっているように見えたら完了とみなす、という罠に陥ります。それは、水道管の水漏れや、簡素なウェブサイト、重要度の高くないソフトウェアなら、まだ許されるでしょう。しかし FPGA では、それではまったく不十分です。
FPGA 向けの設計を行うということは、その設計が動くことを保証することです。設計ツールがまさにそのために用意している手法を使って、失敗しないビットストリーム(bitstream)をツールに生成させることです。
それは「こうなったら、こうする」と考えるのではなく、論理設計が正しいことを数学の証明のように自分自身に証明していくことです。論理回路は、どんなに奇妙なコーナーケースでも動作するはずです。それは、そうしたケースを一つひとつ考慮したからではなく、正しい数式が何をしても正しくあり続けるのと同じ理由によってです。
最終的に動いたからといって、喜ぶ理由にはなりません。それは、正しく設計したことの自然な結果なのです。
ルール #3: 賢くシミュレーションする(あるいは、まったくしない)
FPGA 初心者がよく口にする不満の一つに、「シミュレーションは完璧に動く。だから設計は正しいはずだ。問題はほかにあるに違いない」というものがあります。もちろん、これはまったくのナンセンスです。
まず何よりも、次の点をはっきりさせておきましょう。Verilog のコーディングスタイルが厳密なルールに従っていない限り、シミュレーションとハードウェアはまったく異なる動作をすることがあります(もちろん VHDL でも同じです)。ルール #1 を参照してください。
しかし、シミュレーションは、正しく行ったとしても、対象とする時間とシナリオが限られています。中規模の設計であっても、たとえば 100 ms の間に FPGA 内部で何が起こるかをシミュレーションするには、気の遠くなるような時間がかかります。さらに、実際にハードウェア上で設計を動かすと、設計者が想像もしなかったためシミュレーションしていないシナリオに回路がさらされることも少なくありません。ですから、シミュレーションを完璧に通過した設計でも、FPGA がシミュレーションの対象時間よりはるかに長く動作し続けたとか、想定外のことが起きたといった理由で、ハードウェア上では完全な大失敗に終わることがあります。
さらに悪いことに、ハードウェア上ではすべてが並列に動くため、バグは見つけにくくなります。ソフトウェアのデバッグと違い、追跡できるイベントの並びはほとんどなく、ましてやシングルステップ実行などできません。FPGA 内部の信号をトレースするツールはもちろんありますが、どの信号をトレースすべきか、トレースデータ収集のトリガーにどの条件を使うべきかを判断するのは、必ずしも簡単ではありません。
ですから、シミュレーションはできるだけ使わないことを目標にしましょう。「なんとか動かそう」と、シミュレーションと修正を繰り返しながら設計を直しているようなら、ハードウェアで試したときにはほぼ間違いなくトラブルに見舞われます。
むしろ、FPGA 設計が初回から完璧に動くように書くことを目指してください。それには、最初の 1 行を書く前にしっかり考えることと、自分が何をしているのかを理解することが必要です(ルール #1)。シミュレーションは、設計が正しいことを確認するか、せいぜいばかげたタイプミスを見つける程度の役割で十分です。この目標に達するには学びと改善のプロセスが必要ですが、それだけの価値はあります。最終的には、シミュレーションは直すべきものを見つけられなくなり、時間の無駄になります。
これは単に時間を節約できるだけでなく、ハードウェア上で修正すべきバグが減り、しかも見つけやすくなります。
FPGA 設計の最初の教えが「まずシミュレーションをしてから、ハードウェアで動かす」だということは十分承知しています。ただ、それは最初のレッスンとしては良いというだけのことです。
ルール #4: 運を試さない
言い換えれば、実績のあるコーディングスタイルに従うことです。
論理合成のために使う Verilog は、プログラミング言語ではありません。最も大きな違いは、どんなプログラミング言語でも、構文的に正しいものを書けば、コンパイラ(またはインタープリタ)はその構文が意味する通りの動作をすることが保証されているということです。最悪でも、エラーを報告します。
一方、シンセサイザ(synthesizer)は、限られた種類の論理素子に基づいて回路を生成します。そのため、Verilog で、信頼できない回路になるコードや、FPGA 上に実装できないコードを書くのは、とても簡単です。さらに悪いことに、Verilog のコードを FPGA 上の論理として実装する方法がない場合、シンセサイザはしばしば、異なる動作をする回路を生成します。しかも、シンセサイザはそれを警告なしに行うことがよくあります。言い換えれば、FPGA 上の論理回路が、期待された(つまりシミュレーションされた)動作と異なることを、何の警告もなくやってしまうのです。
さらに困ったことに、シンセサイザのバグはコンパイラのバグよりはるかに多く存在します。凝ったコーディングスタイルは、そうしたバグを簡単に引き出してしまいます。
もちろん、ここまで述べたことはすべて VHDL にも当てはまります。
この種のトラブルを避ける唯一の方法は、他の多くの人も使っているコーディングスタイルを採用することです。心に留めておくべき問いは、「このコード片でシンセサイザが混乱したら、自分以外にどれだけ多くの人が困るだろうか」です。答えが「大勢の人」なら、あなたは安全な側にいます。
実績のあるコーディングスタイルに従うことには、もう一つ利点があります。移植性(portability)です。好むと好まざるとにかかわらず、今日はあるシンセサイザで仕事をしていても、明日にはまったく別の FPGA と別の開発ツールを相手にしていることになるのです。
実績のあるコーディングスタイルがどんなものかを知るには、ツールが内蔵 IP コア(IP core)のために生成する Verilog コードを見るとよいでしょう。コードの書き手によって多少の違いはありますが、ほかよりも頻繁に現れるコーディングパターンがあります。それを真似すればいいのです。
言うまでもなく、RTL パラダイムに従って設計してください。それは単に実績のあるコーディングスタイルであるだけでなく、FPGA ツールが期待している書き方でもあります。
Verilog の教科書やチュートリアルは誤解を招くことがあります。なぜなら、それらは通常、網羅的であろうとするからです。そのため、構文的には正しいものの実際にはほとんど使われず、ときには合成に不適切な可能性を数多く取り上げることがあります。
ルール #5: タイミングこそがすべて
論理設計はソフトウェアプログラミングではありません。Verilog の wire やレジスタに正しい値が入るだけでは足りず、その値が正しい場所に正しいタイミングで現れることも、同じくらい重要です。また、クロックが正しく扱われていることも重要です。
主な論点は、おおよそ次のとおりです。
- データがパイプライン(pipeline)の各ステージをどのように、そしていつ通過するのかを考え抜いてください。特に、パイプラインが(全体として、または部分的に)ストールし得る場合が重要です。実際、これはあらゆるデータフローにも当てはまります。
- タイミング制約(timing constraints)が正しいことを確認してください。特に、外付け部品のデータシートを読み、計算を行いましょう。このページでは、タイミングの検証について説明しています。
- クロックにも注意を払ってください。クロックは、使い始めた最初の瞬間から安定していますか? ジッタ(jitter)は、その用途に対して十分に小さいですか?
- クロックドメイン間の受け渡し(clock domain crossing):再同期化ロジックは必要ですか? もし必要なら、それは信号があるドメインから別のドメインへ確実に伝わることを保証していますか? 詳しくはこちらをご覧ください。
要するに、コンピュータプログラムと違って、論理設計で重要なのは何が起こるかだけではなく、それがいつ起こるかなのです。
まとめ
FPGA 設計が簡単だと言った人は誰もいませんし、この五つのルールも、どれも簡単に守れるものではありません。それぞれに知識と、ある程度の自己規律の両方が必要です。それでも、これらのルールを守る努力には、間違いなく価値があります。そうすることで、特にプロジェクトの最終段階で、すべてがそのまま動くことを期待される時期に、多くのいら立ちを避けられるのです。