タスクおよびデータフロー - 2023.2 日本語

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

Document ID
UG1399
Release Date
2023-12-18
Version
2023.2 日本語

hls::task は、データフロー領域内のタスクの定義もサポートします。データフロー領域では、デザイン階層の上位から M_AXI、スカラー値、または PIPO 引数にマップされた外部配列にアクセスするプロセスを定義できます。このため、#pragma HLS dataflow 文で特定され、ap_ctrl_chain を介して同期されたデータフロー プロセスが必要です。このプロセスでは、任意の非ストリーム型 C++ データ構造からデータを読み出し、hls::stream または hls::stream_of_blocks チャンネルとして出力して hls::tasks に接続します。その後、タスクは、ほかのデータフロー プロセスによって読み出され、M_AXI、スカラー、または PIPO の引数に書き込まれるストリームを出力できます。タスクは、入力ストリームを生成するプロセスまたは領域の後、出力ストリームを消費するプロセスまたは領域の前に宣言する必要があります。

重要: hls::task オブジェクトでは、M_AXI、スカラー、PIPO 引数を読み出し/書き込みできないため、次の例に示すように、データフロー プロセスでこれらのインターフェイスを読み出し/書き込み、ストリーム チャネルを hls::tasks に対して読み出し/書き込む必要があります。

次の例に、タスクおよびデータフロー プロセスをともに示します。最上位関数 (top-func) は、シーケンシャル関数 write_out()read_in()、および hls::task オブジェクトと hls::stream チャネルを定義するデータフロー領域です。

#include "hls_task.h"

// This is an I/O dataflow process
void write_out(int* out, int n, hls::stream<int> &s2) {
  for (int i=0; i<n; i++)
    out[i] = s2.read();
}
// This is an I/O dataflow process
void read_in(int* in, int n, hls::stream<int> &s1) {
  for (int i=0; i<n; i++)
    s1.write(in[i]);
}
// This is an hls::task body
void func1(hls::stream<int> &s1, hls::stream<int> &s3) {
  // No while(1) needed! This will be a task
  s3.write(... + s1.read());
}
// This is an hls::task body
void func2(hls::stream<int> &s3, hls::stream<int> &s2) {
  // No while(1) needed! This will be a task
  s2.write(... * s3.read());
}
// This could legally be at the top of the design hierarchy
void top-func(int *in, int *out, int n) {
#pragma HLS dataflow
  hls_thread_local hls::stream<int> sk3;
  hls_thread_local hls::stream<int> sk1;
  hls_thread_local hls::stream<int> sk2;
 
  read_in(in, n, sk1);                              // can access stream, scalar or array; calling order matters
  hls_thread_local hls::task t2(func2, sk3, sk2);   // can access only stream; instance order does not matter
  hls_thread_local hls::task t1(func1, sk1, sk3);   // can access only stream; instance order does not matter
  write_out(out, n, sk2);                           // can access stream, scalar or array; calling order matters
}

#pragma HLS DATAFLOW は 2 つのシーケンシャル関数に必要ですが、hls::task オブジェクトには不要です。内部的には、Vitis HLS で、通常のデータフロー プロセスおよび hls::task プロセスの両方を含め、top-func が自動的に次の 2 つのデータフロー領域に分割されます。

  1. ap_ctrl_chain を使用するデータフロー領域: read_in() および write_out() といった通常のデータフロー プロセスを C++ コードに登場する順番で含み、また次の ap_ctrl_none 領域への呼び出しを含む。
  2. ap_ctrl_none を使用する 2 つ目のデータフロー領域: タスクおよびチャネルを含む。

この結果、Vitis HLS GUI のデータフロー ビューでは、2 つのレベルの階層が表示されます。