Slide 1

Slide 1 text

Copyright© Fixstars Group 実践的!FPGA開発セミナー vol.17 2022/12/22 18:00~

Slide 2

Slide 2 text

Copyright© Fixstars Group Intel HLS を利用した モジュール開発

Slide 3

Slide 3 text

Copyright© Fixstars Group Who I am 写真 Ryuji NISHIDA 西田 竜之 ソリューション第四事業部 シニアエンジニア

Slide 4

Slide 4 text

Copyright© Fixstars Group Who I am 写真 Eisuke MOCHIZUKI 望月 英輔 ソリューション第四事業部 シニアエンジニア

Slide 5

Slide 5 text

Copyright© Fixstars Group 高位合成 High-Level Synthesis 高位合成(HLS) とは ● 高位合成(HLS) = C/C++ でFPGA の実装ができる? ○ ・・・正しいが、正確ではない C/C++ Code Verilog/VHDL Code FPGA Bitstream 合成/配置配線 Synthesis/Implement ● 高位合成(HLS) とはC/C++ からVerilog/VHDL を生成すること ○ HLS だけでFPGA の実装が完了することは稀である ○ Fixstars ではHLS はIP やモジュールの開発に使用し、トップレベルのデザインはVerilog や IP 結線を行うシステム構築ツール で実装することが多い Top Level (Verilog, IP Integrator) Module by HLS Module by Verilog Module by IP Catalog Module by HLS 5

Slide 6

Slide 6 text

Copyright© Fixstars Group HLS の原理的にしんどいところ ● 「C/C++ からVerilog/VHDL を生成する」 ○ C/C++ : ソフトウェアを表現するための、逐次処理を記述する言語 ○ Verilog/VHDL: ハードウェアを表現するための、並列処理を記述する言語 ○ ・・・別のものを表現するために生まれた両者をつなぐのは原理的にしんどい ● しんどいが故に以下のようなことが起こりがち ○ 既存のC/C++ コードをそのまま持ってきても高位合成できない ■ 最近はこういうことを言う人は減ってきたかな ○ 高位合成はできたが、期待した性能に届かない ■ 書き方を工夫したり、pragma を活用しないと性能は出ないことが多いです ○ ソフトウェアエンジニアでも開発できると思ったのにやっぱりできない ■ 高位合成で加速するアクセラレータ開発 (2) ~ 高位合成と C ベース設計 1章 を読むと共感できます ● HLS は魔法のツールではない! 6

Slide 7

Slide 7 text

Copyright© Fixstars Group ではなぜわざわざHLS を使用するのか ● モジュール実装のTAT が大きく向上するから ○ C/C++ で実装するので、ソフトウェアベースでテストが可能 ■ ハードウェアベースのテスト(Co-simulation)と比較して非常に短い時間で完了する ■ 機能面の抜け漏れや論理的なバグはこの段階で潰せる ○ 高位合成時にモジュール本体だけでなくテストもハードウェア化してくれる ■ Verilog/VHDL でテストを書き直す必要がない ■ ハードウェア化時に仕込まれたバグもここで弾くことができる ○ 汎用的なインターフェースのコード実装を省略できる ■ ハンドシェイクを行うインターフェースのRTL 実装は、テストを含め意外と面倒 ● 時間のかかるFPGA 開発で、モジュール実装TAT の向上は非常に助かる ○ HLS で機能的には正しいことを(一応)保証してくれるので、性能向上に集中できる ○ Fixstars ではどうしても性能がでない場合を除き、ほとんどのモジュール開発でHLS を利用 7

Slide 8

Slide 8 text

