はじめに
インテル® HLS コンパイラーに興味をおもちで、まずは、サンプル等を触ってみたいという方も多いかと思います。
そこで、インテルから提供されているサンプル・チュートリアルの内容についてどういったサンプルが用意されているのかまとめました。
サンプル・チュートリアルはインテル® Quartus® Prime 開発ソフトウェアのインストール・ディレクトリーの下記に保存されています。
- <インストール・ディレクトリー>\intelFPGA\18.1\hls\examples
この記事で紹介するサンプルは、インテル® Quartus® Prime 開発ソフトウェア・スタンダード・エディションで提供されているものです。
また、サンプル・チュートリアルの実行手順については、下記をご確認ください。
HLS サンプル & チュートリアルまとめ
■デザインサンプル
(<インストール・ディレクトリー>\hls\examples)
|
サンプル |
内容 |
|
counter |
シンプルなカウンターを作成するサンプル。 |
|
image_downsample |
bmp ファイルの縦横比を小さくするサンプル。 |
|
interp_decim_filter |
補間フィルター、デシメーション・フィルターのサンプル。 |
|
QRD |
行列演算の QR 分解を行うサンプル。 |
|
YUV2RGB |
YUV422 から RGB888 への色空間変換のサンプル。 |
■ ac データ型関連のサンプル
(<インストール・ディレクトリー>\hls\examples\tutorials\ac_datatypes)
|
サンプル |
内容 |
|
ac_fixed_constructor |
コーディング・スタイルの小数の変動を用いてより良い QoR (結果の品質) が得られる ac_fixed コンストラクターの例を示すサンプル。 推奨の「コンポーネント外で動的な double / float 値を変換」を用いることで、非推奨「コンポーネント内で動的な double / float 値を変換」と比べてより良い結果が得られます。 |
|
ac_fixed_math_library |
固定小数点演算ライブラリーを使用したサンプル。 浮動小数点から固定小数点に切り替えた際の、精度/ QoR 間におけるトレードオフが確認できます。 |
|
ac_int_basic_ops |
ac_int 型を使用した複数の使用例を確認するサンプル。 ac_int 型の計算の例として、加算/乗算/除算の計算の記述例を確認できます。また、ac_int 型の演算子の例として、シフト演算子/左シフト演算子/スライスの記述例も確認できます。 |
|
ac_int_overflow |
DEBUG_AC_INT_WARNING と DEBUG_AC_INT_ERROR が発生し、それを回避する方法を示すサンプル。 どういった条件で DEBUG_AC_INT_WARNING や DEBUG_AC_INT_ERROR が発生するのか実例を基に確認できます。Linux 環境では gdb を使ってバックトレースすることを推奨します。 |
■ ベストプラクティス・ガイドで提示されている最適化内容のサンプル
(<インストール・ディレクトリー>\hls\examples\tutorials\best_practices)
|
サンプル |
内容 |
|
const_global |
const_global を使用した場合と、使用しなかった場合の比較ができるサンプル。 テストベンチがグローバル変数を一定の値で保持していても、コンパイラーは変数がすべての状況で一定であるとは想定しません。一方、const 修飾されたグローバル変数は、すべての状況で一定であることが保証されています。したがって、const 修飾されたグローバル変数は、コンポーネントにフォールディングされ、完全に最適化されます。 優れた結果を得るには、コンポーネント内で可変グローバル変数を使用しないようにすることが推奨です。 |
|
floating_point_ops |
浮動小数点演算結果の精度が多少悪くても許容できる場合に使用する i++ の --fpc フラグと --fp-relaxed フラグの影響度を示すサンプル。 ●--fp-relaxed フラグ : 演算実行順序を気にしない場合に、i++ へのコンパイラーへ最小限のパイプラインでの実現を指示できます。 ●--fpc フラグ : 可能であれば浮動小数点演算の中間丸めと正規化を最適化するようにコンパイラーに指示し、浮動小数点演算のチェーンに必要なハードウェアの量を削減できます。 |
|
integer_promotion |
promote-integer オプションで整数昇格を確認するサンプル。 g++ コンパイラーでは、自動的に整数昇格が行われますが、i++ では明示的に --promote-integer のオプションを付けて整数昇格を指示しないと、整数昇格が行われません。 |
|
loop_memory_dependency |
メモリー配列に依存性がないことを示す ivdep pragma の効果を確認するサンプル。 ループ構造において、インテル® HLS コンパイラーはデフォルトでは、依存関係があると判断し、依存関係にあるメモリー動作が完了するまで待機したり、ハードウェアを追加したりするため、リソースとパフォーマンスにボトルネックが発生します。依存関係のないループ構造において、ivdep pragma を使用することで、使用しない場合と比べて、II (Initiation Interval) の低減、リソースが削減できていることがレポートから確認できます。 |
|
parameter_aliasing |
"restrict" オプションを使用し、競合しないリード動作とライト動作間の不要なメモリー依存関係の生成を回避するサンプル。 "restrict" 型修飾子をポインター型に正しく適応させることで、不要な回路生成を回避し、Loop & Latency の改善をもたらします。 |
|
resource_sharing_filter |
firfilt と firfilt_shared という2つのフィルターを作成し、それぞれのフィルターの比較ができるサンプル。 firfilt はスループットの高いデザインで、シミュレーションからも returndata がクロックサイクル毎に返ってきていることが確認できます。firfilt_shared はスループットが低いデザインで、シミュレーションから returndata が返ってくるのに時間を要します。ただし、ロジックの使用数は少なく、firfilt と比較して ALUTs の使用数としても半分程度で済むことが確認できます。 |
|
shift_register |
シフトレジスターを実装する際に推奨するコーディング・スタイルについて示すサンプル。 この推奨コーディング・スタイルであれば、概ね最適化されたリソースとなります。 |
|
single_vs_double_precision_math |
単精度リテラルと関数を選択した場合の倍精度のものに対する影響を説明しているサンプル。 C++ 標準に精通していないユーザーは、単精度バージョンが意図されているときに誤って倍精度リテラルまたは関数を使用することがあります。倍精度演算はより複雑で、その結果、より多くのリソースを消費し、通常は単精度の実装よりも待ち時間が長くなります。以下の点に注意が必要です。 1) 倍精度値が必要な場合を除き、常に単精度リテラル(接尾辞「f」付き)を使用します。 2) 倍精度値によって提供される追加の精度または範囲が必要でない限り、単精度浮動小数点引数を受け入れて返す関数を選択します。 3) 倍精度浮動小数点値を明示的にできるだけ早く単精度値に戻すように変換して、偶然により多くの倍精度演算で追加の演算を実行しないようにします。 |
|
struct_interface |
パディングビット無しでインターフェイスを実装するための ac_int の使用方法を示すサンプル。 以下の異なるクラスに基づいて作成された両コンポーネントは同じ動作をします。 1) I26 バイト整列構造体 (184 bit) :class IPPacketHeader_padding 2) ac_int タイプ (160 bit) :class IPPacketHeader_no_padding |
|
swap_vs_copy |
swap を使用した際と deepcopy を使用した際の比較ができるサンプル。 ポインター・スワッピングは、大量のデータのコピーを回避するための一般的な方法ですが、この手法は今日のコンポーネント・メモリーでしか機能しないため、バッファーを実装するためにレジスターを使用する場合は別の手法が必要です。このサンプルでは、リソースとパフォーマンスを向上させるために、ディープコピーを持つレジスターを使用します。 deepcopy の使用により、swap と比較して最高の QoR が実現できます。 |
■ メモリー関連のサンプル
(<インストール・ディレクトリー>\hls\examples\tutorials\component_memories)
|
サンプル |
内容 |
|
bank_bits |
複数のメモリーへアクセスする際にアドレス指定する方法を示すサンプル。 指定方法の違いにより、メモリーへのアクセスパターンが異なることが確認できます。アクセスパターンが異なることはレポートの Component memory viewer からも確認できます。 |
|
depth_wise_merge |
"merge" アトリビュートを使用することで、2 つのメモリーブロックを 1 つのメモリーブロックにマージさせるサンプル。 パフォーマンスを犠牲にすることなく、load/store もマージでき、メモリーの使用量が削減できます。 |
|
static_var_init |
リセット時と電源起動時でコンポーネント内の初期化動作を制御するサンプル。 MIF ファイルを使用してメモリーを初期化することで、コンポーネントのリソース使用率と起動待ち時間を短縮します。 |
|
width_wise_merge |
同じアドレスにアクセスするメモリー 2 つを "merge" アトリビュートを使用することで、幅方向にマージさせるサンプル。 パフォーマンスを犠牲にすることなく、load/store もマージでき、メモリーの使用量が削減できます。 |
■ インターフェイス関連のサンプル
(<インストール・ディレクトリー>\hls\examples\tutorials\interfaces)
|
サンプル |
内容 |
|
explicit_streams_buffer |
stream_in、stream_out の使い方を示すサンプル。 "ihc::stream_in"、"ihc::stream_out" を使うことで、生成される回路のインターフェイスが Avalon® ストリーミング (ST) インターフェイスになることが確認できます。入力に対してバッファーも定義できますが、バッファーの定義方法についても確認できます。 |
|
explicit_streams_packets_ready_valid |
ストリーム信号処理の各種サンプル。 1) ストリーム信号の値を基準値より大きいか小さいかを判断し、大きい場合は基準値を出力することが確認できます。"ihc::stream_in"、"ihc::stream_out" を使って Avalon®-ST を使用しています。 2) part1 の回路に ihc::usesPackets を追加することで start of packet 及び end of packet から開始と終了を判断できることが確認できます。 3) part2 の回路から ihc::usesValid、ihc::usesReady を使用し valid 入力信号及び ready 出力信号が削除されていることが確認できます。 |
|
mm_master_testbench_operators |
メモリー・マップド・マスターでの getInterfaceAtIndex(int)演算子の使用方法を示すサンプル。 配列へのインデックス付けと似ています。詳細については、コード内の対応するコメントを参照してください。 |
|
mm_slaves |
4 byte Swap デザインをベースに、Step 毎にモジュールのインターフェイスを変更させていくサンプル。 1) Base Design ( デフォルト・インターフェイス) 2) "hls_avalon_slave_component" オプションにより、デフォルト HLS インターフェイスを Avalon® メモリー・マップド・スレーブ (MM Slave) のインターフェイスに変更します。 3) "hls_avalon_slave_register_argument" オプションにより、ユーザー入力インターフェイス含め、Avalon® MM Slave に集約します。 4) "hls_avalon_slave_memory_argument" オプションにより、RAM リソースと引換えに、ロジック削減, レイテンシー改善をもたらします。 |
|
multiple_stream_call_sites |
複数のストリーム・コールサイトを使用する利点を示すサンプル。 同じストリームにアクセスする全てのコールサイトは 1 つの FIFO ポートを共有し、同じストリームへの複数のリード/ライトを含む領域はシリアル化されます。つまり、その領域に対応するハードウェアは一度に 1 つのスレッド、またはループの反復のみを実行します。コンポーネントが x86 エミュレーションとして実行された場合も、FPGA シミュレーションで実行された場合も、リードとライトの順序は同じとなります。 |
|
pointer_mm_master |
コンポーネントの外にあるメモリーに格納されたデータに、簡素なベクタと制御をインプリしたサンプル。 様々なオプションを利用して、コンポーネント上の Avalon® MM インターフェイスを最適化します。 1) a,b,c、3 つのポインター入力と Avalon® MM Master インターフェイスをもった、Base Design (デフォルト・インターフェイス)。 2) コンポーネントへの追加記述により、外部メモリの Avalon® MM インターフェイスをパラレルに用意し、レイテンシーを改善します。 3) インターフェイスをまとめ、データ幅拡張、バースト対応への変更により、load / Store のリソースが増大する一方、効率的アクセス制御を実現します。 4) Load / Store ユニットを合体させ、コンパイラーにエリア、スループット変更を与えることで、レイテンシーの向上を実現します。 5) 融合したメモリーアクセスをメモリーワードでアラインさせ、Load / Store 部をシンプルにし、結果として Fmax を改善します。 |
|
stable_arguments |
"hls_stable_argument" アトリビュートを使用することで component 呼び出しの間に引数が変更されないことを確認できるサンプル。 パイプライン化された component から同じ引数が呼び出される際、"hls_stable_argument" アトリビュートを使用することで、component 呼び出しの間に引数が変更されないことを確認できます。 |
■ その他のサンプル
(<インストール・ディレクトリー>\hls\examples\tutorials\usability)
|
サンプル |
内容 |
|
enqueue_call |
直接関数呼び出しとエンキュー呼び出しした際のコンポーネント呼び出し時間を比較するサンプル。 エンキュー呼び出しでは、パイプライン形式で次々にコンポーネントをエンキューし呼び出すことができます。そのため、通常の直接呼び出しより、呼び出し時間を短くすることができます。(呼び出した関数の実行には ihc_hls_component_run_all() を実行する必要があります)。 |
|
qsys_2xclock |
clock と clock2x のシグナルを持つインターフェイスを作成する非常にシンプルなコンポーネントが含まれており、生成されたコンポーネントを取得し、Platform Designer システムに組み込む方法を説明しているサンプル。 PLL は基準クロックを取り込み、2 つの出力クロック信号を生成します。一方のクロックは他方の周波数の 2 倍の周波数を生成するように設定され、2 つのクロックは互いに同相で生成されることに注意が必要です。 |
|
qsys_stitching |
インテル® HLS コンパイラーで生成された複数コンポーネントを結合させ、バンドパスフィルターの生成フローを紹介しているサンプル。 インテル® Quartus® Prime 開発ソフトウェアの Platform Designer 機能を用いることで、複数コンポーネントの結合を簡単に行うことができます。 |
その他参考資料