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 つのデータフロー領域に分割されます。
-
ap_ctrl_chain
を使用するデータフロー領域:read_in()
およびwrite_out()
といった通常のデータフロー プロセスを C++ コードに登場する順番で含み、また次のap_ctrl_none
領域への呼び出しを含む。 -
ap_ctrl_none
を使用する 2 つ目のデータフロー領域: タスクおよびチャネルを含む。
この結果、Vitis HLS GUI のデータフロー ビューでは、2 つのレベルの階層が表示されます。