Copyright© Fixstars Group 代表的なHLS ● Vivado/Vitis HLS: 無償: 2013年~ ○ AMD Xilinx が自社製品向けに提供しているHLS ○ Web 上にたくさん情報があり、Fixstars でもよく使用している ● Intel High-Level Synthesis: 無償: 2017年~ ○ Intel FPGA が自社製品向けに提供しているHLS ○ Vivado/Vitis HLS と比較すると情報は少ないが、Fixstars では最近使用する機会が増えている ● その他 EDA ベンダ提供の HLS:有償 ○ Catapult HLS (Siemense) ○ Stratus HLS (Cadence) ■ etc... ○ ASIC 業界での利用が多く、Fixstars での使用経験はほとんどない(はず) ● 本日はIntel HLS についてお話します。 参考: https://en.wikipedia.org/wiki/High-level_synthesis 8

Slide 9

Slide 9 text

Copyright© Fixstars Group Output :{24, 21, 18, 15, 12, 9, 6, 3} Input A :{ 8, 7, 6, 5, 4, 3, 2, 1} Input B :{16, 14, 12, 10, 8, 6, 4, 2} ● Intel FPGA の開発ツールQuartus Prime に含まれていて無償利用可能 ○ /path/to/intelFPGA_pro//hls/bin/i++ ○ i++ はg++ を模していて、ソースコードとオプションを指定すれば高位合成可能 ■ Vitis HLS のプロジェクトベースで高位合成するスタイルとは異なる ● 下記のようなモジュールを実装するときのコードとコマンドを例示 ○ unsigned int 8 bit x 8 のvector 同士の足し算をするモジュール ■ 入出力はAvalon-ST 64 bit 形式 Intel HLS について vecadd 9

Slide 10

Slide 10 text

Copyright© Fixstars Group Intel HLS 実装例 モジュール本体 モジュールのテストコード 2 つの入力stream からデータ をread しa, b に格納 下記を要素数分繰り返す データ内の各要素に対して 加算を実行し、out に格納 out に格納したデータを出力 stream にwrite モジュールへのテストデータを生成 入力データをコンソールに表示 入力データを入力stream に格納 モジュールを呼び出し 出力データを出力streamからread 出力データをコンソールに表示 10 vecadd.cpp vecadd_test.cpp

Slide 11

Slide 11 text

Copyright© Fixstars Group Intel HLS 実行例 11 $ i++ vecadd.cpp vecadd_test.cpp -march=x86-64 x86 emualtion: ソフトウェアベースでのテスト $ ./a.out a = 0, 1, 2, 3, 4, 5, 6, 7 b = 0, 2, 4, 6, 8, 10, 12, 14 out = 0, 3, 6, 9, 12, 15, 18, 21 数秒でビルド完了 -> テストを実行 1秒未満で実行完了 実行結果に問題がなければCo-simulation へ ➚ 問題があれば修正、このTAT が短いことが利点 $ i++ vecadd.cpp vecadd_test.cpp -march=Agilex -ghdl 1分程度で高位合成完了 -> テストを実行 $ ./a.out a = 0, 1, 2, 3, 4, 5, 6, 7 b = 0, 2, 4, 6, 8, 10, 12, 14 out = 0, 3, 6, 9, 12, 15, 18, 21 1分程度でシミュレーション完了 実行結果に問題がなければテストは完了 x86 emulation はOK でもCo-simulation でNG の パターンもよくあるので注意 Co-simulation: ハードウェアベースでのテスト モジュールコード テストコード x86 emulation を指定 モジュールコード テストコード Co-simulation 実行の ためにデバイスを指定 テスト時の 波形を保存

Slide 12

Slide 12 text

Copyright© Fixstars Group Intel HLS のレポート、シミュレーション波形 12 $ firefox ./a.prj/reports/report.html 高位合成レポートはHTML 形式で出力される $ vsim ./a.prj/verification/vsim.wlf シミュレーション波形は下記コマンドで確認可能 性能面に問題があればコードを修正 & テスト - レイテンシ : レポートのレイテンシサイクル数を確認 - スループット: レポートのII(Initiation Interval) を確認 レポートだけでは分からないことは波形で確認 - モジュール起動までサイクル数 - モジュールを複数回連続実行したときのII

Slide 13

Slide 13 text

