高位合成
Vitis HLS、Altera HLS、oneAPI、Bambu、DynamaticといったHLSツールがCやC++をどう扱うか、プラグマがハードウェアをどう形作るか、HLSが勝つ場面と負ける場面を解説します。
概要
高位合成(HLS)は、C、C++、SYCLで書かれた関数をレジスタ転送レベルのハードウェアにコンパイルします。ツールは、どの演算をどのクロックサイクルで行うか(スケジューリング)、どの物理ユニットがそれを実行するか(バインディング)、配列をどのメモリにマッピングするかを決めます。それを操るのはプラグマと、コードの形です。このハブは、HLSを使えばソフトウェアの人がFPGAを作れると聞いて、それがどこまで本当なのかを知りたいエンジニアのためのものです。
正直な答えは、HLSは作業をなくすのではなく移動させる、というものです。ステートマシンやパイプラインを手で書くのをやめる代わりに、ループの反復回数、メモリポート、開始間隔について考えるようになります。フィルタ、行列演算、画像パイプライン、パケット処理といったデータフロー中心のカーネルでは、この取引はしばしば良いものです。制御が支配的な論理、ビットレベルのプロトコル、正確なサイクル予算を守らなければならないものについては、手書きのRTLが今でも勝ちます。
重要な考え方
スケジューリング、バインディング、開始間隔
Cのループは逐次的です。ハードウェアでは、HLSツールはそれを展開するか、パイプライン化するか、その両方を行います。ループのパイプライン化とは、前の反復が終わる前に次の反復を開始することで、開始から次の開始までのサイクル数が開始間隔(II)です。IIが1なら1クロックに1反復で、ストリーミングフィルタで望ましい状態です。ある反復が前の反復に依存する場合(ループ搬送依存)、2つの反復がひとつのメモリポートを奪い合う場合、あるいは浮動小数点演算を十分速くパイプライン化できない場合、ツールはII=1に到達できません。スケジュールレポートを読み、なぜIIがずれたのかを理解することが、日々の作業の大半です。
バインディングは、乗算器、加算器、メモリをいくつインスタンス化するかを決めます。ループを8倍に展開すると、本体のコピーが8個でき、メモリポートへの要求も8倍になります。配列を複数のブロックRAMに分割(パーティション)すれば、そのポートを供給できます。unrollとarray partitionというこの2つのプラグマが、HLSユーザーが持つ面積とスループットの制御手段の大半を占めます。
インターフェースとデータフロー
関数の引数はハードウェアのポートになります。ポインタ引数は、DDRから読み出すAXIマスタにも、別のカーネルから供給されるAXI-Streamポートにも、ブロックRAMインターフェースにもなり得ます。インターフェースのプラグマを選ぶことは、システムアーキテクチャを選ぶことです。dataflowプラグマは、順に並んだ複数の関数をFIFOでつないだ並行ブロックに変え、プロデューサとコンシューマが重なって動くようにします。画像パイプラインやネットワーク機能がフルスループットに到達するのはこの方法によります。各中間バッファにはプロデューサとコンシューマがひとつずつ、という規則は厳格で、これに違反するのが最もよくあるdataflowのエラーです。
どのツールか
AMD Vitis HLSが最も広く使われています。任意精度型を含むC++を受け入れ、Vivado IPとしてパッケージされたRTLを出力し、Vitisアクセラレーションカーネルの背後にあるエンジンでもあります。Alteraの経路はIntel HLS Compilerを経て、最近ではFPGA向けSYCLを使うoneAPIに移っており、本稿執筆時点では分社化後にAlteraの名前の下へ移管されつつあります。ミラノ工科大学のBambuはオープンソースのHLSツールで、出力したVerilogを通じてあらゆるベンダーをターゲットにでき、研究やベンダーHLSのないデバイスで有用です。EPFLのDynamaticは、固定スケジュールの代わりにハンドシェイクを使う動的スケジューリング回路を合成するもので、静的HLSが苦手とする不規則なループに役立ちます。MicrochipのSmartHLSはPolarFireをターゲットにします。Siemens CatapultとCadence StratusはASICチームに向けたもので、FPGAプロジェクトで見かけることはまれです。
どこから始めるか
HLSは、RTLを手で書いてデバッグした経験があってこそ意味が通りやすくなります。まずは次から始めてください。
- /learn/beginner/03-combinational-logic-and-luts/と/learn/beginner/04-registers-clocks-and-state/は、HLSのスケジュールが何を構築しているのかを説明します。
- /learn/beginner/09-memories-block-ram-and-fifos/。メモリポートはあらゆるHLS設計を制約するからです。
- /learn/beginner/06-simulation-and-testbenches/は、Cシミュレーションと協調シミュレーションにそのまま引き継がれます。
Vitis HLSでストリーミングFIRフィルタを構築し、手書きRTLと比較する中級レッスンは準備中です。
ツールとベンダー
| ツール | 入力 | ターゲット | ライセンス | 備考 |
|---|---|---|---|---|
| Vitis HLS | C、C++ | AMDデバイス | Vivadoに付属、無償 | 成熟、豊富なプラグマ、良質なレポート |
| Altera HLS CompilerとoneAPI | C++、SYCL | Alteraデバイス | 無償枠あり | oneAPIはカーネルとホストコードの両方をカバーするが、Intelは2025.1コンパイラリリースでoneAPIのFPGAサポートパッケージを非推奨にした |
| SmartHLS | C、C++ | Microchip PolarFire | Liberoに付属、無償 | LegUpベース |
| Bambu (PandA) | C、C++ | 任意(Verilog経由) | オープンソース | 研究レベル、活発に保守 |
| Dynamatic | C、C++ | 任意(VHDL経由) | オープンソース | 動的スケジューリング、ハンドシェイク回路 |
| Catapult、Stratus | C++、SystemC | ASICとFPGA | 商用 | 主にASICチーム |
インストールの注意点は/vendors/amd/と/vendors/altera/を参照してください。
よくある間違い
- HLSをCコンパイラとして扱い、無修正のソフトウェアが性能を出すと期待する。ポインタ、再帰、動的割り当て、システムコールはハードウェアではありません。
- HLSレポートの推定クロックだけを読む。本当の数値は配置配線から得られます。
- 読み出す配列を分割せずにループを展開し、ツールがメモリポート不足に陥る。
- 固定小数点で済むところで浮動小数点を使い、面積とIIで代償を払う。
- インターフェースのプラグマを無視してデフォルトを受け入れ、ブロックがストリームではなく32ビットのメモリマップドポートを持つ理由を不思議がる。
- 協調シミュレーションを省く。Cシミュレーションが証明するのはアルゴリズムであって、ハードウェアではありません。
さらに深く
- AMD UG1399, Vitis HLS User Guide: プラグマ、インターフェース、データフローモデルのリファレンス。
- Kastner, Matai and Neuendorffer, “Parallel Programming for FPGAs”: Vivado HLSの例を軸にした無償の教科書。
- Cong et al., “High-Level Synthesis for FPGAs: From Prototyping to Deployment”: ツールが内部で何をしているかを説明する2011年のサーベイ。
- Bambu documentation: オープンソースのPandAフレームワーク。
- Dynamatic: EPFLの動的スケジューリングHLS。論文とソースあり。