デザインに複数のループがある場合、デフォルトではこれらがオーバーラップせずに順に実行されます。このセクションでは、シーケンシャル ループのデータフロー最適化の概念について説明します。次のようなコードがあるとします。
void adder(unsigned int *in, unsigned int *out, int inc, int size) {
unsigned int in_internal[MAX_SIZE];
unsigned int out_internal[MAX_SIZE];
mem_rd: for (int i = 0 ; i < size ; i++){
#pragma HLS PIPELINE
// Reading from the input vector "in" and saving to internal variable
in_internal[i] = in[i];
}
compute: for (int i=0; i<size; i++) {
#pragma HLS PIPELINE
out_internal[i] = in_internal[i] + inc;
}
mem_wr: for(int i=0; i<size; i++) {
#pragma HLS PIPELINE
out[i] = out_internal[i];
}
}
上記の例は、mem_rd
、compute
、および mem_wr
の 3 つのシーケンシャル ループを示しています。
-
mem_rd
ループはメモリ インターフェイスから入力ベクター データを読み出し、内部ストレージに格納します。 -
compute
ループは、内部ストレージからデータを読み出してインクリメント演算を実行し、結果を別の内部ストレージに保存します。 -
mem_wr
ループは、内部ストレージからデータを読み出してメモリに書き込みます。
このコード例ではメモリの入力/出力インターフェイスに対する読み出しと書き込みに 2 つの個別のループを使用してバースト読み出し/書き込みを推論しています。
デフォルトでは、これらのループはオーバーラップせずに順に実行されます。mem_rd
ループが入力データをすべて読み出すまで、compute
ループの処理は開始しません。同様に、compute
ループがデータを処理し終わってから mem_wr
ループがデータの書き込みを開始します。ただし、これらのループの処理をオーバーラップさせて、mem_rd
(または compute
) ループがデータを処理し終えるまで待たずに、compute
(または mem_wr
) ループが処理を実行するのに十分なデータが使用可能になったらすぐに開始されるようにできます。
ループの実行は、データフロー最適化に示すように、データフロー最適化を使用してオーバーラップさせることができます。