Copyright© Fixstars Group AMD Xilinx Vivado/Vitis HLS との違い ● 細かい記述方法の差はあるが、大きくは変わらないと考えてよい ○ あえて挙げるとすれば下記となる ● 両社とも、自社製品以外でのそれぞれのHLS の利用を許可していないので、 開発対象デバイス次第でどちらを利用するか決まる ○ どちらかに触れたことがあれば、大きな違和感なく開発が行えるはず 13 項目 Intel HLS Vivado/Vitis HLS コメント 高位合成用の プロジェクト 不要 必要 Git 管理するときはプロジェクト不要の方が嬉しいが、 決定的な差ではない 標準バス Avalon AXI 共にMM, Stream があり、Quartus, Vivado との連携良好 性能の最適化 プラグマなしでも、ある程度最適化 プラグマで都度指示 最終的には両者ともプラグマで指示をすることになる * プラグマ: 高位合成時の指示のこと 性能チューニング時に多用する

Slide 14

Slide 14 text

Copyright© Fixstars Group 小ネタ: 開発時にハマったこと ● Stream で入力されるパケットから固定長のHeader を取り除き、 Body だけを出力するモジュールをIntel HLS で開発 ● 性能面の要求として、100 Gbps 以上のスループットが求められる ○ Stream を512 bit 幅とし、モジュールを250 MHz かつII=1 で動作させようと考えた ■ 512 bit * 250 MHz / 1 = 128 Gbps ● 簡単そうに見えるが、実は少しむずかしい 14 Header Body 14 Byte N Byte (N ≧ 46) Body N Byte (N ≧ 46) Module X by Intel HLS * II: Initiation interval, II=1 だと、Stream を連続入力して処理できる

Slide 15

Slide 15 text

Copyright© Fixstars Group 小ネタ: 開発時にハマったこと ● Stream の幅(512 bit=64 Byte) の関係で、Body Size で場合分けが発生する ○ 可変長の長さのパケットは、64 Byte 単位で切られて入出力され、 入力と出力でStream の切れ目が異なることに注意(下図の点線) 15 出力0は、入力0,1 が入ってからでないと出力できない 出力1は、入力2が入ったら出力できる 出力2は、入力3が入ったら出力できる 入力 出力 0 1 2 3 0 1 2 3 入力 出力 0 1 2 3 0 1 2 出力0は、入力0,1 が入ってからでないと出力できない 出力1は、入力2が入ったら出力できる 出力2, 3 は、入力3が入ったときに連続して出力する必要がある Pattern A Pattern B この実装が大変だった

Slide 16

Slide 16 text

Copyright© Fixstars Group 小ネタ: 開発時にハマったこと ● 最後の連続出力を記載すると、II=1がどうしても達成できない ○ Intel HLS の特性なのか、同一の出力ポートへのwrite が2行あると、II=2 になるようだ ● どうしたか? -> 出力ポートを2つに増やした ○ 異なるポートへのwrite であれば、2行書いてもII=1 になった ○ 後段にMerge module を追加したが、これはHLS でII=1 で問題なく記述することができた ● よりスマートな方法があるかもしれないので、情報提供お願いします🙇 16 Module X by Intel HLS 入力 通常の出力 最後の一回専用の出力 Merge module by Intel HLS 出力

Slide 17

Slide 17 text

Copyright© Fixstars Group まとめ ● HLS を利用することで、モジュール実装TAT の向上が見込める ● Intel HLS の実装/実行は、お作法さえ理解できれば容易 ● Vivado/Vitis HLS と比較して、記述方法, 使い方に極端な差は無い ● Intel FPGA ユーザーでしたら一度は触ってみてください 17

Slide 18

Slide 18 text

Copyright© Fixstars Group Lightning Talk!

Slide 19

Slide 19 text

Copyright© Fixstars Group Who I am 写真 Yuki MATSUDA 松田 裕貴 ソリューション第四事業部 リードエンジニア

