次の図に、AccLoad
、AccMul
、AccStore
の 3 つの PE を持つシングルパス パイプラインの例を示します。PE AccLoad
および AccStore
は、M_AXI チャネルを介してグローバル メモリに格納されたデータにアクセスします。アクセラレータ クラス ヘッダーは、inputData
および outputData
ポートを DDR[0] に接続されています。この場合、 ZERO_COPY
コードが使用されて、これらの PE がグローバル メモリに直接アクセスされています。
次は、図のコード例です。
typedef vpp::stream<DT> STREAM;
class Acc : public VPP_ACC<Acc, NCU>
{
ZERO_COPY(inputData);
ZERO_COPY(outputData);
SYS_PORT(inputData, DDR[0]);
SYS_PORT(outputData, DDR[0]);
public:
static void compute(DT* inputData, DT* outputData);
static void AccLoad(DT* inputData, STREAM& aStr,
STREAM& bStr, STREAM& iStr);
static void AccMul(STREAM& aStr, STREAM& bStr,
STREAM& cStr);
static void AccStore(STREAM& iStr, STREAM& cStr,
DT* outputData);
}
void Acc::compute(DT* inputData, DT* outputData)
{
static STREAM aStr, bStr, cStr, iStr;
AccLoad (inputData, aStr, bStr, iStr);
AccMul (aStr, bStr, cStr);
AccStore(iStr, cStr, outputData);
}
void Acc::AccMul(STREAM& aStr, STREAM& bStr, STREAM& cStr)
{
for (int i = 0 ; i < N_WORDS ; i ++) {
int res = aStr.read() * bStr().read();
cStr.write(res);
}
}
compute()
関数本体は、ハードウェア パイプラインを表します。PE に対応する 3 つの関数呼び出しがあり、4 つのローカル ストリーム変数が宣言されています。 -
AccLoad
はinputData
を読み込んで、3 つのストリームに書き出します。 -
AccMul
は入力ストリームaStr
およびbStr
内の決まった数のワードを処理して、cStr
に結果を書き出します。 -
AccStore
関数は、iStr
およびcStr
の入力データをさらに処理し、DDR[0] ポートに接続されたoutputData
に結果を書き出します。
このシステムの PE は同期で実行され、データがパイプラインで流れるように実行されます。compute()
の呼び出しはすべて、inputData
をロードして、新しいトランザクションのためにすべての PE をトリガーします。compute()
を呼び出すたびに、すべての PE が 1 回だけ実行 (開始と停止) を完了する必要があります。この例は、3 段階でパイプライン、またはシングルパスでチェーン接続された PE です。したがって、簡単な C++ コーディング スタイルを使用して、ユーザーがハードウェア パイプラインを作成できます。
VPP_ACC
クラスを使用すると、NCU パラメーターを使用して、このようなパイプラインを複製できます。NCU が複数の場合、ハードウェアには複製されたパイプラインがいくつも含まれます。compute()
への呼び出しは、次に使用可能なパイプライン スロットに自動的にロードされます。したがって、アプリケーション層はシンプルで管理しやすいまま、ハードウェア内の複数のパイプラインを使用してデータの実行が自動化されます。