ハードウェア記述言語
VHDL、Verilog、SystemVerilogが合成可能なハードウェアをどう記述するか、Chisel、SpinalHDL、Amaranth、Hardcaml、Clashがどこに位置づけられるか、そしてどう選ぶかを解説します。
概要
ハードウェア記述言語が記述するのは回路であって、プログラムではありません。モジュール、信号、条件分岐があり、テキストはソフトウェアのように見えますが、合成可能サブセットの中のすべての文は、同時に存在するゲート、レジスタ、配線になります。このハブは、FPGA開発のために言語を選ぼうとしているエンジニアと、すでにひとつの言語を知っていてツールが何を受け入れ何を受け入れないかを理解したいプログラマのためのものです。
合成では2つの言語が主流です。VHDLと、Verilog(およびその上位互換であるSystemVerilog)です。どちらもIEEE規格で、すべてのベンダーツールがサポートしています。もうひとつのグループは、ハードウェア構築言語やジェネレータと呼ばれることが多く、Scala、Python、OCaml、Haskellの通常のプログラムとして実行され、ベンダーツールに渡すVerilogやVHDLを出力します。これらは合成ツールの置き換えではありません。置き換えるのはタイピングです。
重要な考え方
レジスタ転送レベルと合成可能サブセット
言語が何であれ、合成可能なコードはレジスタ転送レベル(RTL)で書かれます。つまり、レジスタと、レジスタ間の組み合わせ論理と、どのクロックエッジで各レジスタがロードされるかの記述です。どの言語も、その合成可能サブセットよりはるかに大きなものです。遅延、ファイルI/O、動的メモリ、クラスオブジェクト、そして検証機能の大部分はシミュレーション専用です。合成ツールはそのサブセットを読み、クロック付きプロセスからフリップフロップを推論し、条件分岐からマルチプレクサを推論し、すべてをデバイスのセルにマッピングします。シミュレーションでは正しく動くのにサブセットの外にあるコードは、拒否されるか、さらに悪いことに、黙って異なるハードウェアになります。その境界を知ることが中核となるスキルです。
VHDLとVerilog・SystemVerilogの比較
VHDLは強い型付けを持ち、冗長で明示的です。信号はstd_logic_vector、unsigned、signedといった型を持ち、変換なしに混在させるとエラーになります。この厳格さが、幅や符号の間違いをコンパイル時に捕まえます。VHDL-2008は形式的な記述の多くを緩和し、VHDL-2019はさらに機能を追加しましたが、本稿執筆時点で2019に対するベンダーのサポートはまだ部分的です。VHDLは欧州の産業界、防衛、航空宇宙、そして長い保守期間が重要となるあらゆる分野で一般的です。
Verilogは簡潔で寛容です。幅は暗黙に拡張され、未宣言のワイヤは警告付きで現れ、elseの欠落はラッチを生みます。SystemVerilogはpacked struct、列挙型、always_ffブロックとalways_combブロック、インターフェース、そして大規模な検証層を追加します。合成に関しては、SystemVerilogの型付きサブセットは簡潔さを保ちながら素のVerilogの罠の大半を取り除きます。北米の産業界と、ほとんどのオープンソースコアでのデフォルトです。SystemVerilogに対するベンダーの合成サポートは、AMDとAlteraでは良好、LatticeとMicrochipでは十分、オープンソースのYosysではSlangなどのフロントエンドや商用のVerificプラグインなしでは限定的です。
ジェネレータ: Chisel、SpinalHDL、Amaranth、Hardcaml、Clash
ジェネレータとは、汎用言語のライブラリであって、そのオブジェクトがワイヤやレジスタを表すものです。プログラムを実行すると回路グラフが構築され、Verilogとして書き出されます。Chisel(Scala、バークレー発)は最もよく知られており、Rocket Chipや多くのRISC-Vコアの基盤になっています。SpinalHDL(同じくScala)はFPGAエンジニアによって作られ、クロック領域やバスインターフェースといった点で実用的であり、VexRiscvはこれで書かれています。Amaranth(Python、旧nMigen)はオープンソースツールチェーンのコミュニティで人気があり、独自のシミュレータを同梱しています。Hardcaml(OCaml、Jane Street発)は型安全性とテストを重視します。ClashはHaskellのサブセットを直接ハードウェアにコンパイルし、回路をストリームに対する純粋関数として扱います。
得られるのはパラメータ化と再利用性です。Chiselのジェネレータなら、ひとつのソースから4ポートのクロスバーも64ポートのクロスバーも生成できます。代償は、2つ目のツールチェーン、ベンダーの回路図ビューアで読みにくい生成ネットリスト、そして2層の名前を経由するデバッグです。すでにScalaやPythonで暮らしているチームは、この取引に価値を見出します。認証機関にコードを提出しなければならないチームは、通常そうしません。
選び方
同僚、IP、ツールチェーンがすでに使っている言語を、この順番で選んでください。ひとりで始めるなら、VHDLかSystemVerilogが安全な選択です。すべてのツール、すべての求人、すべてのベンダーサンプルがそれらをサポートしているからです。ジェネレータを採用する前に、どちらかをきちんと学んでください。ジェネレータの出力もやはりRTLであり、何かが失敗したときにはそれを読まなければならないからです。
どこから始めるか
- /learn/beginner/05-your-first-hdl-module/は、VHDLとVerilogの両方で最初のモジュールを書きます。
- /learn/beginner/06-simulation-and-testbenches/は、ボードに触れる前にそれを実行する方法を示します。
- /learn/beginner/07-finite-state-machines/と/learn/beginner/08-counters-timers-and-debouncing/は、最もよく書くことになるパターンを扱います。
- /learn/beginner/10-from-rtl-to-board/は、モジュールを合成からハードウェアまで通します。
合成のためのSystemVerilog、VHDL-2008、最初のAmaranth設計に関する中級レッスンは準備中です。
ツールとベンダー
| 言語 | 規格 | 合成サポート | オープンソースの経路 |
|---|---|---|---|
| VHDL | IEEE 1076-2008、1076-2019 | 全ベンダー(2019は部分的) | GHDLとghdl-yosys-plugin |
| Verilog | IEEE 1364-2005 | 全ベンダー | Yosys、Icarus Verilog、Verilator |
| SystemVerilog | IEEE 1800-2023 | AMDとAlteraは良好、他は部分的 | YosysとSlangフロントエンド、Verilator |
| Chisel | Scalaライブラリ | 出力したVerilog経由 | CIRCT、firtool |
| SpinalHDL | Scalaライブラリ | 出力したVerilogまたはVHDL経由 | Verilator向けの組み込みシミュレータラッパー |
| Amaranth | Pythonライブラリ | 出力したVerilog経由 | Yosys統合、独自シミュレータ |
| Hardcaml | OCamlライブラリ | 出力したVerilog経由 | 独自シミュレータとテストハーネス |
| Clash | Haskellコンパイラ | 出力したVerilogまたはVHDL経由 | GHCベースのツールチェーン |
ベンダー固有の注意点は/vendors/amd/、/vendors/altera/、/vendors/lattice/、/vendors/opensource/にあります。
よくある間違い
- HDLで逐次的なソフトウェアを書き、順番に実行されることを期待する。すべてのプロセスは同時に動きます。
- 組み合わせブロックでの不完全な代入。論理ではなくラッチが推論されます。
- ひとつのVerilog alwaysブロックの中でブロッキング代入とノンブロッキング代入を混在させる。
- VHDLのプロセス内で代入前の信号を使い、その結果生じるデルタサイクルを誤解する。
- シミュレータが合成不可能なコードを指摘してくれると信じる。指摘しません。指摘するのは合成だけです。
- RTLの学習を避けるためにジェネレータを採用し、タイミングが満たせなかったときに出力を読めない。
さらに深く
- IEEE 1076-2019, VHDL Language Reference Manual: 現行のVHDL規格。
- IEEE 1800-2023, SystemVerilog: 現行のSystemVerilog規格。素のVerilogもカバーします。
- Chisel documentation: 言語ガイドとジェネレータの思想。
- SpinalHDL documentation: ジェネレータにおけるクロック領域についての優れた解説を含みます。
- Amaranth documentation: 言語ガイドとシミュレータ。
- Cummings, “Nonblocking Assignments in Verilog Synthesis” (SNUG 2000): ブロッキング対ノンブロッキングの問題に決着をつけた論文。