Slide 20

Slide 20 text

Copyright© Fixstars Group Vitis HLS 2022.1 で追加され た performance pragma を使 ってみる

Slide 21

Slide 21 text

Copyright© Fixstars Group 目標性能 (サイクル数) を指示することで自動で最適化を行ってくれる pragma Performance pragma とは https://docs.xilinx.com/r/ja-JP/ug1399-vitis-hls/pragma-HLS-performance

Slide 22

Slide 22 text

Copyright© Fixstars Group Performance pragma の使い方 https://docs.xilinx.com/r/ja-JP/ug1399-vitis-hls/pragma-HLS-performance ● 構文: #pragma HLS performance target_ti=N ● ドキュメントのコード例で解説 ○ i ループが 1000 cycle で終わるように制約する ○ j ループの unrolling や b の array_partition が自動で適用される

Slide 23

Slide 23 text

Copyright© Fixstars Group 実際に使ってみる: vecadd ● まずはシンプルに vecadd。入出力のIF は AXI MM ● レポート上で Performance Pragma の目標値を達成できたかを確認できる ● シンプルな例なのに ti=1024 (II=1) を達成できず => AXI MM が 1port しかなく、 a, b の読み出しに 2サイクルかかるため

Slide 24

Slide 24 text

Copyright© Fixstars Group 実際に使ってみる: vecadd (cont.) ● 明示的に m_axi の読み出しポートを 2個にする => ti=1024 を達成 ● 流石にインターフェースに対する制約までは自動で書き換えないので、 この辺りは自分で適切に設定する必要がある模様

Slide 25

Slide 25 text

Copyright© Fixstars Group 実際に使ってみる: vecadd (cont.) ● 更に target_ti = 512 に減らせるか? (unroll=2 相当) ○ pragma の値を変えただけだと失敗 (左) ○ ちゃんと入出力のポート幅を増やせば成功 (右) ● やはり入出力までは自分で正しく設計する必要あり 失敗 成功

Slide 26

Slide 26 text

Copyright© Fixstars Group 実際に使ってみる: matmul ● インターフェース部分までは設計した上で、 演算ロジックをどこまでチューニングしてくれるかを確認してみる ● 入力データを予めローカル SRAM にキャッシュし、 それを用いて計算を行う 行列積の計算部分 ローカル SRAM への copy を含む top 定義

Slide 27

Slide 27 text

Copyright© Fixstars Group 実際に使ってみる: matmul (32並列) ● (32, 32) x (32, 32) の行列積を 1024 cycle で終わるように制約した場合 (unroll=32) ● => 成功

Slide 28

Slide 28 text

Copyright© Fixstars Group 実際に使ってみる: matmul (32並列, cont.) ● どんな回路が生成されているのか? => レポートに記載があった ● b を cyclic にしているので j ループを展開していそうに見えるが詳細は不明 https://docs.xilinx.com/r/ja-JP/ug1399-vitis-hls/%E9%85%8D%E5%88%97%E3%81%AE%E5%88%86%E5%89%B2

Slide 29

Slide 29 text

Copyright© Fixstars Group 実際に使ってみる: matmul (1024並列) ● (32, 32) x (32, 32) の行列積を 32 cycle で終わるように制約した場合 (unroll=1024) ● => これも成功。a, b, c それぞれに array_partition を適用している

Slide 30

Slide 30 text

Copyright© Fixstars Group まとめ ● performance プラグマを試してみた ● interface 部分は最適化対象外なので、そこは手動で設計が必要 ● array_partition 等の自動推論部分は優秀で、 行列積くらいなら良い感じに制約をかけてくれる ○ ただし、その制約が最適なのかどうかは確認した方が良さそう ● とりあえず performance プラグマを使用してみて、 良い回路が出ない場合は手動で制約をかけるような形が有用と思われる

Slide 31

Slide 31 text

Copyright © Fixstars Group Thank you! お問い合わせ窓口 : [email protected]