HLS ストリーム オブ ブロック ライブラリ - 2023.2 日本語

Vitis 高位合成ユーザー ガイド (UG1399)

Document ID
UG1399
Release Date
2023-12-18
Version
2023.2 日本語
重要: コードで hls::stream_of_blocks オブジェクトを使用するには、次のようにヘッダー ファイル hls_streamofblocks.h を含めます。

hls::stream_of_blocks 型は、データフロー コンテキスト内のプロセス レベルのインターフェイスのデータのストリーミング ブロックをサポートするユーザー同期ストリームを提供します。各ブロックは配列または多次元配列です。ストリーム オブ ブロックの目的は、データフロー領域内のプロセスのペア間の配列ベースの通信を置き換えることにあります。GitHub で公開されている aggregation_of_m_axi_ports の例を参照してください。

現在のところ、AMD Vitis™ HLS は、プロデューサー プロセスで書き込まれてコンシューマー プロセスで読み出される配列をピンポン バッファー (PIPO) にマップすることで、データフロー領域にインプリメントしています。PIPO バッファーのバッファー交換は C++ でのプロデューサー関数の結果が戻った時とコンシューマー関数を呼び出した時に発生します。

これにより、連続する C++ 実行セマンティクスに完全に準拠した同時通信セマンティックになりますが、次のコード例に示すように、プロデューサーが終了するまでコンシューマーが開始できないということでもあります。

void producer (int b[M][N], ...) {
  for (int i = 0; i < M; i++)
    for (int j = 0; j < N; j++)
      b[i][f(j)] = ...;
}
  
void consumer(int b[M][N], ...) {
   for (int i = 0; i < M; i++)
     for (int j = 0; j < N; j++)
       ... = b[i][g(j)] ...;;
}
  
void top(...) {
#pragma HLS dataflow
  int b[M][N];
#pragma HLS stream off variable=b
  
  producer(b, ...);
  consumer(b, ...);
}

これにより、プロデューサーが小さなブロックでコンシューマー用のデータを生成する場合、たとえばネストされたループ内にバッファー出力の 1 行を書き込む場合などに、スループットが不必要に制限されてしまったり、リソースを増加させたりすることがあります。また、上の例のように、ネストされたループ内のバッファー入力の 1 行を読み出すことで、コンシューマーは小さなブロックのデータを使用します。この例では、内部ループ内の非シーケンシャル バッファーの列アクセスがあるので、単に b 配列をストリーミングすることはできません。ただし、外部ループの行アクセスはシーケンシャルであるため、各ブロックがサイズ N の 1 次元配列である hls::stream_of_blocks 通信がサポートされます。

hls::stream_of_blocks 機能の主な目的は、PIPO のような機能を提供することですが、ユーザー管理による明示的な同期、アクセス、および優れたコーディング スタイルも提供されています。ストリーム オブ ブロックを使用すると、上記の例を最適化する方法であったように、プロデューサーとコンシューマーを含むループでデータフローを使用しないようにできます。ただし、この場合、プロデューサーとコンシューマーを含むデータフロー ループを使用するには、次の例に示すように、PIPO バッファー (2xN) を使用する必要があります。

void producer (int b[N], ...) {
  for (int j = 0; j < N; j++)
    b[f(j)] = ...;
}
  
void consumer(int b[N], ...) {
   for (int j = 0; j < N; j++)
     ... = b[g(j)];
}
  
void top(...) {
// The loop below is very constrained in terms of how it must be written
  for (int i = 0; i < M; i++) {
#pragma HLS dataflow
    int b[N];
#pragma HLS stream off variable=b
  
    producer(b, ...); // writes b
    consumer(b, ...); // reads b
  }
}

この構造には、たとえば、ループ構造に多くの制約が必要であったり (0 から始まって、定数または関数引数と比較し、1 ずつ増加) といったような Vitis HLS の制限がいくつかあるので、上記のループ内のデータフロー コードもお勧めしません。