インテル HLS コンパイラー: リファレンス・マニュアル
バージョン情報
更新対象: |
---|
インテル® Quartus® Prime デザインスイート 17.0 |
1. インテル HLS コンパイラー・リファレンス・マニュアル
- HLSコンパイラー・コマンドオプション
HLSコンパイラーは、一般的な関数を実行するための呼び出しやファイル・リンキング、またはコンパイルのカスタマイズが可能なコマンドオプションを含んでいます。 - コンポーネント合成でサポートされるサブセット
HLSコンパイラーには、サポートされる C99 サブセットと C++ に関連するいくつかの合成制限があります。 - 並行処理モデル
HLSコンパイラーは、コンポーネントの完全にパイプラインされたデータパスが必要であることを前提としています。 - コンポーネント・インターフェイス
HLSコンパイラーが生成するすべてのコンポーネントには、パラメーター・インターフェイスとコンポーネント呼び出しインターフェイスの 2 つのインターフェイスがあります。 - 標準 C および C++ ライブラリー
HLSコンパイラーは次のヘッダーファイルにより定義された特定の標準 C および C++ 関数の効果的な実装をサポートしています。 - 静的変数
HLSコンパイラーは C および C++ と同一のセマンティックを有する関数スコープの静的変数をサポートしています。 - ループ
HLSコンパイラーはループをパイプライン化して定義するさまざまなコンポーネントのスループットを最大化しようと試みます。 - 任意高精度整数のサポート
Algorithmic C (AC) データ型は、Mentor Graphics®が Apache ライセンスで提供する一連のヘッダーファイルです。 - エリアの最小化およびオンチップ・メモリー・アーキテクチャーの制御
属性をローカル変数に適用してローカルメモリー・システムのジオメトリーをカスタマイズし、回路のエリア使用率を節約できます。 - 改訂履歴
1.1. HLSコンパイラー・コマンドオプション
コマンドオプション | 説明 |
---|---|
--debug-log | コンパイラーに診断情報を含めたログファイルを生成するように指示します。 デフォルトでは、debug.logファイルは現在の作業ディレクトリー内のa.prjサブディレクトリーにあります。-o <result>コマンドオプションも含める場合は、debug.logファイルは <result>.prjサブディレクトリーに格納されます。 |
-hまたは --help | コンパイラーにすべてのコマンドオプションと画面上のそれらの説明を表示するように指示します。 コマンド : i++ -hまたは i++ --help |
-o <result> | コンパイラーに
<result>
実行可能ファイルと
<result>.prjディレクトリーの中に出力を配置するように指示します。 コンパイラーはデフォルトで Linux 用にa.outファイルを出力し、Windows 用にa.exeファイルを出力します。-o <result> コマンドオプションは、コンパイラー出力の名前を指定できます。 コマンド例 : i++ -o hlsoutput multiplier.c このコマンド例を呼び出すと、現在の作業ディレクトリー内に Linux 用のhlsoutput実行可能ファイルと Windows 用のhlsoutput.exeを作成します。 |
-v | コンパイルの進行状況を記述するメッセージの表示をコンパイラーに指する Verbose モードです。 コマンド例は、 i++ -v hls/multiplier/multiplier.cで、multiplier.cは入力ファイルを示します。 |
--version | コンパイラーに画面上にバージョン情報を表示するように指示します。 コマンド : i++ --version |
オプション | 説明 |
---|---|
-c | コンパイラーに現在の作業ディレクトリーにオブジェクト・ファイル (.o) を前処理、解析、および生成するように指示します。 コマンド例 : i++ -c multiplier.c このコマンド例を呼び出すと、multiplier.oファイルを作成します。 |
--component <components> | コンパイラーが RTL に合成する関数名のコンマ区切り値リストを指定できます。 コマンド例 : i++ --component <components> <input_files> |
-D <macro> [= <val> ] | コンパイラーにマクロ定義 (<macro>) とその値 (<val>) を渡すことができます。 <val> で値を指定しない場合、デフォルト値は 1 になります。 |
-I <dir> | ディレクトリー (<dir>) をインクルード・パス・リストの最後に追加します。 |
-march= [X86-64 | "<FPGA_family>" | "<FPGA_part_number>" | コンポーネントを指定されたアーキテクチャーまたは FPGA ファミリーにコンパイルするように、コンパイラーに指示します。
-marchコンパイラー・オプションは次のいずれかの値を取ります。
コマンド例 : i++ -march=x86-64 multiplier.c このコマンド例を呼び出すと、現在の作業ディレクトリーにa.outファイルを作成します。 コンパイルが失敗した場合は、プロジェクト・ディレクトリー ( a.prjなど ) にあるdebug.logファイルで詳細を参照してください。 |
--promote-integers | コンパイラーに g++ 整数昇格を模倣するための追加の FPGA リソースを使用するように指示します。 --promote-integersコマンドオプションについては <path to i++ installation>/examples/tutorials/best_practices/integer_promotionデザイン例を参照にしてください。 コンパイルに g++ 整数昇格ルールを適用すると、大量のエリア・オーバーヘッドを引き起こします。インテルは、プロダクション・コンパイルでの整数昇格を推奨していません。プロダクション・コンパイルでは、未定義の算術オーバーフロー動作に依存しなくてもいいように、コンポーネント内のデータ型のサイズを適切にします。 |
--quartus-compile |
Quartus® Primeソフトウェアを使用して HDL ファイルをコンパイルします。 コマンド例 : i++ --quartus-compile <input_files> 出力ファイルは、 <result>.prj/quartusディレクトリー内のコンパイルした Quartus® Primeプロジェクトと <result>.prj/reportsディレクトリー内のレポートです。このコンパイルは、コンポーネントを FPGA アーキテクチャーにコンパイルする際に作成されるすべてのファイルも生成します。 |
--simulator
<name>
--simulator none |
検証の実行に使用しているシミュレーターを指定します。 重要:
--simulator
<name> コマンドオプションは-march="
<FPGA_family_or_part_number>
" コマンドオプションと併せてのみ動作します。
デフォルトでは、i++コマンドに-march="
<FPGA_family_or_part_number>
" を含める際、--simulator <name>
は自動的に--simulator modelsimに設定されるため、--simulator <name>
オプションを指定する必要はありません。--simulator noneオプションは、検証フローをスキップし、対応するテストベンチを生成せずにコンポーネントの RTL を生成するように、HLSコンパイラーに指示します。このオプションは、生成された HLD レポート (report.html) でコンポーネント・デザインを反復する必要がある場合に使用します。 コマンド例 : i++ -march="<FPGA_family_or_part_number>" --simulator none multiplier.c |
オプション | 説明 |
---|---|
-clock <clock_spec> | 指定されたクロック周波数または期間で RTL を最適化します。 |
--fpc | 可能な場合、中間丸めと変換を削除します。 |
--fp-relaxed | 算術演算の順序を緩和します。 |
-ghdl | フルデバッグの可視化を有効にし、検証実行可能の実行時にすべての信号をログ付けします。実行可能が実行された後、シミュレーターは波形をa.prj/verification/vsim.wlfファイルにログ付けします。 |
-L <dir> | ディレクトリー (<dir>) をライブラリー・ファイルの検索パスの最後に追加します。 |
-l <library> | オブジェクト・ファイルがバイナリーにリンクする際に、ライブラリー・ファイル名を指定します。 |
1.2. コンポーネント合成でサポートされるサブセット
- 動的ループ境界または分岐は、エリア・オーバーヘッドを引き起こす可能性があります。
- コンパイラーは、動的メモリー割り当て、仮想関数、関数ポインター、およびこの資料の付録で明示的に言及しているサポートされる数学関数を除く C++ または C ライブラリーの関数を合成できません。一般的に、コンパイラーは、クラス、構造、関数、テンプレート、およびポインターを含む関数を合成できます。
コンパイル時にコードがコンパイラーに提供できる情報が多いほど、結果となるハードウェアはより小さく、より速くなります。いくつかの C++ コンストラクターは合成可能ですが、可能な場合は C99 でコンポーネント関数を作成してください。
1.3. 並行処理モデル
1.3.1. メモリースペースまたは I/O 内のシリアルの等価性
単一共有メモリースペースを表示する場合、複数の関数コールが順次実行されると考える必要があります。この場合、done信号がアサートされると、ハードウェアのコンポーネント呼び出しの結果は次のコンポーネント呼び出しと外部システムの両方からの可視化が保証されます。
関連する依存性の並列実行を許容する場合、HLSコンパイラーはパイプライン並列化を利用してコンポーネント呼び出しを実行し、並列にループ反復処理を行います。HLSコンパイラーはコンポーネント呼び出しに広がる依存性のトラックし続けるハードウェアを生成するため、メモリースペースに広がるシリアルの等価性を保証しながらパイプライン並列化をサポートすることができます。I/O 命令間の順序は保証されません。
1.3.2. hls_max_concurrencyを使用した並行処理の制御
hls_max_concurrencyコンポーネント属性を使用して、コンポーネントの最大並行処理を増減することができます。コンポーネントの並行処理は、一度に実行できるコンポーネント呼び出し数です。デフォルトでは、 インテル® HLS コンパイラーはコンポーネントがピーク・スループットで動作するため、並行処理を最大化しようと試みます。
#include "HLS/hls.h" hls_max_concurrency(3) component void foo ( /* arguments */ ){ // Component code }
- インテル HLS コンパイラーは、コンポーネント・レベルでのスループットの増加のためにローカルメモリーを自動的に複製しません。コンポーネント呼び出しが、コンポーネント呼び出しによって使用される ( 静的でない ) ローカル・メモリー・システムを使用する場合、前の呼び出しがローカルメモリーへ、およびローカルメモリーからのすべてのアクセスを終了するまで、次の呼び出しを開始できません。この制限は、ループ分析レポートにアレイでのロードストアーの依存関係として表示されます。コンポーネントでhls_max_concurrency(N)属性を追加することで、ローカルメモリーを複製し、同時にコンポーネントの複数の呼び出しが可能です。
- 場合によっては、コンパイラーは大量のエリアを節約するために並行処理を減らします。これらの場合は、hls_max_concurrency(N)属性は並行処理を 1 つから増やすことができます。
また、max_concurrency(N)プラグマを使用して、ループの並行処理を制御することも可能です。max_concurrency(N)プラグマについて詳しくは、ループ並行処理の制御を参照してください。
1.4. コンポーネント・インターフェイス
パラメーター・インターフェイスは、関数の引数の中にデータをプッシュしたり関数からのデータを返したりするために使用するプロトコルです。次の関数の定義を考察します。
component int interfaces(int a, int b);
関数の定義は 2 つの引数 ( すなわち aとb) があります。ハードウェアで使用するプロトコルを各引数に渡す際にどのように指定するかについて詳しくは、パラメーター・プロトコルを参照してください。
コンポーネントへのコール動作やコンポーネントから返す動作を表すには、コンポーネント呼び出しインターフェイスが必要です。このインターフェイスは、戻り値 ( nonvoid 関数で ) と、コンポーネントに制御を渡し、関数が実行を完了すると制御を戻すハンドシェイク信号が含まれています。
1.4.1. コンポーネント・インターフェイスの構造体
コンポーネント内の構造体での実装インターフェイスのパディングおよび Packed-ness に関する情報は、 <a.prj>/components/<component_name> フォルダー内のinterface_structs.svファイルを確認し、参照してください。
interface_structs.svファイルには、コンポーネント・インターフェイスで見つかった Verilog 形式の定義が含まれています。
1.4.2. パラメーター・プロトコル
- スカラー・パラメーターおよび Avalon Streaming インターフェイス
コンポーネントのすべてのスカラー・パラメーター関数引数には、生成した Verilog モジュール内に入力ポートがあります。 - ポインター・パラメーター、参照パラメーター、および Avalon Memory-Mapped インターフェイス
コンポーネントは、Avalon® Memory-Mapped (Avalon®-MM) インターフェイスを介して外部メモリーとインターフェイスすることができます。 - メモリーマップド・マスター・テストベンチ・コントラクター
これらのメモリー・インターフェイスを記述するためのメモリーマップド・マスター・クラス (mm_master<>) が使用するコンポーネントでは、各mm_master引数でのテストベンチでmm_master<>オブジェクトを作成する必要があります。 - 参照パラメーター
HLSコンパイラーはポインター・パラメーターと同様の方法で参照パラメーターを扱います。 - グローバル変数
コンポーネントはグローバル変数の使用と更新ができます。HLSコンパイラーは、コンポーネントへのポインター引数と同様の方法でグローバル変数をモデル化します。 - 引数の実装を制御するマクロと属性
ソースコード内のマクロまたは属性を個別のコンポーネント引数に追加することにより、これらのインターフェイスの実装をポインター・パラメーターと同様の方法で制御するオプションがあります。
1.4.2.1. スカラー・パラメーターおよび Avalon Streaming インターフェイス
スカラー引数入力に加えて、コンポーネントは、Avalon-ST インターフェイス仕様に準拠する明示的な入力ストリームおよび出力ストリームを有することができます。各ストリームは、コンポーネント内部に 1 つのリードまたはライトのみを有する場合があります。これらの入力ストリームおよび出力ストリームは、提供されたihc::stream_in<> とihc::stream_out<> テンプレート・クラスをコンポーネントへの関数引数として使用することで、C ソースで表されます。これらのクラスをコンポーネント・シグネチャーの参照パラメーターとして定義する必要があります。これらのクラスは他のクラスの基本クラスとして使用したり、構造体や配列などのその他の形式でカプセル化したりすることはできません。ただし、他のクラス内部の参照として使用することができ、つまり、データメンバーとしてストリームへの参照を持つクラスが構築できるということを意味しています。
ストリーミング・インターフェイスについて詳しくは、Avalon Interface Specificationsを参照してください。
テンプレート引数 | 値 | デフォルト | 説明 |
---|---|---|---|
ihc::type | 任意の有効な C++ 型 | N/A | ストリームにより実行されるデータ型。 |
ihc::buffer | 正の整数値 | 0 | ストリームに関連するデータ上のワード単位での FIFO バッファーの容量。 このパラメーターは入力ストリームでのみ有効です。 |
ihc::readyLatency | 正の整数値 値の範囲は 0 ~ 8 |
0 | ready 信号がディアサートされてから、ストリームシンクが新しい入力を受け入れられなるまでの間のサイクル数。概念的には、このパラメーターはストリームに関連するデータの入力 FIFO バッファーでの almost ready レイテンシーとして確認できます。 |
ihc::bitsPerSymbol | 正の整数値 値はデータ型サイズにより均等に分割される必要があります。 |
データ型のサイズ | データがどのようにデータバスのシンボル内で分割されるかを記述します。データは常にリトル・エンディアンの順序で分割されます。 |
ihc::usesPackets | trueまたはfalse | false | ストリーム・インターフェイスのstartofpacketとendofpacketのサイドバンド信号を抽出します。信号はパケットベースのリード / ライトによりアクセス可能です。 |
ihc::usesReady | trueまたはfalse | true |
stream_out<> インターフェイスでのみサポートされます。 ready 信号が存在するかどうかを制御します。true の場合、ダウンストリーム・シンクは valid がアサートされるサイクルごとにデータを受け入れます。 これは、ストリーム書き込みコールをtryWriteに変更し、successが常にtrueであることと同じことです。 falseに設定すると、readyLatencyは0になります。 |
ihc::usesValid | trueまたはfalse | true |
stream_in<>インターフェイスでのみサポートされます。 valid 信号がストリーム・インターフェイスに存在しているかどうかを制御します。false の場合、アップストリーム・ソースは ready 信号がアサートされるサイクルごとに有効データを提供します。 これは、ストリーム書き込みコールをtryReadに変更し、success が常に true であることと同じことです。 falseに設定すると、bufferとreadyLatencyは0になります。 |
API | ブロックキング | サイドバンド信号 | コンポーネントのstream_inによる使用 | コンポーネントのstream_outによる使用 | 説明 |
---|---|---|---|---|---|
T read() | 可能 | 不可能 | 可能 | 不可能 | この関数は、ストリームから次の使用可能なデータ項目を読み込みます。コンポーネント内に使用可能なデータがない場合、関数は有効なデータが存在するまでデータパスをストールします。 |
T read(bool& sop, bool& eop) | 可能 | 可能 | 可能 | 不可能 | この関数はusesPacketsがtrueに設定されている場合のみ使用可能です。 この関数は、ストリームから次の使用可能なデータ項目を読み込みます。コンポーネント内に使用可能なデータがない場合、関数は有効なデータが存在するまでデータパスをストールします。 |
T tryRead(bool& success) | 不可能 | 不可能 | 可能 | 不可能 | この関数は、使用可能な場合にストリームから次の使用可能なデータ項目を読み込みます。この関数コールはストールを引き起こしません。bool引数はデータが有効かどうかを表示します。 |
T tryRead(bool& success, bool& sop, bool& eop) | 不可能 | 可能 | 可能 | 不可能 | この関数は、usesPacketsがtrueに設定されている場合のみ使用可能です。 この関数は、次のデータが使用可能な場合にストリームからそのデータを読み込みます。この関数コールはストールを引き起こしません。bool引数はデータが有効かどうかを表示します。 |
void write(T arg) | 可能 | 不可能 | 不可能 | 可能 | この関数はデータをストリームに書き込みます。ストリームが新しいデータを受け入れられない場合 ( 例えば、ストリームの他のエンドからのストールのため )、この関数はストリームにデータを書き込めるまでデータパスをストールします。 |
void write(T data, bool sop, bool eop) | 可能 | 可能 | 不可能 | 可能 | この関数は、usesPacketsがtrueに設定されている場合のみ使用可能です。 この関数はデータをストリームに書き込みます。ストリームが新しいデータを受け入れられない場合、この関数はストリームにデータを書き込めるまでデータパスをストールします。 |
bool tryWrite(T data) | 不可能 | 不可能 | 不可能 | 可能 | この関数は、新しいデータを受け入れられる場合、ストリームにデータを書き込みます。この関数コールはストールを引き起こしません。bool戻り値はライト命令が実行されたかどうかを表示します。 |
bool tryWrite(T data, bool sop, bool eop) | 不可能 | 可能 | 不可能 | 可能 | この関数は、usesPacketsがtrueに設定されている場合のみ使用可能です。 この関数は、新しいデータを受け入れられる場合にストリームにデータを書き込みます。この関数コールはストールを引き起こしません。bool戻り値はライト命令が実行されたかどうかを表示します。 |
1.4.2.2. ポインター・パラメーター、参照パラメーター、および Avalon Memory-Mapped インターフェイス
テンプレート引数 | 値 | デフォルト | 説明 |
---|---|---|---|
type | 任意の有効な C++ 型 | N/A | 基となるポインター型です。マスター・オブジェクトで実行されるポインター演算はこの型に準じます。マスターの依存関係は、sizeof(type)の幅を有するロード・ストアー・サイトの結果となります。ポインター引数は、少なくともバイト単位でsizeof(type)に揃えられている必要があります。 |
ihc::dwidth<value> | 8、16、32、64、128、256、512、または 1024 | 64 | ビット単位のメモリーマップド・データバスの幅。 |
ihc::awidth<value> | 1 – 64 の範囲の整数値 | 64 | ビット単位のメモリーマップド・アドレスバスの幅。 |
ihc::aspace<value> | 0 よりも大きい整数値 | 1 | マスターに関連するインターフェイスのアドレススペースです。同じアドレススペースのすべてのマスターは、コンポーネント内で単一インターフェイスに調停されます。これらのマスターは、インターフェイスを記述する同じテンプレート・パラメーターを共有している必要があります。 |
ihc::latency<value> | 正の整数値 | 1 | 外部メモリーが有効な読み出しデータを返す際に、read コマンドがコンポーネントを終了してから保証されるレイテンシーです。 このレイテンシーが変数の場合、 0 に設定されます。 |
ihc::maxburst<value> | 1 – 1024 の範囲の整数値 | 1 | リードおよびライト・トランザクションに関連付けることができるデータ転送の最大数です。固定レイテンシー・インターフェイスでは、値は 1 に設定される必要があります。 詳しくは、Avalon Interface Specificationsを参照ししてください。 |
ihc::align<value> | type引数の整列の整数倍である整数値 | 型のアライメント |
基本ポインターアドレスのバイト境界合わせです。HLSコンパイラーはこの情報を使用してこのポインターへのロードとストアーで可能な結合の量を決定します。 データ型の幅がマスターデータの幅より小さい場合、 インテル® はこの引数を少なくともマスター幅と同じに設定することを推奨しています。 例えば、型がcharでマスター幅を 64 ビットになるように設定している場合、各クロックサイクルごとに 8 文字をリードまたはライトできるように、alignテンプレート引数を 8 バイトに設定します。 重要: 呼び出し元は、align引数の設定値にデータを整列する必要があります。そうでない場合、機能上で障害が起こる場合があります。
|
1.4.2.3. メモリーマップド・マスター・テストベンチ・コントラクター
mm_master<>オブジェクトを作成するには、コードに次のコンストラクターを追加します。
ihc::mm_master<int, … > mm(void* ptr, int size, bool use_socket=false);
位置
- void* ptrはテストベンチでのメモリーへの基となるポインターです。
- int sizeはバイト単位のバッファーの合計サイズです。
-
bool use_socketはメモリーバッファーのコピーをオーバーライドして、すべてのメモリーアクセスをテストベンチ・メモリーに戻すオプションです。
デフォルトでは、HLSコンパイラーはメモリーバッファーをシミュレーターにコピーし、コンポーネントが実行された後にそれをコピーして戻します。リンクされたリストのポインターチェーシングなどの場合、メモリーバッファーを前後にコピーすることは好ましくありません。この動作はbool use_socketをtrueに設定することでオーバーライドできます。
注: bool use_socketをtrueに設定すると、64 ビット幅アドレスのmm_mastersのみがサポートされます。更に、このオプション設定はシミュレーションのランタイムを増加させます。
1.4.2.3.1. 暗黙的および明示的なメモリー・インターフェイスの記述例
暗黙的な例
次のコード例は、両方のポインター逆参照からのロード / ストアー命令をコンポーネントのトップレベル・モジュールの単一インターフェイスに調停します。このインターフェイスは、64 ビットのデータバス幅と 64 ビットアドレス幅、および固定レイテンシー 1 を有します。
#include "HLS/hls.h" component void dut(int *ptr1, int *ptr2) { *ptr1 += *ptr2; *ptr2 += ptr1[1]; } int main(void) { int x[2] = {0, 1}; int y = 2; dut(x, &y); return 0; }
明示的な例
この例は、明示的なmm_masterクラスを使用して、特定のメモリー・インターフェイスに対して前のコードスニペットを最適化する方法を示します。mm_masterクラスは定義されたテンプレートであり、次の特性があります。
- 各インターフェイスには、2 つの独立したインターフェイスを推測してコンポーネント内の調停量を減らす一意の ID が与えられる。
- デフォルトの 64 ビット幅より大きいデータバス幅
- デフォルトの 64 ビット幅より小さいアドレスビット幅
- 2 の固定レイテンシーを有するインターフェイス
これらの特性を定義することで、システムが正確に 2 クロックサイクル後に有効な読み込みデータを返し、読み込みと書き込みの両方でインターフェイスがストールしないことが保証されますが、システムは 2 つの異なるメモリーが提供できなければなりません。
#include "HLS/hls.h" component void dut(ihc::mm_master<int, ihc::dwidth<256>, ihc::awidth<32>, ihc::aspace<1>, ihc::latency<2> > &mm1, ihc::mm_master<int, ihc::dwidth<256>, ihc::awidth<32>, ihc::aspace<4>, ihc::latency<2> > &mm2) { *mm1 += *mm2; *mm2 += mm1[1]; } int main(void) { int x[2] = {0, 1}; int y = 2; ihc::mm_master<int, ihc::dwidth<256>, ihc::awidth<32>, ihc::aspace<1>, ihc::latency<2> > mm_x(x,2*sizeof(int),false); ihc::mm_master<int, ihc::dwidth<256>, ihc::awidth<32>, ihc::aspace<1>, ihc::latency<2> > mm_y(&y,sizeof(int),false); dut(mm_x, mm_y); return 0; }
1.4.2.4. 参照パラメーター
1.4.2.5. グローバル変数
コンポーネントはグローバル変数の使用と更新ができます。HLSコンパイラーは、コンポーネントへのポインター引数と同様の方法でグローバル変数をモデル化します。
コンポーネントが使用する各グローバル変数は、@<global variable name> という名前のコンデュイット引数があり、この変数はシステムメモリー内の特定のグローバル変数のアドレスが指定されている必要があります。その結果、コンポーネント内のグローバル変数を使用すると、グローバル変数を定数として宣言する場合と比べて、デザインに必要なエリアが増えます。追加エリアは、グローバル変数とロード・ストアー・ユニットのやり取りに必要です。
定数グローバル変数の最適化
グローバル変数が定数の場合、constとして宣言するとグロバール変数の余白エリアの使用はされなくなります。
1.4.2.6. 引数の実装を制御するマクロと属性
<path to i++ installation>/include/HLS/hls.h ファイル内のマクロ定義 | 属性 | 説明 |
---|---|---|
hls_conduit_argument | __attribute__((argument_interface("wire"))) | デフォルト実装。 コンパイラーは、Avalon®-ST プロトコルに従って、コンポーネントの呼び出し (start または busy) インターフェイスに同期する入力コンデュイットとして引数を実装します。 |
hls_avalon_slave_register_argument | __attribute__((argument_interface("avalon_mm_slave"))) | コンパイラーは、Avalon-MM スレーブ・インターフェイスを介して読み出しと書き込みができるレジスターとして引数を実装します。引数は、コンデュイットの実装と同様にコンポーネントのパイプラインに読み込まれます。実装は、start または busy インターフェイスに同期します。 |
hls_avalon_slave_memory_argument(size_of_slave_memory_in_bytes) | N/A | コンパイラーは、専用スレーブ・インターフェイスを介して読み出しと書き込みができるオンチップ・メモリーブロックに引数を実装します。 生成されたメモリーは、他のすべての内部コンポーネント・メモリー ( つまり、バンキング、結合など ) と同じアーキテクチャーの最適化を行います。コンパイラーが静的結合の最適化を実行する場合、スレーブ・インターフェイスのデータ幅は結合した幅になります。
注: この属性はポインター引数にのみ適用されます。
|
<path to i++ installation>/include/HLS/hls.h ファイル内のマクロ定義 | 属性 | 説明 |
---|---|---|
hls_stable_argument | __attribute__((stable_argument)) | 安定引数とは、コンポーネントにライブデータがある間 ( つまり、パイプラインされた関数呼び出しの間 ) に変更されない引数のことです。 コンポーネント実行中の安定引数の変更には予期しない動作が発生する可能性があります。特に、安定引数の使用ごとに古い値または新しい値になる可能性があり、呼び出し内での一貫性が保証されません。すなわち、同じ呼び出しでの同じ変数が複数の値で表示されます。 適切な場合は、安定引数の使用によりデザインで大量のレジスター数の節約が可能です。 |
1.4.2.6.1. インターフェイス合成マクロの使用例
#include "HLS/hls.h" component int dut(hls_conduit_argument int a, hls_avalon_slave_register_argument int b) { return a * b; }
#include "HLS/hls.h" component int dut(hls_stable_argument hls_conduit_argument int a, hls_stable_argument hls_avalon_slave_register_argument int b) { return a * b; }
1.4.3. コンポーネント呼び出しインターフェイスを制御するマクロと属性
マクロ | 属性 | 説明 |
---|---|---|
hls_avalon_streaming_component | __attribute__((component_interface("avalon_streaming"))) | この属性は関数コールとリターンストリームの両方のAvalon®-ST プロトコルに従います。コンポーネントは、start信号がアサートされ、busy信号がディアサートされると、不安定引数を消費します。コンポーネントはdone信号がアサートされると戻りデータを生成します。 このインターフェイスはデフォルトのコンポーネント呼び出しインターフェイスです。 トップレベル・モジュール・ポート 関数コール—start、busy 関数戻り値—done、stall |
hls_avalon_slave_component | __attribute__((component_interface("avalon_mm_slave"))) |
start、done、およびreturndata ( 可能な場合 ) 信号は、コンポーネントのスレーブ・メモリーマップにレジスターされます。詳細については、CSR スレーブの項を参照してください。 トップレベル・モジュール・ポート : Avalon-MM スレーブ・インターフェイス |
hls_always_run_component | __attribute__((component_interface("always_run"))) |
start信号はコンポーネントの内部で1に結び付けられます。done信号の出力はありません。コンポーネントのデータパスがデータの入力と出力の明示的なストリームにのみ依存する場合は、このプロトコルを使用します。 重要: IP 検証は、このコンポーネント呼び出しプロトコルを使用するコンポーネントをサポートしていません。
トップレベル・モジュール・ポート : None |
1.4.3.1. コンポーネント呼び出しプロトコルマクロの使用例
#include "HLS/hls.h" hls_avalon_streaming_component component int dut(hls_conduit_argument int a, hls_avalon_slave_register_argument int b) { return a * b; }
#include "HLS/hls.h" hls_avalon_slave_component component int dut(hls_conduit_argument int a, hls_avalon_slave_register_argument int b) { return a * b; }
#include "HLS/hls.h" hls_always_run_component component int dut(hls_conduit_argument int a, hls_avalon_slave_register_argument int b) { return a * b; }
1.4.4. スレーブ・インターフェイス
スレーブ型 | 実装 | 関連するスレーブ・インターフェイス | リード / ライト動作 | 同期化 | リード・レイテンシー | インターフェイス・データ幅の制御 |
---|---|---|---|---|---|---|
Register | レジスター | コンポーネントの制御およびステータスレジスター (CSR) スレーブ | 書き込まれた値を読み出し直す場合にのみ使用します。コンポーネントは、これらのレジスターをデータパスから更新できません。 | コンポーネントの start 信号を使用する同期化を制御するためにhls_stable_argument マクロを使用します。 | 固定値 1 | 常に 64 ビット |
Memory | M20K | コンポーネントの専用スレーブ・インターフェイス | コンポーネントのデータパスからの更新はメモリーで可視化されます。 | このメモリーでのすべての変更は、コンポーネントのデータパスに即時に表示されます。したがって、コンポーネントの外部からのリードとライトは、コンポーネント内で実行中のスレッドがない場合にのみ発生します。 | 固定値はコンポーネントに依存します。 詳細はコンポーネントの.qsysファイルを参照してください。 |
データ幅はスレーブのデータ型の倍数であり、倍数は内部アクセスを合わせて決定します。 |
1.4.4.1. CSR スレーブ
HLSコパイラーはレジスターに CSR スレーブを実装します。
CSR スレーブを使用するコンポーネントのコード例 :
#include "HLS/hls.h" struct MyStruct { int f; double j; short k; }; hls_avalon_slave_component component MyStruct mycomp_xyz (hls_avalon_slave_register_argument int y, hls_avalon_slave_register_argument MyStruct struct_argument, hls_avalon_slave_register_argument unsigned long long mylong, hls_avalon_slave_register_argument char char_arg ) { return struct_argument; }
コンポーネントmycomp_xyzで生成される C ヘッダーファイル :
/* This header file describes the CSR Slave for the mycomp_xyz component */ #ifndef __MYCOMP_XYZ_CSR_REGS_H__ #define __MYCOMP_XYZ_CSR_REGS_H__ /******************************************************************************/ /* Memory Map Summary */ /******************************************************************************/ /* Register | Access | Register Contents | Description Address | | (64-bits) | ------------|---------|--------------------------|----------------------------- 0x0 | W | {reserved[62:0], | Write 1 to signal start to | | start[0:0]} | the component ------------|---------|--------------------------|----------------------------- 0x8 | R/W | {reserved[62:0], | 0 - Disable interrupt, | | interrupt_enable[0:0]} | 1 - Enable interrupt ------------|---------|--------------------------|----------------------------- 0x10 | R/Wclr | {reserved[61:0], | Signals component completion | | done[0:0], | done is read-only and | | interrupt_status[0:0]} | interrupt_status is write 1 | | | to clear ------------|---------|--------------------------|----------------------------- 0x18 | R | {returndata[63:0]} | Return data (0 of 3) ------------|---------|--------------------------|----------------------------- 0x20 | R | {returndata[127:64]} | Return data (1 of 3) ------------|---------|--------------------------|----------------------------- 0x28 | R | {returndata[191:128]} | Return data (2 of 3) ------------|---------|--------------------------|----------------------------- 0x30 | R/W | {reserved[31:0], | Argument y | | y[31:0]} | ------------|---------|--------------------------|----------------------------- 0x38 | R/W | {struct_argument[63:0]} | Argument struct_argument (0 of 3) ------------|---------|--------------------------|----------------------------- 0x40 | R/W | {struct_argument[127:64]} | Argument struct_argument (1 of 3) ------------|---------|--------------------------|----------------------------- 0x48 | R/W | {struct_argument[191:128]} | Argument struct_argument (2 of 3) ------------|---------|--------------------------|----------------------------- 0x50 | R/W | {mylong[63:0]} | Argument mylong ------------|---------|--------------------------|----------------------------- 0x58 | R/W | {reserved[55:0], | Argument char_arg | | char_arg[7:0]} | NOTE: Writes to reserved bits will be ignored and reads from reserved bits will return undefined values. */ /******************************************************************************/ /* Register Address Macros */ /******************************************************************************/ /* Byte Addresses */ #define MYCOMP_XYZ_CSR_START_REG (0x0) #define MYCOMP_XYZ_CSR_INTERRUPT_ENABLE_REG (0x8) #define MYCOMP_XYZ_CSR_INTERRUPT_STATUS_REG (0x10) #define MYCOMP_XYZ_CSR_RETURNDATA_0_REG (0x18) #define MYCOMP_XYZ_CSR_RETURNDATA_1_REG (0x20) #define MYCOMP_XYZ_CSR_RETURNDATA_2_REG (0x28) #define MYCOMP_XYZ_CSR_ARG_Y_REG (0x30) #define MYCOMP_XYZ_CSR_ARG_STRUCT_ARGUMENT_0_REG (0x38) #define MYCOMP_XYZ_CSR_ARG_STRUCT_ARGUMENT_1_REG (0x40) #define MYCOMP_XYZ_CSR_ARG_STRUCT_ARGUMENT_2_REG (0x48) #define MYCOMP_XYZ_CSR_ARG_MYLONG_REG (0x50) #define MYCOMP_XYZ_CSR_ARG_CHAR_ARG_REG (0x58) /* Argument Sizes (bytes) */ #define MYCOMP_XYZ_CSR_RETURNDATA_0_SIZE (8) #define MYCOMP_XYZ_CSR_RETURNDATA_1_SIZE (8) #define MYCOMP_XYZ_CSR_RETURNDATA_2_SIZE (8) #define MYCOMP_XYZ_CSR_ARG_Y_SIZE (4) #define MYCOMP_XYZ_CSR_ARG_STRUCT_ARGUMENT_0_SIZE (8) #define MYCOMP_XYZ_CSR_ARG_STRUCT_ARGUMENT_1_SIZE (8) #define MYCOMP_XYZ_CSR_ARG_STRUCT_ARGUMENT_2_SIZE (8) #define MYCOMP_XYZ_CSR_ARG_MYLONG_SIZE (8) #define MYCOMP_XYZ_CSR_ARG_CHAR_ARG_SIZE (1) /* Argument Masks */ #define MYCOMP_XYZ_CSR_RETURNDATA_0_MASK (0xffffffffffffffffULL) #define MYCOMP_XYZ_CSR_RETURNDATA_1_MASK (0xffffffffffffffffULL) #define MYCOMP_XYZ_CSR_RETURNDATA_2_MASK (0xffffffffffffffffULL) #define MYCOMP_XYZ_CSR_ARG_Y_MASK (0xffffffff) #define MYCOMP_XYZ_CSR_ARG_STRUCT_ARGUMENT_0_MASK (0xffffffffffffffffULL) #define MYCOMP_XYZ_CSR_ARG_STRUCT_ARGUMENT_1_MASK (0xffffffffffffffffULL) #define MYCOMP_XYZ_CSR_ARG_STRUCT_ARGUMENT_2_MASK (0xffffffffffffffffULL) #define MYCOMP_XYZ_CSR_ARG_MYLONG_MASK (0xffffffffffffffffULL) #define MYCOMP_XYZ_CSR_ARG_CHAR_ARG_MASK (0xff) /* Status/Control Masks */ #define MYCOMP_XYZ_CSR_START_MASK (1<<0) #define MYCOMP_XYZ_CSR_START_OFFSET (0) #define MYCOMP_XYZ_CSR_INTERRUPT_ENABLE_MASK (1<<0) #define MYCOMP_XYZ_CSR_INTERRUPT_ENABLE_OFFSET (0) #define MYCOMP_XYZ_CSR_INTERRUPT_STATUS_MASK (1<<0) #define MYCOMP_XYZ_CSR_INTERRUPT_STATUS_OFFSET (0) #define MYCOMP_XYZ_CSR_DONE_MASK (1<<1) #define MYCOMP_XYZ_CSR_DONE_OFFSET (1) #endif /* __MYCOMP_XYZ_CSR_REGS_H__ */`
1.4.4.2. スレーブメモリー
- マスター・インターフェイスはシングルポートを有します。コンポーネントに複数のロード・ストアー・サイトがある場合、そのポートの調停により、ストール可能なロジックが作成される可能性があります。
- コンポーネントがインスタンス化されているシステムによっては、コンポーネントが動作中に他のマスターがメモリーバスを使用して、バス上に好ましくないストールを作成する場合があります。
小から中サイズのオンチップ・メモリーでは、スレーブメモリーのポインター引数は上記の欠点にアドレスする可能性があります。ポインター引数をスレーブメモリーとして宣言することは、コンポーネントの中で静的アレイを宣言することと類似しています。静的アレイの宣言とは異なり、内部初期化はメモリーに外部から公開されたポートに置き換えられます。メモリーは現在コンポーネントの内部にあるため、HLS コンパイラーは通常のメモリー最適化をすべて利用して、コンポーネントのアクセスパターン ( つまり、バンキング、結合など ) に最適化されたメモリー・アーキテクチャーを作成することができます。
HLSコンパーラーはオンチップ・メモリーブロックにスレーブメモリーを実装します。
コンポーネントは多数のメモリー・インターフェイスを有することができます。CSR スレーブ・インターフェイスとともにグループ化されたスレーブレジスター引数とは異なり、スレーブメモリーはコンポーネントで独自のスレーブ・インターフェイスを有します。スレーブメモリー・インターフェイスのデータバス幅はスレーブタイプの幅により決定します。メモリーへの内部アクセスが結合した場合、スレーブメモリー・インターフェイスのデータバス幅はスレーブタイプの幅の倍数になる可能性があります。
1.4.5. ポインター・エイリアシングの回避
restrict キーワードを可能な場合にポインター引数に挿入します。 restrict キーワードを含めることで、 インテル® HLS コンパイラーは競合しないリードおよびライト動作の間に不要なメモリーの依存関係の作成を回避します。
各反復があるアレイからデータを読み出し、データを同じ物理メモリー内の別のアレイに書き込むループを考慮します。これらのポインター引数に restrict キーワードがない場合、コンパイラーは 2 つのアレイ間で依存関係を仮定し、結果としてパイプライン並列化をより少なく抽出する必要があります。
1.5. 標準 C および C++ ライブラリー
math.h
合成されるコンポーネントからmath.h関数にアクセスするには、ソースコードにHLS/math.hファイルをインルードします。コンパイラーは、コンポーネントがハードウェア・バージョンの数学関数を呼び出すようにします。
サポートされるmath.h関数について詳しくは、この資料の HLSコンパイラーでサポートされる標準数学関数の章を参照してください。
stdio.h
合成したコンポーネント関数は一般的に FILE ポインターといった C および C++ 標準ライブラリー関数をサポートしません。
コンポーネントはヘッダーファイルHLS/stdio.hをインクルードすることでprintfをコールできます。このヘッダーはコンパイルの対象に応じてprintfの動作を変更します。
- x86-64 アーキテクチャー ( つまり、-march=x86-64) を対象とするコンパイルの場合、printfコールが通常通りに動作します。
- FPGA アーキテクチャー ( つまり、-march="<FPGA_family_or_part_number>") を対象とするコンパイルの場合、コンパイラーはprintfコールを削除します。
初めにコードに#include "HLS/stdio.h"行を含めずに ハードウェアを FPGA アーキテクチャーにコンパイルすると、次に類似したエラーメッセージが表示されます。
$ i++ -march="<FPGA_family_or_part_number>" -I${<path to i++ installation>}/include --component dut test.cpp Error: HLS gen_qsys FAILED. See ./dut.prj/dut.log for details.
fopenやprintfなどの C および C++ 標準ライブラリー関数は、すべての非コンポーネント関数で通常通りに使用できます。
iostream
合成したコンポーネント関数は一般的に C++ ストリーム・オブジェクト (coutなど ) のような C++ 標準ライブラリー関数をサポートしません。
コンポーネントはヘッダーファイルHLS/iostreamをインクルードすることでcoutまたはcerrをコールできます。このヘッダーはコンパイルの対象に応じてcoutとcerrの動作を変更します。
- x86-64 アーキテクチャー ( つまり、-march=x86-64) を対象とするコンパイルの場合、coutまたはcerrコールが通常通りに動作します。
- FPGA アーキテクチャー ( つまり、-march="<FPGA_family_or_part_number>") を対象とするコンパイルの場合、コンパイラーはcoutまたはcerrコールを削除します。
初めにコードに#include "HLS/iostream"行を含めずにcoutまたはcerrをコンポーネント関数で使用すると、ハードウェアを FPGA アーキテクチャーにコンパイルすると、次に類似したエラーメッセージが表示されます。
$ i++ -march="<FPGA_family_or_part_number>" run.cpp run.cpp:5: Compiler Error: Cannot synthesize std::cout used inside of a component. HLS Main Optimizer FAILED.
1.6. 静的変数
HLSコンパイラーは C および C++ と同一のセマンティックを有する関数スコープの静的変数をサポートしています。
関数スコープの静的変数はリセット時に指定された値に初期化されます。加えて、これらの変数への変更はコンポーネントの起動時に表示されるため、コンポーネント内の状態の保存に最適です。
静的変数の初期化のために、コンポーネントは余分なロジックを必要とし、そのロジックがアクティブな間はコンポーネントがリセット状態を終了するまで時間がかかる場合があります。
HLSコンパイラーは単一コンポーネントでのみアクセスされるファイルスコープの静的変数をサポートしています。HLSコンパイラーはこれらのファイルスコープの静的変数をそのコンポーネントにおける関数スコープの静的変数であるかのようにコンパイルします。
静的変数の初期化
典型的なプログラムとは異なり、コンポーネント内の静的変数がいつ初期化されるかを制御することができます。静的変数は、コンポーネントの電源投入時またはリセット時に初期化できます。
コンポーネントの電源投入時に静的変数を初期化することは、プログラムの実行開始後に静的変数の値を変更できない従来のプログラミング・モデルに類似しています。
コンポーネントがリセットされた際に静的変数を初期化すると、電源投入時を含めてコンポーネントがテストベンチから呼び出されるたびに、静的変数が初期化されます。しかしながら、このタイプの静的変数の初期化には余分なロジックが必要です。この余分なロジックは、スタートアップ・レイテンシーおよびコンポーネントに必要な FPGA エリアに影響を与えます。
デフォルト動作は、コンポーネントのリセット時に静的変数を初期化します。
- hls_init_on_reset
- 静的変数値はコンポーネントのリセット後に初期化されます。次の例で示すように、このキーワードを静的変数の宣言に追加します。
static char arr[128] hls_init_on_reset;
これは静的変数を初期化するためのデフォルトの動作です。この動作を取るために静的変数の宣言でhls_init_on_resetのキーワードを指定する必要はありません。
例えば、次の例の静的変数もコンポーネントのリセット時に初期化されます。static in arr[64];
- hls_init_on_powerup
- 静的変数は、電源投入時にのみ初期化されます。この初期化はメモリー初期化ファイル (.mif) を使用してメモリーを初期化し、これによりリソース使用率とコンポーネントのスタートアップ・レイテンシーを減らします。
-
次の例で示すように、このキーワードを静的変数の宣言に追加します。
static char arr[128] hls_init_on_powerup;
一部の静的変数は、静的変数の複雑さのためにこの初期化を利用できない場合があります。このような場合、コンパイラーはエラーを返します。
静的変数の初期化の説明について詳しくは、 <path to HLS compiler installation>/examples/tutorials/static_var_initにあるstatic_var_initデザインのチュートリアルをご覧ください。
コンポーネントのリセットについて詳しくは、インテル HLS コンパイラー・ユーザーガイドの「リセット動作」を参照してください。
1.7. ループ
ループのパイプライン化は、HLSコンパイラーがループの後続の反復をパイプライン並列処理方式で実行できるようにします。パイプライン並列処理実行とは、複数のループの反復が実行中の異なる時点で同時に実行することを意味します。また、パイプライン化ループは、生成されたハードウェアの使用を最大限にするのに役立ちます。
一部のケースではパイプライン化ができない場合があります。ループの新しい反復処理は、前の反復処理後 N サイクルまで開始されません。ループ反復処理が開始されるまで待機しなければならないサイクル数は、ループのイニシエーション・インターバル (II) と呼ばれます。一般的にイニシエーション・インターバの値は 1 が理想的です。II > 1の場合の通常のケースは、最適化レポートに示されているように、後続のループ反復間にループ伝搬依存性がある場合です。回路はループの新しい反復処理の開始前にこれらのループ伝搬依存性が解決されるのを待機する必要があります。可能であれば、コンパイラーが低い II 値を持つループのスケジュールを生成できるように、ループ伝搬依存性を削減します。
ネストされたループの場合、クリティカルな内側のループが作業の大部分を実行すると、外側のループのII > 1は重要なパフォーマンス・リミッターとはみなされません。一般的なパフォーマンス・リミッターの 1 つは、HLSコンパイラーが内側のループのトリップ数 ( 可変内部ループトリップ数など ) を静的に計算できない場合です。既知のトリップ数がない場合、コンパイラーは外側のループをパイプライン処理できません。
1.7.1. ループ展開
コード例 :
1 #pragma unroll <N> 2 for (int i = 0; i < M; ++i) { 3 // Some useful work 4 }
この例では、Nはアンロール係数、すなわち、HLSコンパイラーが生成するループのコピーの数をサポートしています。アンロール係数を指定しない場合、HLSコンパイラーはループを完全に展開します。最適化レポートで各ループのアンロールステータスを確認することができます。
1.7.2. ループ結合
#pragma loop_coalesce <loop_nesting_level>
<loop_nesting_level> パラメーターはオプションであり、コンパイラーに結合させたいネスト化ループレベルの数を指定する整数です。<loop_nesting_level> パラメーターを指定しない場合、コンパイラーはすべてのネスト化ループを結合しようとします。
for (A) for (B) for (C) for (D) for (E)
- ループ (A) はネスト化ループレベル 1
- ループ (B) はネスト化ループレベル 2
- ループ (C) はネスト化ループレベル 3
- ループ (D) はネスト化ループレベル 4
- ループ (E) はネスト化ループレベル 3
- #pragma loop_coalesce 1を指定する場合、コンパイラーはどのネスト化ループも結合しようとしない。
- #pragma loop_coalesce 2を指定する場合、コンパイラーはループ (A) と (B) を結合しようとする。
- #pragma loop_coalesce 3を指定する場合、コンパイラーはループ (A)、(B)、(C)、および (E) を結合しようとする。
- #pragma loop_coalesce 4を指定する場合、コンパイラーはループ (A) ~ (E) の全ループを結合しようとする。
例
次の簡単な例はコンパイラーが 2 つのループを 1 つのループに結合する方法を示しています。
#pragma loop_coalesce for(int i = 0; i < N; i++) for(int j = 0; j < M; j++) sum[i][j] += i+j;
int i = 0; int j = 0; while(i < N){ sum[i][j] += i+j; j++; if(j == M){ j=0; i++; } }
1.7.3. ループ・イニシエーション・インターバル (II)
反復インターバル、または II は、連続するループ反復を開始する間のクロックサイクル数です。II 値が高いほど、次のループ反復までの待機時間が長くなります。
コンポーネントのいくつかのループでは、コンパイラーが選択するよりもより高い II をiiプラグマで指定すると、スループットを損なうことなく componentの最大動作周波数 (fmax) を上げることができます。
- ループが コンポーネントのスループットにとって重大ではない場合
- ループの実行時間が含まれる可能性のある他のループと比較して短時間の場合
#pragma ii <desired_initiation_interval><desired_initiation_interval> パラメーターは必須であり、連続するループ・インターバルの間に待機するクロックサイクル数を指定する整数です。
例
コンポーネントに 2 つの異なるパイプライン可能なループがある場合、すなわち、ループ伝搬依存性を持つショートラニング初期化ループと処理の大半を実行するロングラニング・ループの場合を考慮します。この場合、コンパイラーは初期化ループがデザインの全体的なスループットに及ぼす影響がはるかに小さいことを認識しません。コンパイラーは可能であれば II の値が 1 の両方のループをパイプライン化しようとします。
初期化ループはループ伝搬依存性があるため、生成されたハードウェアにはフィードバック・パスがあります。このようなフィードバック・パスのある II を達成するには、いくつかのクロック周波数を犠牲にする能性があります。メインループのフィードバック・パスに応じて、残りのデザインがより高い周波数で動作する可能性があります。
初期化ループで#pragma ii 2プラグマを指定すると、このループで II を最適化するアグレッシブが少ないことがコンパイラーに通知されます。少ないアグレッシブの最適化は、コンパイラーがパスをパイプライン化して最大動作周波数 (fmax) を制限できるようにし、 コンポーネントデザイン全体でより高い fmaxが達成できます。
初期化ループは、新しい II で実行するのに長時間を要します。しかしながら、fmaxが高いため、ロングランニング・ループの実行時間が短くなると、初期化ループの実行時間の長さは増加します。
1.7.4. ivdep プラグマを使用したループ伝搬依存性の削除
ループ依存性に関する詳細は、safelen(N)クローズをivdepプラグマに追加することで取得できます。safelen(N)クローズはループ伝搬依存性のない連続ループ反復の最大数を指定します。例えば、#pragma ivdep safelen(32)はコンパイル時にループ伝搬依存性が導入される前に最大 32 回のループ反復があることをコンパイラーに示します。つまり、#pragma ivdepはこのループの反復間に暗黙的なメモリー依存性がないことを保証し、#pragma safelen(32)はこの反復に依存する可能性のある最も近い反復が 32 回の反復であることを保証します。
ループ内部の特定のメモリーアレイへのアクセスがループ伝搬依存性を引き起こさないように指定するには、コンポーネント・コードのループの前に#pragma ivdep array (array_name)行を追加します。ivdepプラグマで指定されたアレイは、ローカルまたはプライベートのメモリーアレイ、もしくはグローバル、ローカル、またはプライベートのメモリーストレージを指すポインター変数でなければなりません。指定されたアレイがポインターの場合、ivdepプラグマは指定されたポインターでエイリアスする可能性があるすべてのアレイにも適用されます。ivdepプラグマで指定されたアレイは、構造体のアレイまたはポインターメンバーでもあります。
使用ケース 1:
ループ内部のメモリーアレイへのすべてのアクセスがループ伝搬依存性を引き起こさない場合、ループの前に#pragma ivdepを追加します。
1 // no loop-carried dependencies for A and B array accesses 2 #pragma ivdep 3 for(int i = 0; i < N; i++) { 4 A[i] = A[i + N]; 5 B[i] = B[i + N]; 6 }
使用ケース 2:
#pragma ivdep array (array_name)はすべてのアレイアクセスに代わり、特定のメモリーアレイに指定できます。このプラグマはアレイ、ポインター、または構造体のポインターメンバーに適用されます。指定したアレイがポインターの場合、ivdepプラグマは指定したポインターでエイリアスする可能性のあるすべてのアレイに適用します。
1 // No loop-carried dependencies for A array accesses 2 // Compiler inserts hardware that reinforces dependency constraints for B 3 #pragma ivdep array(A) 4 for(int i = 0; i < N; i++) { 5 A[i] = A[i - X[i]]; 6 B[i] = B[i - Y[i]]; 7 } 8 9 // No loop-carried dependencies for array A inside struct 10 #pragma ivdep array(S.A) 11 for(int i = 0; i < N; i++) { 12 S.A[i] = S.A[i - X[i]]; 13 } 14 15 // No loop-carried dependencies for array A inside the struct pointed by S 16 #pragma ivdep array(S->X[2][3].A) 17 for(int i = 0; i < N; i++) { 18 S->X[2][3].A[i] = S.A[i - X[i]]; 19 } 20 21 // No loop-carried dependencies for A and B because ptr aliases 22 // with both arrays 23 int *ptr = select ? A : B; 24 #pragma ivdep array(ptr) 25 for(int i = 0; i < N; i++) { 26 A[i] = A[i - X[i]]; 27 B[i] = B[i - Y[i]]; 28 } 29 30 // No loop-carried dependencies for A because ptr only aliases with A 31 int *ptr = &A[10]; 32 #pragma ivdep array(ptr) 33 for(int i = 0; i < N; i++) { 34 A[i] = A[i - X[i]]; 35 B[i] = B[i - Y[i]]; 36 }
1.7.5. ループ並行処理の制御
ループで最大の並行処理を達成するには、ループが完全にパイプラインされないようにする基となるハードウェアの依存関係を解除するために、ローカルメモリーを複写する必要があります。これは、コンポーネント HLD レポート (report.html)の Details ペインのループ分析レポートで同時実行の最大数が N に制限されていることを示すメッセージとして、確認できます。この場合のローカルメモリーの重複は、ポート数の増加のために複製するメモリーと同一ではありません。
#pragma max_concurrency 1 for (int i = 0; i < N; i++) { int arr[M]; // Doing work on arr }
また、hls_max_concurrency(N)コンポーネント属性を使用して、コンポーネントの並行処理を制御することも可能です。hls_max_concurrency(N)コンポーネント属性について詳しくは、hls_max_concurrencyを使用した並行処理の制御を参照してください。
1.8. 任意高精度整数のサポート
AC データ型 | インテル・ヘッダーファイル | 説明 |
---|---|---|
ac_int | HLS/ac_int.h | 任意幅の整数サポート |
ac_fixed | HLS/ac_fixed.h | 任意精度の固定小数点サポート |
インテル® はHLSコンパイラーが以下の理由のためにハードウェアの生成に使用するヘッダーファイルの最適化バージョンを開発しました。
- Mentor Graphics の一部のヘッダーファイルは インテル® 高位合成 (HLS) コンパイラーと互換性がない。
- Mentor Graphics のヘッダーファイルを使用する場合、HLSコンパイラーは最適な品質の結果を得られない。
ac_intおよびac_fixedデータ型の使用による利点 :
- より小さいデータ型および回路のさまざまな動作でのエレメント処理が実現できる。
- データ型は、コンテナーサイズを 32 または 64 ビットに昇格せずに、十分なサイズのコンテナーでのさまざまな動作結果を返すための整数昇格の優れたサポートを提供する。
HLSコンパイラーのac_intおよび ac_fixedデータ型の現在の実装での制限事項 :
- 512 ビットの結果の生成に限定された乗算器
- 最大 64 ビットに制限された除算器
- cout出力ストリームはコンポーネントでサポートされるが、コンポーネントを FPGA アーキテクチャーにコンパイルする際には含まれないようにする必要がある。
1.8.1. コンポーネントのac_intデータ型の定義
ac_intデータ型について詳しくは、任意高精度整数のサポートを参照してください。
-
コンポーネントに次のようにac_int.hヘッダーファイルをインクルードします。
#include "HLS/hls.h" #include "HLS/ac_int.h"
-
ヘッダーファイルをインクルードした後、次のいずれかの方法でac_int変数を宣言します。
- テンプレートベースの宣言
- ac_int<N, true> var_name; //Signed N bit integer
- ac_int<N, false> var_name; //Unsigned N bit integer
- 63 ビットまでの組み込みtypedefine宣言
- intN var_name; //Signed N bit integer
- uintN var_name; //Unsigned N bit integer
- テンプレートベースの宣言
1.8.1.1. ac_int データ型での重要な使用情報
ac_intデータ型は整数昇格サポートしています。次の例を考察します。
// For a 14-bit addition, the result should be stored in a 15-bit container int15 s_adder(int14 a, int14 b) { return (a + b); }
この場合、加算演算は自動的に 15 ビットの結果を出力します。しかしながら、結果を適切なデータ型に格納するのはユーザーの責任となります。HLSコンパイラーは指定されたコンテナーのサイズに自動的に切り捨てまたは拡張します。
ac_intデータ型は C および Verilog を含め、他の言語とはビットシフトが異なります。デフォルトでは、シフト量が符号付きデータ型の場合、下のコード例にようにac_intは負のシフトを許容します。ハードウェアでは、この負のシフトは左シフトと右シフトの両方の実装をもたらします。
int14 shift_left(int14 a, int14 b) { return (a << b); }
シフトが常に一方向にあるとわかっている場合、効率的なシフト演算子を実装するには、次のようにシフト量を符号なしのデータ型として宣言します。
int14 efficient_left_only_shift(int14 a, uint14 b) { return (a << b); }
HLSコンパイラー・インストレーション・パッケージはチュートリアル・デザインのいくつかの例が含まれています。推奨される例については、これらのデザインを参照してください。
1.8.2. ac_intデータ型のデバッグ用ツール
これらのツールでコンポーネントにオーバーフローがあることを確認した後、コンポーネントでgdbデバッガーを使用してプログラムを再度実行し、オーバーフローが発生した場所をバックトレースします。
DEBUG_AC_INT_WARNING
DEBUG_AC_INT_WARNINGを使用して、コンポーネントの x86 エミュレーション中にac_intデータ型のランタイム・トラッキングを有効にします。このツールはオーバーヘッドを追跡するために追加のオーバーヘッドを使用し、検出されたオーバーフローごとに警告を出します。
DEBUG_AC_INT_WARNINGはコンポーネント・コード内のマクロとして使用するか、i++コマンドのオプションとして次のように指定することもできます。
- マクロ
-
#define DEBUG_AC_INT_WARNING
- コンパイラー・コマンドライン・オプション
-
-D DEBUG_AC_INT_WARNING
DEBUG_AC_INT_ERROR
DEBUG_AC_INT_ERROR を使用して、コンポーネントの x86 エミュレーション中にac_intデータ型のランタイム・トラッキングを有効にします。このツールはオーバーヘッドを追跡するために追加のオーバーヘッドを使用し、最初に検出されたオーバーフローのメッセージを出力して、エラーが発生したコンポーネントを終了します。
DEBUG_AC_INT_ERRORはコンポーネント・コード内のマクロとして使用するか、i++コマンドのオプションとして次のように指定することもできます。
- マクロ
-
#define DEBUG_AC_INT_ERROR
- コンパイラー・コマンドライン・オプション
-
-D DEBUG_AC_INT_ERROR
1.8.3. コンポーネント内のac_fixedデータ型の定義
ac_fixedデータ型について詳しくは、任意高精度整数のサポートを参照してください。
-
次の方法でコンポーネントにac_fixed.hヘッダーファイルをインクルードします。
#include "HLS/hls.h" #include "HLS/ac_fixed.h"
-
ヘッダーファイルをインクルードした後、次のようにac_fixed変数を宣言します。
- ac_fixed<N, I, true, Q, O> var_name; //Signed fixed-point number
-
ac_fixed<N,
I, false, Q, O>
var_name; //Unsigned fixed-point number
テンプレートの属性の位置は次のように定義されます。
- N
- ビット単位の固定小数点の合計の長さ
- I
- 固定小数点の整数値を表すために使用されるビット数
- Q
- 小数部を表すために、生成された精度 ( 小数点以下の桁数 ) が変数で使用可能なビット数を超える値を扱う方法を決定する量子化モード
量子化モードおよびその詳細については、 <path to i++ installation>/include/ref/ac_datatypes_ref.pdfとして入手可能なMentor Graphics Algorithmic C (AC) Datatypesの「2.1. Quantization and Overflow」を参照してください。
- O
- 生成された値が変数で使用可能なビット数よりも多いビットのハンドル方法を決定するオーバーフロー・モード
オーバーフロー・モードおよびその詳細については、 <path to i++ installation>/include/ref/ac_datatypes_ref.pdfで入手可能な Mentor Graphics Algorithmic C (AC) Datatypesの「2.1. Quantization and Overflow」を参照してください。
1.9. エリアの最小化およびオンチップ・メモリー・アーキテクチャーの制御
HLS 属性 | 説明 |
---|---|
hls_register | コンパイラーがレジスターに実装する必要があるローカル変数を指定します。 |
hls_memory | コンパイラーがエンベデッド・メモリーに実装する必要があるローカル変数を指定します。 |
hls_numbanks(n) | ローカル変数を実装しているメモリーが、n が 0 より大きい 2 のべき乗定数であるnバンクを有することを指定します。 |
hls_bankwidth(n) | ローカル変数を実装しているメモリーが、nが 0 より大きい 2 のべき乗定数であるnバイト幅のバンクを有することを指定します。 |
hls_singlepump | ローカル変数を実装しているメモリーがシングルポンピングする必要があることを指定します。 |
hls_doublepump | ローカル変数を実装しているメモリーがダブルポンピングする必要があることを指定します。 |
hls_numports_readonly_writeonly(m,n) | ローカル変数を実装しているメモリーに、mおよびnが 0 より大きい定数であるmリードポートおよびnライトポートを有することを指定します。 |
hls_simple_dual_port_memory | 次の属性を指定することと同等のコンフィグレーションを指定します。
|
hls_merge("label", "direction") | 2 つ以上の変数を同じメモリーシステムに実装するように強制します。 labelは任意の文字列です。マージするすべての変数に同じラベルを割り当てます。 メモリーを幅方向または深さ方向にそれぞれマージするかどうかを判断するために、directionをwidthまたはdepthのいずれかとして指定します。 |
hls_bankbits(b 0 , b 1 , ..., b n ) | バンク選択ビットを形成する{b
0
, b
1
, ..., b
n
} を使用して、2nバンク内を分割するようにメモリーシステムに強制します。 重要:
b
0
, b
1
, ..., b
n
は連続的であり、正の整数です。
bank_bits属性なしでnumbanks(n)属性を指定する場合、バンク選択ビットはデフォルトで最下位ビット ( つまり、0, 1, ..., log2(numbanks)-1) になります。 |
1.9.1. メモリー属性の使用例
オンチップ・メモリーブロックを節約するための統合メモリーのオーバーライド例
次のコード例は、次のメモリー属性を使用して結合メモリーをオーバーライドする方法を示しています。
- hls_bankwidth(n)
- hls_numbanks(n)
- hls_singlepump
- hls_numports_readonly_writeonly(m,n)
オリジナルコードは、64 ビット幅の 256 の深さ ( 256x64 ビット ) のメモリー、つまり、2 つのオンチップ・メモリーブロックを統合します。
component unsigned int mem_coalesce(unsigned int raddr, unsigned int waddr, unsigned int wdata){ unsigned int data[512]; data[2*waddr] = wdata; data[2*waddr + 1] = wdata + 1; unsigned int rdata = data[2*raddr] + data[2*raddr + 1]; return rdata; }
変更されたコードは、32 ビット幅の 512 の深さ ( 512×32 ビット ) で、ストール可能な調停を備えたシンプル・デュアルポート・オンチップ・メモリーブロックを実装しています。
component unsigned int mem_coalesce(unsigned int raddr, unsigned int waddr, unsigned int wdata){ //Attributes that stop memory coalescing hls_bankwidth(4) hls_numbanks(1) //Attributes that specify a simple dual port hls_singlepump hls_numports_readonly_writeonly(1,1) unsigned int data[512]; data[2*waddr] = wdata; data[2*waddr + 1] = wdata + 1; unsigned int rdata = data[2*raddr] + data[2*raddr + 1]; return rdata; }
オンチップ・メモリーブロックを節約するバンクメモリー・オーバーライドの例
次のコード例は、下のメモリー属性を使用してバンクメモリーをオーバーライドする方法を示しています。
- hls_bankwidth(n)
- hls_numbanks(n)
- hls_singlepump
- hls_doublepump
オリジナルコードは、シングルポンプ・オンチップ・メモリーブロックのバンクを 2 つ作成します。
component unsigned short mem_banked(unsigned short raddr, unsigned short waddr, unsigned short wdata){ unsigned short data[1024]; data[2*waddr] = wdata; data[2*waddr + 9] = wdata +1; unsigned short rdata = data[2*raddr] + data[2*raddr + 9]; return rdata; }
バンクメモリーの節約のために、data[1024] の宣言前に次の属性を追加することで、ダブルポンプ・オンチップ・バンクメモリーのバンクを 1 つ実装するオプションがあります。
hls_bankwidth(2) hls_numbanks(1)hls_doublepump unsigned short data[1024];
あるいは、次の属性をdata[1024] の宣言前に追加することでストール可能な調停のシングルポンプ・オンチップ・メモリーブロックのバンクを 1 つ実装することもできます。
hls_bankwidth(2) hls_numbanks(1)hls_singlepump unsigned short data[1024];
1.9.2. hls_merge 属性の使用例
深さに関する hls_merge 属性の実装
次のコンポーネントコードを考察します。
component int depth_manual(bool use_a, int raddr, int waddr, int wdata) { int a[128]; int b[128]; int rdata; // mutually exclusive write if (use_a) { a[waddr] = wdata; } else { b[waddr] = wdata; } // mutually exclusive read if (use_a) { rdata = a[raddr]; } else { rdata = b[raddr]; } return rdata; }
コードはローカルメモリーaとbをそれぞれ独自のロード / ストアー命令を有する 2 つのオンチップ・メモリーブロックとしてHLSコンパイラーに命令します。
ローカルメモリーaとbのロード / ストアー命令が相互に排他的なため、下のサンプルコードに示すようにアクセスをマージすることができ、これによりロード / ストアー命令の数が減り、オンチップ・メモリーブロックの数も半減します。
component int depth_manual(bool use_a, int raddr, int waddr, int wdata) { int a[128] hls_merge("mem","depth"); int b[128] hls_merge("mem","depth");; int rdata; // mutually exclusive write if (use_a) { a[waddr] = wdata; } else { b[waddr] = wdata; } // mutually exclusive read if (use_a) { rdata = a[raddr]; } else { rdata = b[raddr]; } return rdata; }
深さに関してローカルメモリーをマージするとメモリーアクセスの効率が低下する場合があります。深さに関するローカルメモリーをマージするかどうかを決定する前に、HLD レポート ( <result>.prj/reports/report.html) を参照し、予測されたロード / ストアー命令の数で予測されたメモリー構成を生成しているかを確認する必要があります。下の例では、各メモリーへのロード / ストアー命令は互いに排他的ではないため、HLSコンパイラーはローカルメモリーaとbへのアクセスをマージすべきではありません。
component int depth_manual(bool use_a, int raddr, int waddr, int wdata) { int a[128] hls_merge("mem","depth"); int b[128] hls_merge("mem","depth"); int rdata; // NOT mutually exclusive write a[waddr] = wdata; b[waddr] = wdata; // NOT mutually exclusive read rdata = a[raddr]; rdata += b[raddr]; return rdata; }
この場合、HLSコンパイラーはメモリーシステムを ダブルポンプし、すべてのアクセスに十分なポートを提供する可能性があります。それ以外の場合、アクセスはストールフリーのアクセスを防止するポートを共有する必要があります。
幅に関する hls_merge 属性の実装例
次のコンポーネント・コードを考察します。
component short width_manual (int raddr, int waddr, short wdata) { short a[256]; short b[256]; short rdata = 0; // Lock step write a[waddr] = wdata; b[waddr] = wdata; // Lock step read rdata += a[raddr]; rdata += b[raddr]; return rdata; }
この場合、HLSコンパイラーは、ロード / ストアー命令は同じアドレスへのアクセスであるため、ロード / ストアー命令をローカルメモリーaとbにマージすることができ、次のように統合されます。
component short width_manual (int raddr, int waddr, short wdata) { short a[256] hls_merge("mem","width"); short b[256] hls_merge("mem","width"); short rdata = 0; // Lock step write a[waddr] = wdata; b[waddr] = wdata; // Lock step read rdata += a[raddr]; rdata += b[raddr]; return rdata; }
1.9.3. hls_bankbits 属性での使用例
{b0, b1, ... ,bn} 引数はHLSコンパイラーがバンク選択ビットで使用すべきワードアドレス・ビットを参照します。hls_bankbits(b0, b1, ..., bn) 属性を指定することは、バンク数が 2^( バンクビット数 ) と同等であることを意味します。
hls_bankbits 属性の実装例
次のコンポーネント・コードを考察します。
component int bank_arb_consecutive_multidim (int raddr, int waddr, int wdata, int upperdim) { int a[2][4][128]; #pragma unroll for (int i = 0; i < 4; i++) { a[upperdim][i][(waddr & 0x7f)] = wdata + i; } int rdata = 0; #pragma unroll for (int i = 0; i < 4; i++) { rdata += a[upperdim][i][(raddr & 0x7f)]; } return rdata; }
下の図に示すように、このコード例は複数のロード / ストアー命令を生成します。ただし、命令数に対するポート数が不足しているため、ストール可能なアクセスと II の値は 66 になります。
hls_bankbits属性を指定することで、ロード / ストアー命令がローカルメモリーにアクセスする方法を制御できます。変更されたコード例と下の図に示すように、ローカルメモリーaにアクセスするたびに一定のバンク選択ビットを選択すると、ロード / ストアー命令の各ペアはメモリーバンクの 1 つに接続するためのみに必要になります。このアクセスパターンは II の値を 66 から 1 に大幅に減少させます。
component int bank_arb_consecutive_multidim (int raddr, int waddr, int wdata, int upperdim) { int a[2][4][128] hls_bankbits(8,7); #pragma unroll for (int i = 0; i < 4; i++) { a[upperdim][i][(waddr & 0x7f)] = wdata + i; } int rdata = 0; #pragma unroll for (int i = 0; i < 4; i++) { rdata += a[upperdim][i][(raddr & 0x7f)]; } return rdata; }
hls_bankbits属性でワードアドレス・ビットを指定する場合、バンク選択ビットの結果がローカルメモリーへのアクセスごとに一定であることを確認します。下の図に示すように、ローカルメモリーのアクセスパターンは、選択されたバンク選択ビットがアクセスごとに一定であるという保証がないようなものです。結果として、ロード / ストアー命令の各ペアは、すべてのローカルメモリー・バンクに接続する必要があり、ストール可能なアクセスとなります。
component int bank_arb_consecutive_multidim (int raddr, int waddr, int wdata, int upperdim){ int a[2][4][128] hls_bankbits(5,4); #pragma unroll for (int i = 0; i < 4; i++) { a[upperdim][i][(waddr & 0x7f)] = wdata + i; } int rdata = 0; #pragma unroll for (int i = 0; i < 4; i++) { rdata += a[upperdim][i][(raddr & 0x7f)]; } return rdata; }
1.10. 改訂履歴
日付 | バージョン | 変更内容 |
---|---|---|
2017 年 6 月 | 2017.06.23 |
|
2017 年 6 月 | 2017.06.09 |
|
2017 年 2 月 | 2017.02.03 |
|
2016 年 11 月 | 2016.11.30 |
|
2016 年 9 月 | 2016.09.12 | 初版 |
A. HLS コンパイラー・クイック・リファレンス
コマンドオプション | デフォルト値 | 説明 | 例 |
---|---|---|---|
-c | オブジェクト・ファイルの前処理、解析、生成。 | ||
--clock <clock target> | 240 MHz | 指定したクロック周波数または周期で RTL を最適化する。 |
i++ -march="Arria 10" test.cpp --clock 100MHz i++ -march="Arria 10" test.cpp --clock 10ns |
--component <component name> | RTL に合成するための関数名のコンマ区切りのリスト。 | ||
-D<macro>[=<val>] | 値としての <val> での <macro> を定義する。 | ||
--fpc | 可能時に中間丸めと変換を削除する。 | ||
--fp-relaxed | 浮動小数点演算動作の順序を緩和する。 | ||
-ghdl | シミュレーションでのすべての HDL 信号の完全なデバッグの可視化およびログ付けを有効にする。 | ||
-L<dir> | -i を検索できるディレクトリーのリストにディレクトリー <dir> を追加する。 | ||
-l<library> | リンクキングの際にライブラリー名 <library> を検索する。 | ||
-march=[x86-64 | "<FPGA_family>" | "<FPGA_part_number>" | x86-64 | エミュレーター・フロー (x86-64)、または指定された FPGA ファミリーもしくは FPGA パートナンバーのコードを生成する。 | |
--promote-integers | 余分な FPGA リソースを使用し g++ 整数昇格を模倣する。 | ||
--quartus-compile | Quartus® Primeから生成された HDL を実行する。 | ||
--simulator none | テストベンチなしでコンポーネントの RTL を生成する。 |
ヘッダーファイル | 説明 |
---|---|
#include "HLS/hls.h" | コンポーネントの識別と明示的なインターフェイスで必要である。 |
#include "HLS/math.h" | 動作システム用のmath.hからのすべての数学関数を含む。 |
#include "HLS/extendedmath.h" | math.hではない追加の数学関数を含む。 |
#include "HLS/ac_int.h" |
ac_intヘッダーファイルのインテル HLS バージョンであり、 最適化された任意のサイズの整数サポートを提供する。 |
#include "HLS/ac_fixed.h" |
ac_fixedヘッダーファイルのインテル HLS バージョンであり、 任意の長さの固定小数点サポートを提供する。 |
キーワード | デフォルト値 | 説明 | 例 |
---|---|---|---|
component | 関数がコンポーネントであることを示すために使用される。 |
component void foo() |
関数 | 説明 | 例 |
---|---|---|
ihc_hls_enqueue(/*ptr to return type*/, /*function arguments*/) | この関数は HLS コンポーネントの 1 つの呼び出しをエンキューする。戻り値は、戻り型へのポインターである最初の引数に格納される。コンポーネントはihc_hls_component_run_all()関数が呼び出されるまで実行されない。 |
component int foo(int val) { // function definition } component void bar (int val) { // function definition } int main() { // ……. int input = 0; int res; ihc_hls_enqueue(&res, &foo, input); ihc_hls_enqueue_noret(&bar, input); input = 1; ihc_hls_enqueue(&res, &foo, input); ihc_hls_enqueue_noret(&bar, input); ihc_hls_component_run_all(foo); ihc_hls_component_run_all(bar); } |
ihc_hls_enqueue_noret(/*function arguments*/) | この関数は HLS コンポーネントの 1 つの呼び出しをエンキューする。この機能は HLS コンポーネントの戻り値が void の場合に使用される。コンポーネントはihc_hls_component_run_all() 関数が呼び出されるまで実行されない。 | |
ihc_hls_component_run_all(/*function name*/) | この関数は HLSコンポーネントの名前を受け入れる。実行時、コンポーネントのエンキューされたすべての呼び出しは、コンポーネントが新しい呼び出しをできるだけ早く受け入れられるように、HDL シミュレーターのコンポーネント内にプッシュされる。 | |
int ihc_hls_sim_reset(void) | この関数は自動シミュレーション中にリセット信号をコンポーネントに送る。リセットが実行されると 1 を返し、それ以外の場合は 0 を返す。 |
属性 | デフォルト値 | 説明 |
---|---|---|
hls_register | アクセスパターンに基づいた値 | コンポーネント内の変数 / アレイを強制的にレジスターとして実装する。 |
hls_memory | アクセスパターンに基づいた値 | コンポーネント内の変数 / アレイを強制的にエンベデッド・メモリーとして実装する。 |
hls_singlepump | アクセスパターンに基づいた値 | ローカル変数を実装しているメモリーがシングルポンプする必要があることを指定する。 |
hls_doublepump | アクセスパターンに基づいた値 | ローカル変数を実装しているメモリーがダブルポンプする必要があることを指定する。 |
hls_numbanks(N) | アクセスパターンに基づいた値 | ローカル変数を実装しているメモリーが、Nが 0 より大きい 2 のべき乗の定数であるNバンクを有する必要があることを指定する。 |
hls_bankwidth(N) | アクセスパターンに基づいた値 | ローカル変数を実装しているメモリーが、Nが 0 より大きい 2 のべき乗の定数であるNバイト幅のバンクを有する必要があることを指定する。 |
hls_bankbits(b 0 , b 1 , ..., b n ) | バンク数に基づくアドレスの最下位ビット | {b
0
, b
1
, ..., b
n
} がバンク選択ビットを形成するように、メモリーシステムを強制的に 2nのバンクに分割するようにする。 重要:
b
0
, b
1
, ..., b
n
は連続した正の整数である必要がある。
|
hls_numports_readonly_writeonly(M, N) | アクセスパターンに基づいた値 | ローカル変数を実装しているメモリーが、MおよびNが 0 より大きい定数であるMリードポートとNライトポートを有することを指定する。 |
hls_simple_dual_port_memory | hls_singlepumpおよびhls_numports_readonly_writeonly(1,1)マクロの両方の存在により定義される構成を指定する。 | |
hls_merge("mem_name", "depth") | 2 つ以上のローカル変数を単一マージド・メモリーシステムとして深さ方向にコンポーネント・メモリー内に実装できることを可能にする。 | |
hls_merge("mem_name", "width") | 2 つ以上のローカル変数を単一マージド・メモリーシステムとして横方向にコンポーネント・メモリー内に実装できることを可能にする。 | |
hls_init_on_reset | 静的変数でのデフォルト動作の値 | この属性は、コンポーネント・リセット信号がアサートされると、コンポーネント内部の静的変数を強制的にリセットする。これはコンポーネント・メモリーへの追加のライトポートの実装を必要とし、コンポーネントのリセット時にパワーアップ・レイテンシーを増加できる。 |
hls_init_on_powerup | この属性は、FPGA がプログラムされている際に静的変数を実装するコンポーネント・メモリーを電源投入に設定するように設定する。コンポーネントがリセットの場合、コンポーネント・メモリーは静的初期化値にリセットが戻されない。 |
プラグマ | 説明 | 例 |
---|---|---|
#pragma ii <N> | これが適用されるループに <N> の値が 0 より大きい II の <N> を強制する。 |
#pragma ii 2 for (int i = 0; i < 8; i++) { // Loop body } |
#pragma ivdep safelen(<N>) array(<array_name>) | このループの反復間のメモリー依存をコンパイラーに無視するように通知する。アレイの名前を指定するオプションの引数を受け入れることができる。これを指定しない場合、すべてのコンポーネント・メモリー依存は無視される。safelenパラメーターはオプションであるが、推奨されている。ループ内のロード / ストアー間の依存距離を指定する。コンパイラーはこの情報を使用して依存関係に適切な注釈を付ける。safelenを含まないことが安全である唯一のケースは、依存距離が無限大 ( つまり、実際の依存関係がない ) 場合である。 |
#pragma ivdep safelen(2) for (int i = 0; i < 8; i++) { // Loop body } |
#pragma loop_coalesce <N> | コンパイラーはこのループ内にネストされたすべてのループを 1 つのループに結合しようと試みる。このプラグマは一緒に結合するループの数を示すオプションの <N> を受け入れる。 |
#pragma loop_coalesce for (int i = 0; i < 8; i++) { for (int j = 0; j < 8; j++) { // Loop body } } |
#pragma unroll <N> | このプラグマはループを完全に、または <N> 回 (<N> はオプションで正の整数値 ) で、アンロールする。 |
#pragma unroll for (int i = 0; i < 8; i++) { // Loop body } |
#pragma max_concurrency <N> | このプラグマはいつでも同時に実行できるループの反復の数を制限する。主にループのスループットを向上させるためにコンポーネント・メモリーが複製されている場合に役立つ ( ループ分析ペイン内のループの詳細ペインに記載されている )。これはコンポーネント・メモリーのスコープ ( 宣言またはアクセスパターンによる ) がこのループに制限されている場合にのみ発生する。このプラグマを追加すると、いくつかのスループットを犠牲にして消費するループのエリアを節約できる。 |
// Without this pragma, multiple copies // of the array "arr" #pragma max_concurrency 1 for (int i = 0; i < 8; i++) { int arr[1024]; // Loop body } |
コンポーネント属性 | 説明 | 例 |
---|---|---|
hls_max_concurrency(<N>) | コンポーネント・メモリーがインスタンス化されている場合、( つまり、静的変数ではない )、コンポーネント・メモリがーインスタンス化されている場合、( およびコンポーネント・メモリーのスコープがループだけでなくコンポーネント全体である場合 )、単一のコピーのみがインスタンス化される。これによりコンポーネントがパイプラインされ、複数の呼び出しが一度に実行される際にパフォーマンスを制限することができる。この属性はコンポーネントに追加でき、メモリーの複数のコピーが作成され、メモリー内の異なるスペースで異なる呼び出しが並列実行できるようになる。異なるコピーがすべて同じメモリーシステムにマップされることは、レプリケーションが深刻であることに注意する必要がある。 |
hls_max_concurrency(2) void foo(ihc::stream_in<int> &data_in, ihc::stream_out<int> &data_out) { int arr[N]; for (int i = 0; i < N; i++) { arr[i] = data_in.read(); } // Operate on the data and modify in place for (int i = 0; i < N; i++) { data_out.write(arr[i]); } } |
デフォルト・インターフェイス | 説明 |
---|---|
コンポーネント呼び出しと戻り値 | コンポーネント呼び出しインターフェイスは、start と busy コンデュイットから成るストリーミング・インターフェイスとして実装される。 コンポーネント戻り値インターフェイスも done と stall 信号を含むストリーミング・インターフェイスとして実装される。 |
スカラー引数 | スカラー引数はコンポーネント呼び出しインターフェイスに同期されるコンデュイットとして実装される。 |
ポインター引数 | ポインター引数はデフォルトのパラメーター化でのmm_masterインターフェイスとして実装される。 デフォルトでは、ベースアドレスはスカラー引数として扱われるため、コンポーネント呼び出しインターフェイスに同期されるコンデュイットとして実装される。 メモリーマップド・インターフェイスもコンポーネント上に公開される。 |
コンポーネント呼び出しインターフェイス引数 | 説明 | 例 |
---|---|---|
restrict | restrict キーワードを含めることで、可能な場合に インテル® HLS コンパイラーが非競合のリードおよびライト動作間の不要なメモリー依存関係の作成を回避できる。 |
component void foo (restrict int *ptr1, restrict int *ptr2); |
hls_avalon_streaming_component
これはデフォルトのコンポーネント呼び出しインターフェイスである。 |
この属性は関数コールとリターンストリームの両方のストリーミング・プロトコルに従う。コンポーネントは start 信号がアサートされて busy 信号がディアサートされると、不安定引数を消費する。コンポーネントは done 信号がアサートされると戻り値データを生成する。 トップレベルのモジュールポート : 関数コール—start、busy 関数リターン—done、stall |
hls_avalon_streaming_component void foo(/*component arguments*/) |
hls_avalon_slave_component | start、done、および returndata ( 可能な場合 ) 信号はコンポーネントのスレーブ・メモリー・マップにレジスターされる。詳しくは、CSR スレーブの項を参照。 トップレベルのモジュールポート : Avalon-MM スレーブ・インターフェイスおよび irq_done 信号 |
hls_avalon_slave_component void foo(/*component arguments*/) |
hls_always_run_component | Start 信号はコンポーネント内で 1 に結び付けられる。done 信号は出力されない。コンポーネントのデータパスが入力 / 出力用の明示的なストリームでのみ依存する場合にこのプロトコルを使用する。 注意 : IP 検証ではこのコンポーネント呼び出しプロトコルを使用するコンポーネントはサポートされていない。 トップレベルのモジュールポート : なし |
hls_always_run_component void foo(/*component arguments*/) |
コンポーネント引数マクロ | 説明 | 例 |
---|---|---|
hls_conduit_argument
これはスカラー引数のデフォルト・インターフェイスである。 |
コンパイラーはコンポーネントの呼び出し (start と busy) に同期する入力コンデュイットとして引数を実装する。 |
void foo( hls_conduit_argument int b) |
hls_avalon_slave_register_argument | コンパイラーは Avalon-MM スレーブ・インターフェイス上で読み書きできるレジスターとして引数を実装する。引数は、コンデュイット実装と同様にコンポーネントのパイプラインにリードされる。実装は、start および busy インターフェイスに同期する。 |
void foo( hls_avalon_slave_register_argument int b) |
hls_avalon_slave_memory_argument(N) | コンパイラーはオンチップ・メモリーブロックに引数を実装し、これは専用スレーブ・インターフェイス上で読み書きできる。生成されたメモリーは他のすべての内部コンポーネント・メモリー ( つまり、バンキング、結合など ) と同じアーキテクチャーの最適化を行う。 コンパイラーが静的結合最適化を実行すると、スレーブ・インターフェイスのデータ幅は結合された幅になる。この属性は、ポインター引数でのみ適用する。 コンポーネントのデータパスで行われたこの引数の値の変更はこのレジスターに反映されない。 |
component void foo( hls_avalon_slave_memory_argument(128) *a) |
hls_stable_argument | stable 引数は、ライブデータがコンポーネントにある間 ( つまり、パイプライン化関数呼び出しの間 ) は変更されない引数である。 コンポーネント実行中の stable 引数の変更は、未定義の動作を引き起こす。つまり、stable 引数の使用のたびに古い値または新しい値が使用される可能性があるが、一貫性の保証はない。同じ呼び出しでの同じ変数では複数の値が現れる場合がある。 stable 引数を使用すると、適切な場合にデザインの多くのレジスター数を節約できる場合がある。stable 引数はコンデュイット、mm_master インターフェイス、slave_registers で使用できる。 |
component int dut( hls_stable_argument int a, hls_stable_argument int b) { return a * b;} |
入力インターフェイス | デフォルト値 | 有効値 | 説明 | 例 |
---|---|---|---|---|
stream_in 宣言 |
void foo (ihc::stream_in<int> &a) { int x = a.read(); // Blocking read } void foo_nb (ihc::stream_in<int> &a) { bool success = false; int x = a.tryRead(&success); // Blocking read if (success) { // x is valid } } int main() { ihc::stream_in<int> a; ihc::stream_in<int> b; for (int i = 0; i < 10; i++) { a.write(i); b.write(i); } foo(&a); foo_nb(&b); } |
|||
ihc::stream_in<datatype> | コンポーネントへのストリーミング用の入力インターフェイスであり、テストベンチはこのバッファーをコンポーネントに送信する前に配置する必要がある。 | |||
ihc::buffer | 0 | 正の整数値 | ストリームに関連する入力データ上の FIFO バッファーのワード単位での容量。 このパラメーターは入力ストリーム上でのみ使用可能。 このパラメーターはvoid foo (ihc::stream_in<int, ihc::buffer<16 > &a); など、関数引数に追加される。 |
|
ihc::readylatency | 0 | 正の整数値 ( 0-8 の間 ) | リード信号がディアサートされてから入力ストリームが新しい入力を受け入れられなくなるまでのサイクル数。概念的には、このパラメーターはストリームと関連するデータの入力 FIFO バッファー上の almost ready レイテンシーとして確認することができる。 | |
ihc::bitsPerSymbol | データ型サイズ | データ型サイズを均等に分割する正の整数値 | データがデータバス上のシンボルにどのようにブレークされるかを記述する。データは常にリトル・エンディアンの順に中断される。 | |
ihc::usesPackets | false | trueまたはfalse | ストリーム・インターフェイス上の startofpacket と endofpacket 信号を公開する。これは、パケットベースの読み出し / 書き込みによりアクセス可能。 | |
ihc::usesValid | true | trueまたはfalse | 有効な信号がストリーム・インターフェイス上に存在するかどうかを制御する。falseの場合は、アップストリーム・ソースは ready がアサートされるサイクルごとに有効なデータを提供する必要がある。 これはストリームリード呼び出しをtryReadに変更し、successを常にtrueを保つこととと同じである。 trueに設定する場合は、bufferとreadyLatencyは 0 である必要がある。 |
|
stream_in 関数 API | ||||
T read() | コンポーネント内から使用されるブロッキング・リードコール。 | |||
T read(bool& sop, bool& eop) |
usesPackets<true>が設定されている場合にのみ有効である。 sideband 信号によるブロッキング・リード。 |
|||
T tryRead(bool &success) | コンポーネント内から使用されるノンブロッキング・リードコール。読み込みが有効であれば、success bool は true に設定される。 | |||
T tryRead(bool& success, bool& sop, bool& eop) |
usesPackets<true>が設定されている場合にのみ有効である。 sideband 信号によるノンブロッキング・リード。 |
|||
void write(T data) | コンポーネントに送信される FIFO を配置するためにテストベンチから使用されるブロッキング・ライトコール。 | |||
void write(T data, bool sop, bool eop) |
usesPackets<true>が設定されている場合にのみ有効である。 sideband 信号によるブロッキング・ライトコール。 |
出力インターフェイス | デフォルト値 | 有効値 | 説明 | 例 |
---|---|---|---|---|
Stream_out 宣言 |
void foo (ihc::stream_out<int> &a) { static int count = 0; a.write(count++); // Blocking write } void foo (stream_in<int> &a) { static int count = 0; bool success = a.tryWrite(count++); // Non-blocking write if (success) { // write was successful } } |
|||
ihc::stream_out<datatype> | コンポーネントからのストリーミング用の出力インターフェイス。テストベンチはコンポーネントが返されるとこのバッファーから読み出しが可能。 | |||
ihc::readylatency | 0 | 正の整数値 (0-8 の間 ) | リード信号がディアサートされてから入力ストリームが新しい入力を受け入れられなるまでのサイクル数。 概念的には、このパラメーターはストリームと関連するデータの入力 FIFO バッファー上の almost ready レイテンシーとして確認することができる。 |
|
ihc::bitsPerSymbol | データ型サイズ | データ型サイズを均等に分割する正の整数値 | データがデータバス上のシンボルにどのようにブレークされるかを記述する。データは常にリトル・エンディアンの順に中断される。 | |
ihc::usesPackets | false | trueまたはfalse | ストリーム・インターフェイス上の startofpacket と endofpacket 信号を公開する。これは、パケットベースの読み出し / 書き込みによりアクセス可能。 | |
ihc::usesReady | true | trueまたはfalse | ready 信号が存在するかどうかを制御する。trueの場合は、ダウンストリーム・シンクは valid がアサートされるサイクルごとにデータを受け入れる必要がある。 これはストリーム・リードコールをtryWriteに変更し、successを常にtrueを保つこととと同じである。 falseに設定する場合は、bufferとreadyLatencyは 0 である必要がある。 |
|
stream_out 関数呼び出し API | ||||
void write(T data) | コンポーネント内からのブロッキング・ライトコール。 | |||
void write(T data, bool sop, bool eop) |
usesPackets<true>が設定されている場合にのみ有効。 sideband 信号によるコンポーネントからのブロッキング・ライトコール。 |
|||
bool tryWrite(T data) | コンポーネント内からのノンブロッキング・ライトコール。書き込みが成功したかどうかの戻り値を表す。 | |||
bool tryWrite(T data, bool sop, bool eop) |
usesPackets<true>が設定されている場合にのみ有効。 コンポーネント内からのノンブロッキング・ライトコールし。書き込みが成功したかどうかの戻り値を表す。 |
|||
T read() | コンポーネントからデータを読み戻すためにテストベンチで使用されるブロッキング・リードコール。 | |||
T read(bool &sop, bool &eop) |
usesPackets<true>が設定されている場合にのみ有効。 sideband 信号によるコンポーネントからデータを読み戻すためにテストベンチで使用されるブロッキング・リードコール。 |
mm_master インターフェイス | 有効値 | デフォルト値 | Description | 例 |
---|---|---|---|---|
ihc::mm_master<datatype, /*template arguments*/ > | ポインター引数におけるデフォルト・インターフェイス | メモリーマスター・インターフェイスの引数 : 複数のテンプレート引数がサポートされている。テンプレートの引数は下記のとおりである。有効なハードウェア・コンフィグレーションを要求する限り、任意の組み合わせを使用できる。各コンフィグレーションのデフォルト値は、HLS リファレンス・ガイドに記載されている。 |
component int dut( ihc::mm_master<int, ihc::aspace<2>, ihc::latency<3>, ihc::awidth<10>, ihc::dwidth<32> > &a) |
|
ihc::dwidth<value> | 8、16、32、64、128、256、512、または 1024 | 64 | ビット単位でのメモリーマップド・データバスの幅 | |
ihc::awidth<value> | 範囲 1 – 64 の整数値 | 64 | ビット単位でのメモリーマップド・アドレスバスの幅 | |
ihc::aspace<value> | 0 より大きい整数値 | 1 | マスターに関連するインターフェイスのアドレススペース。同じアドレススペースのすべてのマスターは、コンポーネント内で 1 つのインターフェイスに調停される。したがって、これらのマスターはインターフェイスを記述する同じテンプレート・パラメーターを共有する必要がある。 | |
ihc::latency<value> | 正の整数値 | 1 | 外部メモリーが有効な読み出しデータを返す際に、リードコマンドがコンポーネントを終了してからの保証されたレイテンシー。このレイテンシーが変数であれば、0 に設定します。 | |
ihc::maxburst<value> | 範囲 1 - 1024 の整数値 | 1 | リード・トランザクションまたはライト・トランザクションに関連されるデータ転送の最大数。 固定レイテンシー・インターフェイスでは、この値は 1 に設定される必要がある。 詳しくはAvalon Interface Specificationsを参照。 |
|
ihc::align<value> | データ型のアラインメントより大きい整数値 | データ型のアラインメント | ベースポインター・アドレスのバイト・アラインメント。HLS コンパイラーはこの情報を使用して、このポインターへのロードとストアーで可能な結合の量を決定する。 データ型幅がマスターデータ幅以下の場合、この引数を少なくともマスター幅以上に設定する。 例えば、型charが 64 ビットのマスター幅に設定されている場合、各クロックサイクルで 8 文字の読み出しと書き込みが可能となるように、alignテンプレート引数は 8 バイトに設定する。重要: 呼び出し元は align 引数の設定値にデータを揃える必要があり、そうでない場合は機能障害が発生する可能性がある。
|
|
getInterfaceAtIndex(int index) | この関数は、mm_master オブジェクトへのインデックスに使用される。これは、アレイを反復処理してアレイの異なるインディケーター上のコンポーネントを呼び出す際に便利である。この機能はテストベンチでのみサポートされている。 |
int main() { // ……. for(int index = 0; index < N; index++) { dut(src_mm.getInterfaceAtIndex(index)); } // ……. } |
AC データ型 | インテル・ヘッダーファイル | 内容 |
---|---|---|
ac_int | HLS/ac_int.h | 任意の幅の整数サポート |
ac_fixed | HLS/ac_fixed.h | 任意精度の固定小数点サポート |
デバッグツール | 説明 |
---|---|
|
ac_intデータ型の x86 エミュレーション中にランタイムでのトラッキングを有効にする。 これは、オーバーフローを追跡する際に追加のオーバーヘッドを使用し、オーバーフローが検出されると警告を出す。 |
|
ac_intデータ型のオーバーフローのトラッキングを有効にする。 これは、オーバーフローの追跡で追加のオーバースレッドを使用し、オーバーフローが検出されるとランタイムでエラーを出す。 |
B. HLSコンパイラーでサポートされる標準の数学関数
#include "HLS/math.h"
#include "HLS/extendedmath.h"extendedmath.hヘッダーファイルはHLS/math.hヘッダーファイルを含んでいます。
HLSコンパイラーでサポートされる Math.h 関数
HLSコンパイラーはmath.hに存在する関数のサブセットをサポートしています。
各math.h関数を下にリストしています。「●」はHLSコンパイラーがサポートする関数を表し、「X」はサポートされない関数を表します。
三角関数 | HLSコンパイラーによるサポート | |
---|---|---|
倍精度浮動小数点関数 | cos | ● |
sin | ● | |
tan | ● | |
acos | ● | |
asin | ● | |
atan | ● | |
atan2 | ● | |
単精度浮動小数点関数 | cosf | ● |
sinf | ● | |
tanf | ● | |
acosf | ● | |
asinf | ● | |
atanf | ● | |
atan2f | ● |
双曲線関数 | HLSコンパイラーによるサポート |
---|---|
cosh | ● |
sinh | ● |
tanh | ● |
acosh (C++11) | X |
asinh (C++11) | X |
atanh (C++11) | X |
指数関数または対数関数 | HLSコンパイラーによるサポート |
---|---|
exp | ● |
frexp | ● |
ldexp | ● |
log | ● |
log10 | ● |
modf | ● |
exp2 (C++11) | ● |
expm1 (C++11) | X |
ilogb (C++11) | ● |
log1p (C++11) | X |
log2 (C++11) | ● |
logb (C++11) | ● |
scalbn (C++11) | X |
scalbln (C++11) | X |
べき関数 | HLSコンパイラーによるサポート |
---|---|
pow | ● |
sqrt | ● |
cbrt (C++11) | X |
hypot (C++11) | X |
エラー関数またはガンマ関数 | HLSコンパイラーによるサポート |
---|---|
erf (C++11) | X |
erfc (C++11) | X |
tgamma (C++11) | X |
lgamma (C++11) | X |
丸め関数と余り関数 | HLSコンパイラーによるサポート |
---|---|
ceil | ● |
floor | ● |
fmod | ● |
trunc (C++11) | ● |
round (C++11) | ● |
lround (C++11) | X |
llround (C++11) | X |
rint (C++11) | ● |
lrint (C++11) | X |
llrint (C++11) | X |
nearbyint (C++11) | X |
remainder (C++11) | X |
remquo (C++11) | X |
浮動小数点操作関数 | HLSコンパイラーによるサポート |
---|---|
copysign (C++11) | X |
nan (C++11) | X |
nextafter (C++11) | X |
nexttoward (C++11) | X |
最小、最大、または差分関数 | HLSコンパイラーによるサポート |
---|---|
fdim (C++11) | ● |
fmax (C++11) | ● |
fmin (C++11) | ● |
関数 | HLSコンパイラーによるサポート |
---|---|
fabs | ● |
abs | X |
fma (C++11) | X |
マクロ分類 | HLSコンパイラーによるサポート |
---|---|
fpclassify (C++11) | X |
isfinite (C++11) | ● |
isinf (C++11) | ● |
isnan (C++11) | ● |
isnormal (C++11) | X |
signbit (C++11) | X |
比較マクロ | HLSコンパイラーによるサポート |
---|---|
isgreater (C++11) | X |
isgreaterequal (C++11) | X |
isless (C++11) | X |
islessequal (C++11) | X |
islessgreater (C++11) | X |
isunordered (C++11) | X |
extendedmath.hヘッダーファイルで提供される数学関数
- sincos
- acospi
- asinpi
- atanpi
- cospi
- sinpi
- tanpi
- pown
- powr
- rsqrt
B.1. 改訂履歴
日付 | バージョン | 変更内容 |
---|---|---|
2017 年 6 月 | 2017.06.09 | extendedmath.hヘッダーファイルでサポートされる数学関数に関する情報を追加。 |
2017 年 2 月 | 2017.02.03 | メンテナンス・リリース |
2016 年 11 月 | 2016.11.30 | メンテナンス・リリース |
2016 年 9 月 | 2016.09.12 | 初版 |