ウィンドウおよびストリーミング データ API

データフロー グラフ カーネルは、長さ無制限の型付き値のシーケンスであるデータ ストリームを処理します。これらのデータ ストリームは個別のブロックに分割でき、これらのブロックはカーネルによって処理されます。カーネルはデータの入力ブロックを使用し、データの出力ブロックを生成します。カーネルは、サンプルごとにデータ ストリームにアクセスすることもできます。この章では、これらの 2 つの場合のデータ アクセス API について説明します。

注記: この章で説明するデータ転送 API は、ベクター/スカラー、符号付き/符号なしの両方のデータに適用されます。ただし、AI エンジン アーキテクチャは、ベクター算術演算については 8 ビット符号なし整数データ型 v16uint8, v32uint8, v64uint8, v128uint8 のみをサポートします。一方、スカラー算術演算については、すべての標準 C 符号なし整数データ型 unsigned char(uint8), unsigned short(uint16), unsigned int(uint32), unsigned long long(uint64) をサポートします。

データ アクセスのメカニズム

ウィンドウ ベースのアクセス

カーネルの入力データ ブロック ビューは、入力ウィンドウと呼ばれます。入力ウィンドウは、タイプ (そのウィンドウ内に格納されるデータ型の定義) によって定義されます。この例は、実数部と虚数部がいずれも 16 ビット幅の複素整数を格納する入力ウィンドウの宣言を示しています。

input_window_cint16 myFirstWindow;

カーネルの出力データ ブロック ビューは、出力ウィンドウと呼ばれます。これらのウィンドウもタイプによって定義されます。この例は、32 ビット整数を格納する出力ウィンドウの宣言を示しています。

output_window_int32 myOtherWindow;

これらのウィンドウ データ構造は、AI エンジン コンパイラによってデータフロー グラフの接続から自動的に推論され、グラフ制御を実装するラッパー コード内で自動的に宣言されます。カーネル関数は、カーネル関数に引数として渡されるウィンドウ データ構造を指すポインターを処理します。データフロー グラフまたはカーネル プログラム内でこれらのウィンドウ データ構造を宣言する必要はありません。

同期ウィンドウ アクセス

カーネルは、入力ウィンドウからデータを読み出し、出力ウィンドウにデータを書き込みます。デフォルトでは、データの入力ウィンドウを待機するのに必要な同期または空の出力ウィンドウを準備するのに必要な同期は、カーネルに入る前に実行されます。カーネルの開始後は、データの個々の要素の読み出しまたは書き込みのためのカーネル内での同期は必要はありません。

ウィンドウのサイズ (バイト単位) は、次に示すように、プロデューサー ポートとコンシューマー ポート間の接続と共に宣言します (詳細は 接続 を参照)。これにより、ポート in とカーネルの最初の入力ポートの間に 128 バイトのウィンドウ接続が確立されます。

connect< window<128> > net0 (in, first.in[0]);

オプションの 2 番目のテンプレート パラメーターは、次に示すように、1 つのデータ ブロックから次のデータ ブロックへのオーバーラップ (マージンとも呼ばれる) をバイト単位で指定します。マージン パラメーターを指定した場合、割り当てられるメモリはウィンドウ サイズとマージン サイズの合計になります。

connect< window<128, 32> net1 (in, first.in[0]);

これらのウィンドウは、順次アクセスされるよう設計されています。カーネル プログラミングはウィンドウのタイプを読み出し、最初の位置から開始します。そのため、読み出しまたは書き込みの際に書き込み位置を前または後ろに移動させることができる現在位置を使用するモデルが便利です。カーネルの開始時に、現在位置は常に適切な位置になります。たとえば、フィルター用の入力ウィンドウの現在位置は、遅延ラインに復元される最初のサンプルになります。入力されるデータ サンプルのオーバーラップを必要とするフィルターの場合、現在位置が古いサンプルになることがあります。この場合、上記のオーバーラップまたはマージンを使用して接続を宣言する必要があります。同様に、出力ウィンドウの現在位置は、次のブロックが古いサンプルの重複を必要とするかどうかにかかわらず、次のブロックに送信される最初のサンプルになります。この現在位置はカーネルで自由に操作でき、カーネルの完了時にこの位置がブロックの最後になる必要はありません。ウィンドウ データ型は循環バッファーとしてインプリメントされます。

非同期ウィンドウ アクセス

カーネルを呼び出すたびに 1 つのウィンドウ分のデータを消費するわけではない場合や、カーネルを呼び出すたびに 1 つのウィンドウ分のデータを生成するわけではない場合、次に示すように、カーネル ポートが async になるように宣言することにより、バッファーの同期を制御できます。

 connect< window<128, 32> net1 (in, async(first.in[0])); 

この宣言は、カーネルの入口でウィンドウ バッファーの同期を省略するようにコンパイラに指示します。次に示すように、読み出し/書き込み API を使用してウィンドウにアクセスする前に、カーネル コード内 に示されるウィンドウ同期 API を使用する必要があります。

void super_kernel(input_window_int32 * data, output_window_int32 * result) {
  ...
  window_acquire(data);     // acquire input window unconditionally inside the kernel
  if (<somecondition>) {
    window_acquire(result); // acquire output window conditionally 
  }
  ...                       // do some computation with "data" and "result"
  window_release(data);     // release input window inside the kernel
  if (<somecondition>) {  
    window_release(result); // release output window conditionally
  }
  ...
};

window_acquire API は、適切な同期と初期化を実行し、ウィンドウ オブジェクトを読み出しまたは書き込みに利用できるようにします。この API は、ウィンドウが複数の AI エンジン プロセッサ間で共有されており、ダブル バッファリングできる場合でも、内部で取得される適切なバッファー ポインターおよびロックを追跡します。この API は、動的制御下で無条件または条件付きで呼び出すことができ、ブロッキング動作になる可能性があります。この API に対応する window_release API が少し後に (おそらく次のカーネル呼び出し中に) 実行され、そのウィンドウ オブジェクトに関連するロックが解放されるようにするのは、ユーザーの役割です。同期が適切でない場合、コード内でデッドロックが発生することがあります。

ストリーム ベースのアクセス

ストリーム ベースのアクセス モデルでは、カーネルは型付きデータの入力ストリームまたは出力ストリームを引数として受け取ります。これらのストリームへの各アクセスは同期されます。すなわち、ストリーム内でデータが利用可能でない場合は読み出しはストールし、ストリームが新しいデータを受け入れることができない場合は書き込みはストールします。

AI エンジンは、id=0 または 1 の 2 つの 32 ビット入力ストリーム ポートをサポートし、id=0 または 1 の 2 つの 32 ビット出力ストリーム ポートをサポートします。この ID はストリーム オブジェクト コンストラクターに引数として与えられます。AI エンジン コンパイラは、入力および出力ストリーム ポートの ID をカーネルの引数リスト内で左から右に自動的に割り当てます。パケット交換ストリームの場合を除いて、同じ AI エンジンにマップされる複数のカーネルがストリーム ポートを共有することはできません (明示的パケット スイッチング 参照)。

1 つの AI エンジンのアキュムレータ レジスタと物理的に隣接するコアの間には、カスケードと呼ばれる直接ストリーム通信チャネルがあります。カスケード ストリームは、AI エンジン アレイ内で AI エンジン プロセッサからプロセッサへ蛇行して接続されます。

ストリーム データ構造は、AI エンジン コンパイラによってデータフロー グラフの接続から自動的に推論され、グラフ制御を実装するラッパー コード内で自動的に宣言されます。カーネル関数は、カーネル関数に引数として渡されるストリーム データ構造を指すポインターを処理します。データフロー グラフまたはカーネル プログラム内でこれらのストリーム データ構造を宣言する必要はありません。

カーネルのウィンドウ動作

ウィンドウ データ型

表 1. サポートしているウィンドウ データ型
入力ウィンドウ型 出力ウィンドウ型
input_window_int8 output_window_int8
input_window_int16 output_window_int16
input_window_int32 output_window_int32
input_window_int64 output_window_int64
input_window_uint8 output_window_uint8
input_window_uint16 output_window_uint16
input_window_uint32 output_window_uint32
input_window_uint64 output_window_uint64
input_window_cint16 output_window_cint16
input_window_cint32 output_window_cint32
input_window_float output_window_float
input_window_cfloat output_window_cfloat

現在の読み出し/書き込み位置の前方移動

次の説明では、<input_window_type> は許容される入力ウィンドウ データ型を表します。同様に、<output_window_type> は許容される出力ウィンドウ データ型を表します。

現在の読み出し/書き込み位置を、基礎をなすウィンドウ データ型のカウントだけインクリメントする (前にずらす) には、次のコードを使用します。

void window_incr(<input_window_type> *w, int count);
void window_incr(<output_window_type> *w, int count);

現在の読み出し/書き込み位置を、基礎をなすウィンドウ データ型のカウントの 4 倍だけインクリメントするには、次のコードを使用します。

void window_incr_v4(<input_window_type> *w, int count);
void window_incr_v4(<output_window_type> *w, int count);

現在の読み出し/書き込み位置を、基礎をなすウィンドウ データ型のカウントの 8 倍だけインクリメントするには、次のコードを使用します。

void window_incr_v8(<input_window_type> *w, int count);
void window_incr_v8(<output_window_type> *w, int count);

現在の読み出し/書き込み位置を、基礎をなすウィンドウ データ型のカウントの 16 倍だけインクリメントするには、次のコードを使用します。

void window_incr_v16(<input_window_type> *w, int count);
void window_incr_v16(<output_window_type> *w, int count);

現在の読み出し/書き込み位置を、基礎をなすウィンドウ データ型のカウントの 32 倍だけインクリメントするには、次のコードを使用します。

void window_incr_v32(<input_window_type> *w, int count);
void window_incr_v32(<output_window_type> *w, int count);

現在の読み出し/書き込み位置を、基礎をなすウィンドウ データ型のカウントの 64 倍だけインクリメントするには、次のコードを使用します。

void window_incr_v64(<input_window_type> *w, int count);
void window_incr_v64(<output_window_type> *w, int count);

現在の読み出し/書き込み位置の後方移動

次の説明では、<input_window_type> は許容される入力ウィンドウ データ型を表します。同様に、<output_window_type> は許容される出力ウィンドウ データ型を表します。

現在の読み出し/書き込み位置を、基礎をなすウィンドウ データ型のカウントだけデクリメントする (後ろにずらず) には、次のコードを使用します。

void window_decr(<input_window_type> *w, int count);
void window_decr(<output_window_type> *w, int count);

現在の読み出し/書き込み位置を、基礎をなすウィンドウ データ型のカウントの 4 倍だけデクリメントするには、次のコードを使用します。

void window_decr_v4(<input_window_type> *w, int count);
void window_decr_v4(<output_window_type> *w, int count);

現在の読み出し/書き込み位置を、基礎をなすウィンドウ データ型のカウントの 8 倍だけデクリメントするには、次のコードを使用します。

void window_decr_v8(<input_window_type> *w, int count);
void window_decr_v8(<output_window_type> *w, int count);

現在の読み出し/書き込み位置を、基礎をなすウィンドウ データ型のカウントの 16 倍だけデクリメントするには、次のコードを使用します。

void window_decr_v16(<input_window_type> *w, int count);
void window_decr_v16(<output_window_type> *w, int count);

現在の読み出し/書き込み位置を、基礎をなすウィンドウ データ型のカウントの 32 倍だけデクリメントするには、次のコードを使用します。

void window_decr_v32(<input_window_type> *w, int count);
void window_decr_v32(<output_window_type> *w, int count);

現在の読み出し/書き込み位置を、基礎をなすウィンドウ データ型のカウントの 64 倍だけデクリメントするには、次のコードを使用します。

void window_decr_v64(<input_window_type> *w, int count);
void window_decr_v64(<output_window_type> *w, int count);

入力ウィンドウからのデータの読み出し

次のコードは、スカラー型の値を同じタイプの入力ウィンドウから読み出します。現在位置は変更されません。関数形式 (値を返す) とプロシージャ形式 (参照引数を変更する) の両方があります。

int8 window_read(input_window_int8 *w);
int16 window_read(input_window_int16 *w);
int32 window_read(input_window_int32 *w);
int64 window_read(input_window_int64 *w);
uint8 window_read(input_window_uint8 *w);
uint16 window_read(input_window_uint16 *w);
uint32 window_read(input_window_uint32 *w);
uint64 window_read(input_window_uint64 *w);
cint16 window_read(input_window_cint16 *w);
cint32 window_read(input_window_cint32 *w);
float window_read(input_window_float *w);
cfloat window_read(input_window_cfloat *w);

void window_read(input_window_int8 *w, int8 &v );
void window_read(input_window_int16 *w, int16 &v );
void window_read(input_window_int32 *w, int32 &v );
void window_read(input_window_int64 *w, int64 &v );
void window_read(input_window_uint8 *w, uint8 &v );
void window_read(input_window_uint16 *w, uint16 &v );
void window_read(input_window_uint32 *w, uint32 &v );
void window_read(input_window_uint64 *w, uint64 &v );
void window_read(input_window_cint16 *w, cint16 &v);
void window_read(input_window_cint32 *w, cint32 &v);
void window_read(input_window_float *w, float &v);
void window_read(input_window_cfloat *w, cfloat &v);

次のコードは、型付き値の 4 ウェイ ベクターを同じタイプの入力ウィンドウから読み出します。現在位置は変更されません。関数形式 (値を返す) とプロシージャ形式 (参照引数を変更する) の両方があります。ベクター演算の場合、メモリ データパスは 128 ビットまたは 256 ビット幅です。

v4cint16 window_read_v4(input_window_cint16 *w);
v4int32 window_read_v4(input_window_int32 *w);
v4cint32 window_read_v4(input_window_cint32 *w);
v4int64 window_read_v4(input_window_int64 *w);
v4float window_read_v4(input_window_float *w);
v4cfloat window_read_v4(input_window_cfloat *w);

void window_read(input_window_cint16 *w, v4cint16 &v);
void window_read(input_window_int32 *w, v4int32 &v);
void window_read(input_window_cint32 *w, v4cint32 &v);
void window_read(input_window_int64 *w, v4int64 &v);
void window_read(input_window_float *w, v4float &v);
void window_read(input_window_cfloat *w, v4cfloat &v);

次のコードは、型付き値の 8 ウェイ ベクターを同じタイプの入力ウィンドウから読み出します。現在位置は変更されません。関数形式 (値を返す) とプロシージャ形式 (参照引数を変更する) の両方があります。ベクター演算の場合、メモリ データパスは 128 ビットまたは 256 ビット幅です。

v8int16 window_read_v8(input_window_int16 *w);
v8cint16 window_read_v8(input_window_cint16 *w);
v8int32 window_read_v8(input_window_int32 *w);
v8float window_read_v8(input_window_float *w);

void window_read(input_window_int16 *w, v8int16 &v);
void window_read(input_window_cint16 *w, v8cint16 &v);
void window_read(input_window_int32 *w, v8int32 &v);
void window_read(input_window_float *w, v8float &v);

次のコードは、型付き値の 16 ウェイ ベクターを同じタイプの入力ウィンドウから読み出します。現在位置は変更されません。関数形式 (値を返す) とプロシージャ形式 (参照引数を変更する) の両方があります。ベクター演算の場合、メモリ データパスは 128 ビットまたは 256 ビット幅です。

v16int8 window_read_v16(input_window_int8 *w);
v16uint8 window_read_v16(input_window_uint8 *w);
v16int16 window_read_v16(input_window_int16 *w);
v16cint16 window_read_v16(input_window_cint16 *w);
v16int32 window_read_v16(input_window_int32 *w);
v16cint32 window_read_v16(input_window_cint32 *w);
v16float window_read_v16(input_window_float *w);
v16cfloat window_read_v16(input_window_cfloat *w);

void window_read(input_window_int8 *w, v16int8 &v);
void window_read(input_window_uint8 *w, v16uint8 &v);
void window_read(input_window_int16 *w, v16int16 &v);
void window_read(input_window_cint16 *w, v16cint16 &v);
void window_read(input_window_int32 *w, v16int32 &v);
void window_read(input_window_cint32 *w, v16cint32 &v);
void window_read(input_window_float *w, v16float &v);
void window_read(input_window_cfloat *w, v16cfloat &v);

次のコードは、型付き値の 32 ウェイ ベクターを同じタイプの入力ウィンドウから読み出します。現在位置は変更されません。関数形式 (値を返す) とプロシージャ形式 (参照引数を変更する) の両方があります。ベクター演算の場合、メモリ データパスは 128 ビットまたは 256 ビット幅です。

v32int8 window_read_v32(input_window_int8 *w);
v32uint8 window_read_v32(input_window_uint8 *w);
v32int16 window_read_v32(input_window_int16 *w);
v32cint16 window_read_v32(input_window_cint16 *w);
v32int32 window_read_v32(input_window_int32 *w);
v32float window_read_v32(input_window_float *w);

void window_read(input_window_int8 *w, v32int8 &v);
void window_read(input_window_uint8 *w, v32uint8 &v);
void window_read(input_window_int16 *w, v32int16 &v);
void window_read(input_window_cint16 *w, v32cint16 &v);
void window_read(input_window_int32 *w, v32int32 &v);
void window_read(input_window_float *w, v32float &v);

次のコードは、型付き値の 64 ウェイ ベクターを同じタイプの入力ウィンドウから読み出します。現在位置は変更されません。関数形式 (値を返す) とプロシージャ形式 (参照引数を変更する) の両方があります。ベクター演算の場合、メモリ データパスは 128 ビットまたは 256 ビット幅です。

v64int8 window_read_v64(input_window_int8 *w);
v64uint8 window_read_v64(input_window_uint8 *w);
v64int16 window_read_v64(input_window_int16 *w);

void window_read(input_window_int8 *w, v64int8 &v);
void window_read(input_window_uint8 *w, v64uint8 &v);
void window_read(input_window_int16 *w, v64int16 &v);

入力ウィンドウの読み出しと前方移動

次のコードは、スカラー型の値を同じタイプの入力ウィンドウから読み出し、ウィンドウの現在位置を、基礎となるデータ型のサイズの 1 倍だけ前に移動させます。関数形式 (値を返す) とプロシージャ形式 (参照引数を変更する) の両方があります。

int8 window_readincr(input_window_int8 *w);
int16 window_readincr(input_window_int16 *w);
int32 window_readincr(input_window_int32 *w);
int64 window_readincr(input_window_int64 *w);
uint8 window_readincr(input_window_uint8 *w);
uint16 window_readincr(input_window_uint16 *w);
uint32 window_readincr(input_window_uint32 *w);
uint64 window_readincr(input_window_uint64 *w);
cint16 window_readincr(input_window_cint16 *w);
cint32 window_readincr(input_window_cint32 *w);
float window_readincr(input_window_float *w);
cfloat window_readincr(input_window_cfloat *w);

void window_readincr(input_window_int8 *w, int8 &v );
void window_readincr(input_window_int16 *w, int16 &v );
void window_readincr(input_window_int32 *w, int32 &v );
void window_readincr(input_window_int64 *w, int64 &v );
void window_readincr(input_window_uint8 *w, uint8 &v );
void window_readincr(input_window_uint16 *w, uint16 &v );
void window_readincr(input_window_uint32 *w, uint32 &v );
void window_readincr(input_window_uint64 *w, uint64 &v );
void window_readincr(input_window_cint16 *w, cint16 &v);
void window_readincr(input_window_cint32 *w, cint32 &v);
void window_readincr(input_window_float *w, float &v );
void window_readincr(input_window_cfloat *w, cfloat &v);

次のコードは、型付き値の 4 ウェイ ベクターを同じタイプの入力ウィンドウから読み出し、ウィンドウの現在位置を、基礎となるデータ型のサイズの 4 倍だけ前に移動させます。関数形式 (値を返す) とプロシージャ形式 (参照引数を変更する) の両方があります。ベクター演算の場合、メモリ データパスは 128 ビットまたは 256 ビット幅です。

v4cint16 window_readincr_v4(input_window_cint16 *w);
v4int32 window_readincr_v4(input_window_int32 *w);
v4cint32 window_readincr_v4(input_window_cint32 *w);
v4int64 window_readincr_v4(input_window_int64 *w);
v4float window_readincr_v4(input_window_float *w);
v4cfloat window_readincr_v4(input_window_cfloat *w);

void window_readincr(input_window_cint16 *w, v4cint16 &v);
void window_readincr(input_window_int32 *w, v4int32 &v);
void window_readincr(input_window_cint32 *w, v4cint32 &v);
void window_readincr(input_window_int64 *w, v4int64 &v);
void window_readincr(input_window_float *w, v4float &v);
void window_readincr(input_window_cfloat *w, v4cfloat &v);

次のコードは、型付き値の 8 ウェイ ベクターを同じタイプの入力ウィンドウから読み出し、ウィンドウの現在位置を、基礎となるデータ型のサイズの 8 倍だけ前に移動させます。関数形式 (値を返す) とプロシージャ形式 (参照引数を変更する) の両方があります。ベクター演算の場合、メモリ データパスは 128 ビットまたは 256 ビット幅です。

v8int16 window_readincr_v8(input_window_int16 *w);
v8cint16 window_readincr_v8(input_window_cint16 *w);
v8int32 window_readincr_v8(input_window_int32 *w);
v8float window_readincr_v8(input_window_float *w);

void window_readincr(input_window_int16 *w, v8int16 &v);
void window_readincr(input_window_cint16 *w, v8cint16 &v);
void window_readincr(input_window_int32 *w, v8int32 &v);
void window_readincr(input_window_float *w, v8float &v);

次のコードは、型付き値の 16 ウェイ ベクターを同じタイプの入力ウィンドウから読み出し、ウィンドウの現在位置を、基礎となるデータ型のサイズの 16 倍だけ前に移動させます。関数形式 (値を返す) とプロシージャ形式 (参照引数を変更する) の両方があります。ベクター演算の場合、メモリ データパスは 128 ビットまたは 256 ビット幅です。

v16int8 window_readincr_v16(input_window_int8 *w);
v16uint8 window_readincr_v16(input_window_uint8 *w);
v16int16 window_readincr_v16(input_window_int16 *w);
v16cint16 window_readincr_v16(input_window_cint16 *w);
v16int32 window_readincr_v16(input_window_int32 *w);
v16cint32 window_readincr_v16(input_window_cint32 *w);
v16float window_readincr_v16(input_window_float *w);
v16cfloat window_readincr_v16(input_window_cfloat *w);

void window_readincr(input_window_int8 *w, v16int8 &v);
void window_readincr(input_window_uint8 *w, v16uint8 &v);
void window_readincr(input_window_int16 *w, v16int16 &v);
void window_readincr(input_window_cint16 *w, v16cint16 &v);
void window_readincr(input_window_int32 *w, v16int32 &v);
void window_readincr(input_window_cint32 *w, v16cint32 &v);
void window_readincr(input_window_float *w, v16float &v);
void window_readincr(input_window_cfloat *w, v16cfloat &v);

次のコードは、型付き値の 32 ウェイ ベクターを同じタイプの入力ウィンドウから読み出し、ウィンドウの現在位置を、基礎となるデータ型のサイズの 32 倍だけ前に移動させます。関数形式 (値を返す) とプロシージャ形式 (参照引数を変更する) の両方があります。ベクター演算の場合、メモリ データパスは 128 ビットまたは 256 ビット幅です。

v32int8 window_readincr_v32(input_window_int8 *w);
v32uint8 window_readincr_v32(input_window_uint8 *w);
v32int16 window_readincr_v32(input_window_int16 *w);
v32cint16 window_readincr_v32(input_window_cint16 *w);
v32int32 window_readincr_v32(input_window_int32 *w);
v32float window_readincr_v32(input_window_float *w);

void window_readincr(input_window_int8 *w, v32int8 &v);
void window_readincr(input_window_uint8 *w, v32uint8 &v);
void window_readincr(input_window_int16 *w, v32int16 &v);
void window_readincr(input_window_cint16 *w, v32cint16 &v);
void window_readincr(input_window_int32 *w, v32int32 &v);
void window_readincr(input_window_float *w, v32float &v);

次のコードは、型付き値の 64 ウェイ ベクターを同じタイプの入力ウィンドウから読み出し、ウィンドウの現在位置を、基礎となるデータ型のサイズの 64 倍だけ前に移動させます。関数形式 (値を返す) とプロシージャ形式 (参照引数を変更する) の両方があります。ベクター演算の場合、メモリ データパスは 128 ビットまたは 256 ビット幅です。

v64int8 window_readincr_v64(input_window_int8 *w);
v64uint8 window_readincr_v64(input_window_uint8 *w);
v64int16 window_readincr_v64(input_window_int16 *w);

void window_readincr(input_window_int8 *w, v64int8 &v);
void window_readincr(input_window_uint8 *w, v64uint8 &v);
void window_readincr(input_window_int16 *w, v64int16 &v);

入力ウィンドウの読み出しと後方移動

次のコードは、スカラー型の値を同じタイプの入力ウィンドウから読み出し、ウィンドウの現在位置を、基礎となるデータ型のサイズの 1 倍だけデクリメントし (後ろにずらし) ます。関数形式 (値を返す) とプロシージャ形式 (参照引数を変更する) の両方があります。

int8 window_readdecr(input_window_int8 *w);
int16 window_readdecr(input_window_int16 *w);
int32 window_readdecr(input_window_int32 *w);
int64 window_readdecr(input_window_int64 *w);
uint8 window_readdecr(input_window_uint8 *w);
uint16 window_readdecr(input_window_uint16 *w);
uint32 window_readdecr(input_window_uint32 *w);
uint64 window_readdecr(input_window_uint64 *w);
cint16 window_readdecr(input_window_cint16 *w);
cint32 window_readdecr(input_window_cint32 *w);
float window_readdecr(input_window_float *w);
cfloat window_readdecr(input_window_cfloat *w);

void window_readdecr(input_window_int8 *w, int8 &v );
void window_readdecr(input_window_int16 *w, int16 &v );
void window_readdecr(input_window_int32 *w, int32 &v );
void window_readdecr(input_window_int64 *w, int64 &v );
void window_readdecr(input_window_uint8 *w, uint8 &v );
void window_readdecr(input_window_uint16 *w, uint16 &v );
void window_readdecr(input_window_uint32 *w, uint32 &v );
void window_readdecr(input_window_uint64 *w, uint64 &v );
void window_readdecr(input_window_cint16 *w, cint16 &v);
void window_readdecr(input_window_cint32 *w, cint32 &v);
void window_readdecr(input_window_float *w, float &v );
void window_readdecr(input_window_cfloat *w, cfloat &v);

次のコードは、型付き値の 4 ウェイ ベクターを同じタイプの入力ウィンドウから読み出し、ウィンドウの現在位置を、基礎となるデータ型のサイズの 4 倍だけデクリメントします。関数形式 (値を返す) とプロシージャ形式 (参照引数を変更する) の両方があります。ベクター演算の場合、メモリ データパスは 128 ビットまたは 256 ビット幅です。

v4cint16 window_readdecr_v4(input_window_cint16 *w);
v4int32 window_readdecr_v4(input_window_int32 *w);
v4cint32 window_readdecr_v4(input_window_cint32 *w);
v4int64 window_readdecr_v4(input_window_int64 *w);
v4float window_readdecr_v4(input_window_float *w);
v4cfloat window_readdecr_v4(input_window_cfloat *w);

void window_readdecr(input_window_cint16 *w, v4cint16 &v);
void window_readdecr(input_window_int32 *w, v4int32 &v);
void window_readdecr(input_window_cint32 *w, v4cint32 &v);
void window_readdecr(input_window_int64 *w, v4int64 &v);void window_readdecr(input_window_float *w, v4float &v);
void window_readdecr(input_window_cfloat *w, v4cfloat &v);

次のコードは、型付き値の 8 ウェイ ベクターを同じタイプの入力ウィンドウから読み出し、ウィンドウの現在位置を、基礎となるデータ型のサイズの 8 倍だけデクリメントします。関数形式 (値を返す) とプロシージャ形式 (参照引数を変更する) の両方があります。ベクター演算の場合、メモリ データパスは 128 ビットまたは 256 ビット幅です。

v8int16 window_readdecr_v8(input_window_int16 *w);
v8cint16 window_readdecr_v8(input_window_cint16 *w);
v8int32 window_readdecr_v8(input_window_int32 *w);
v8float window_readdecr_v8(input_window_float *w);

void window_readdecr(input_window_int16 *w, v8int16 &v);
void window_readdecr(input_window_cint16 *w, v8cint16 &v);
void window_readdecr(input_window_int32 *w, v8int32 &v);
void window_readdecr(input_window_float *w, v8float &v);

次のコードは、型付き値の 16 ウェイ ベクターを同じタイプの入力ウィンドウから読み出し、ウィンドウの現在位置を、基礎となるデータ型のサイズの 16 倍だけデクリメントします。関数形式 (値を返す) とプロシージャ形式 (参照引数を変更する) の両方があります。ベクター演算の場合、メモリ データパスは 128 ビットまたは 256 ビット幅です。

v16int8 window_readdecr_v16(input_window_int8 *w);
v16uint8 window_readdecr_v16(input_window_uint8 *w);
v16int16 window_readdecr_v16(input_window_int16 *w);
v16cint16 window_readdecr_v16(input_window_cint16 *w);
v16int32 window_readdecr_v16(input_window_int32 *w);
v16cint32 window_readdecr_v16(input_window_cint32 *w);
v16float window_readdecr_v16(input_window_float *w);
v16cfloat window_readdecr_v16(input_window_cfloat *w);

void window_readdecr(input_window_int8 *w, v16int8 &v);
void window_readdecr(input_window_uint8 *w, v16uint8 &v);
void window_readdecr(input_window_int16 *w, v16int16 &v);
void window_readdecr(input_window_cint16 *w, v16cint16 &v);
void window_readdecr(input_window_int32 *w, v16int32 &v);
void window_readdecr(input_window_cint32 *w, v16cint32 &v);
void window_readdecr(input_window_float *w, v16float &v);
void window_readdecr(input_window_cfloat *w, v16cfloat &v);

次のコードは、型付き値の 32 ウェイ ベクターを同じタイプの入力ウィンドウから読み出し、ウィンドウの現在位置を、基礎となるデータ型のサイズの 32 倍だけデクリメントします。関数形式 (値を返す) とプロシージャ形式 (参照引数を変更する) の両方があります。ベクター演算の場合、メモリ データパスは 128 ビットまたは 256 ビット幅です。

v32int8 window_readdecr_v32(input_window_int8 *w);
v32uint8 window_readdecr_v32(input_window_uint8 *w);
v32int16 window_readdecr_v32(input_window_int16 *w);
v32cint16 window_readdecr_v32(input_window_cint16 *w);
v32int32 window_readdecr_v32(input_window_int32 *w);
v32float window_readdecr_v32(input_window_float *w);

void window_readdecr(input_window_int8 *w, v32int8 &v);
void window_readdecr(input_window_uint8 *w, v32uint8 &v);
void window_readdecr(input_window_int16 *w, v32int16 &v);
void window_readdecr(input_window_cint16 *w, v32cint16 &v);
void window_readdecr(input_window_int32 *w, v32int32 &v);
void window_readdecr(input_window_float *w, v32float &v);

次のコードは、型付き値の 64 ウェイ ベクターを同じタイプの入力ウィンドウから読み出し、ウィンドウの現在位置を、基礎となるデータ型のサイズの 64 倍だけデクリメントします。関数形式 (値を返す) とプロシージャ形式 (参照引数を変更する) の両方があります。ベクター演算の場合、メモリ データパスは 128 ビットまたは 256 ビット幅です。

v64int8 window_readdecr_v64(input_window_int8 *w);
v64uint8 window_readdecr_v64(input_window_uint8 *w);
v64int16 window_readdecr_v64(input_window_int16 *w);

void window_readdecr(input_window_int8 *w, v64int8 &v);
void window_readdecr(input_window_uint8 *w, v64uint8 &v);
void window_readdecr(input_window_int16 *w, v64int16 &v);

出力ウィンドウへのデータの書き込み

次のコードは、スカラー型の値を同じタイプの出力ウィンドウに書き出します。現在位置は変更されません。

void window_write(output_window_int8 *w, int8 v);
void window_write(output_window_uint8 *w, uint8 v);
void window_write(output_window_int16 *w, int16 v);
void window_write(output_window_uint16 *w, uint16 v);
void window_write(output_window_cint16 *w, cint16 v);
void window_write(output_window_int32 *w, int32 v );
void window_write(output_window_uint32 *w, uint32 v );
void window_write(output_window_cint32 *w, cint32 v);
void window_write(output_window_int64 *w, int64 v );
void window_write(output_window_uint64 *w, uint64 v );
void window_write(output_window_float *w, float v );
void window_write(output_window_cfloat *w, cfloat v);

次のコードは、型付き値の 4 ウェイ ベクターを同じタイプの出力ウィンドウに書き出します。現在位置は変更されません。

void window_write(output_window_cint16 *w, v4cint16 v);
void window_write(output_window_int32 *w, v4int32 v );
void window_write(output_window_cint32 *w, v4cint32 v);
void window_write(output_window_int64 *w, v4int64 v );
void window_write(output_window_float *w, v4float v );
void window_write(output_window_cfloat *w, v4cfloat v);

次のコードは、型付き値の 8 ウェイ ベクターを同じタイプの出力ウィンドウに書き出します。現在位置は変更されません。

void window_write(output_window_int16 *w, v8int16 v);
void window_write(output_window_cint16 *w, v8cint16 v);
void window_write(output_window_int32 *w, v8int32 v );
void window_write(output_window_float *w, v8float v );

次のコードは、型付き値の 16 ウェイ ベクターを同じタイプの出力ウィンドウに書き出します。現在位置は変更されません。

void window_write(output_window_int8 *w, v16int8 v);
void window_write(output_window_uint8 *w, v16uint8 v);
void window_write(output_window_int16 *w, v16int16 v);
void window_write(output_window_cint16 *w, v16cint16 v);
void window_write(output_window_int32 *w, v16int32 v );
void window_write(output_window_cint32 *w, v16cint32 v);
void window_write(output_window_float *w, v16float v );
void window_write(output_window_cfloat *w, v16cfloat v);

次のコードは、型付き値の 32 ウェイ ベクターを同じタイプの出力ウィンドウに書き出します。現在位置は変更されません。

void window_write(output_window_int8 *w, v32int8 v);
void window_write(output_window_uint8 *w, v32uint8 v);
void window_write(output_window_int16 *w, v32int16 v);
void window_write(output_window_cint16 *w, v32cint16 v);
void window_write(output_window_int32 *w, v32int32 v );
void window_write(output_window_float *w, v32float v );

次のコードは、型付き値の 64 ウェイ ベクターを同じタイプの出力ウィンドウに書き出します。現在位置は変更されません。

void window_write(output_window_int8 *w, v64int8 v);
void window_write(output_window_uint8 *w, v64uint8 v);
void window_write(output_window_int16 *w, v64int16 v);

出力ウィンドウの書き込みと前方移動

次のコードは、スカラー型の値を同じタイプの出力ウィンドウに書き出し、そのデータ型に基づいて現在位置を前に移動させます。

void window_writeincr (output_window_int8 *w, int8 v);
void window_writeincr (output_window_uint8 *w, uint8 v);
void window_writeincr (output_window_int16 *w, int16 v);
void window_writeincr (output_window_uint16 *w, uint16 v);
void window_writeincr (output_window_cint16 *w, cint16 v);
void window_writeincr (output_window_int32 *w, int32 v );
void window_writeincr (output_window_uint32 *w, uint32 v );
void window_writeincr (output_window_cint32 *w, cint32 v);
void window_writeincr (output_window_int64 *w, int64 v);
void window_writeincr (output_window_uint64 *w, uint64 v);void window_writeincr (output_window_float *w, float v );
void window_writeincr (output_window_cfloat *w, cfloat v);

次のコードは、型付き値の 4 ウェイ ベクターを同じタイプの出力ウィンドウに書き出し、基礎となるデータ型のサイズの 4 倍だけ現在位置を前に移動させます。

void window_writeincr(output_window_cint16 *w, v4cint16 v);
void window_writeincr(output_window_int32 *w, v4int32 v );
void window_writeincr(output_window_cint32 *w, v4cint32 v);
void window_writeincr(output_window_int64 *w, v4int64 v );
void window_writeincr(output_window_float *w, v4float v );
void window_writeincr(output_window_cfloat *w, v4cfloat v);

次のコードは、型付き値の 8 ウェイ ベクターを同じタイプの出力ウィンドウに書き出し、基礎となるデータ型のサイズの 8 倍だけ現在位置を前に移動させます。

void window_writeincr(output_window_int16 *w, v8int16 v);
void window_writeincr(output_window_cint16 *w, v8cint16 v);
void window_writeincr(output_window_int32 *w, v8int32 v );
void window_writeincr(output_window_float *w, v8float v );

次のコードは、型付き値の 16 ウェイ ベクターを同じタイプの出力ウィンドウに書き出し、基礎となるデータ型のサイズの 16 倍だけ現在位置を前に移動させます。

void window_writeincr(output_window_int8 *w, v16int8 v);
void window_writeincr(output_window_uint8 *w, v16uint8 v);
void window_writeincr(output_window_int16 *w, v16int16 v);
void window_writeincr(output_window_cint16 *w, v16cint16 v);
void window_writeincr(output_window_int32 *w, v16int32 v );
void window_writeincr(output_window_cint32 *w, v16cint32 v);
void window_writeincr(output_window_float *w, v16float v );
void window_writeincr(output_window_cfloat *w, v16cfloat v);

次のコードは、型付き値の 32 ウェイ ベクターを同じタイプの出力ウィンドウに書き出し、基礎となるデータ型のサイズの 32 倍だけ現在位置を前に移動させます。

void window_writeincr(output_window_int8 *w, v32int8 v);
void window_writeincr(output_window_uint8 *w, v32uint8 v);
void window_writeincr(output_window_int16 *w, v32int16 v);
void window_writeincr(output_window_cint16 *w, v32cint16 v);
void window_writeincr(output_window_int32 *w, v32int32 v );
void window_writeincr(output_window_float *w, v32float v );

次のコードは、型付き値の 64 ウェイ ベクターを同じタイプの出力ウィンドウに書き出し、基礎となるタイプのサイズの 64 倍だけ現在位置を前に移動させます。

void window_writeincr(output_window_int8 *w, v64int8 v);
void window_writeincr(output_window_uint8 *w, v64uint8 v);
void window_writeincr(output_window_int16 *w, v64int16 v);

カーネルのストリーム動作

ストリーム データ型

表 2. サポートしているストリーム データ型
入力ストリーム型 出力ストリーム型
input_stream_int8 output_stream_int8
input_stream_int16 output_stream_int16
input_stream_int32 output_stream_int32
input_stream_int64 output_stream_int64
input_stream_uint8 output_stream_uint8
input_stream_uint16 output_stream_uint16
input_stream_uint32 output_stream_uint32
input_stream_uint64 output_stream_uint64
input_stream_cint16 output_stream_cint16
input_stream_cint32 output_stream_cint32
input_stream_acc48 output_stream_acc48
input_stream_cacc48 output_stream_cacc48
input_stream_float output_stream_float
input_stream_cfloat output_stream_cfloat

表の各データ型は、AI エンジン カーネルまたはプログラマブル ロジック カーネルからスカラー グループまたはベクター グループとして読み出しまたは書き込み可能です。ただし、有効なグループ化については、AI エンジン上でサポートされる、プログラマブル ロジックのインターフェイス ポートまたはストリーム スイッチ ネットワークへのバス データ幅に基づく制限があります。AI エンジン カーネルの場合、有効な組み合わせは合計で最大 32 ビットまたは 128 ビットのベクター バンドルです。プログラマブル ロジック カーネルの場合、有効な組み合わせは合計で最大 32 ビット、64 ビット、または 128 ビット バスのベクター バンドルです。アキュムレータ データ型は、隣接する AI エンジン間のカスケード ストリーム接続の指定にのみ使用されます。このデータ型の有効なグループは、2 つのプロセッサ間の 384 ビット幅のカスケード チャネルに基づいています。

注記: これらのデータ型を使用するには、カーネル ソース ファイル内で #include <adf.h> を使用する必要があります。

入力ストリームの読み出しと前方移動

AI エンジンの動作

次の処理は、指定された入力ストリームからデータを読み出し、AI エンジン上でストリームを前に移動させます。AI エンジンには 2 つの入力ストリーム ポートがあるため、物理ポートの割り当ては AI エンジン コンパイラによって自動的に実行され、ストリーム データ構造の一部として伝搬されます。データ値は、一度に 1 つずつストリームから読み出すことも、ベクターとして読み出すこともできます。ベクターとして読み出す場合、すべての値が存在しない限り、ストリームの処理はストールします。データのグループは、基礎となる 1 サイクル、32 ビットのストリーム処理、または 4 サイクル、128 ビット幅のストリーム処理に基づきます。カスケード接続では、すべてのアキュムレータ値を並列に読み出します。

int32 readincr(input_stream_int32 *w);
uint32 readincr(input_stream_uint32 *w);
cint16 readincr(input_stream_cint16 *w);
float readincr(input_stream_float *w);
cfloat readincr(input_stream_cfloat *w);

v16int8 readincr_v16(input_stream_int8 *w);
v16uint8 readincr_v16(input_stream_uint8 *w);
v8int16 readincr_v8(input_stream_int16 *w);
v4cint16 readincr_v4(input_stream_cint16 *w);
v4int32 readincr_v4(input_stream_int32 *w);
v2cint32 readincr_v2(input_stream_cint32 *w);
v4float readincr_v4(input_stream_float *w);

v8acc48 readincr_v8(input_stream_acc48 *w);
v4cacc48 readincr_v4(input_stream_cacc48 *w);

出力ストリームの書き込みと前方移動

AI エンジンの動作

次の処理は、指定された出力ストリームにデータを書き込み、AI エンジン上でストリームを前に移動させます。AI エンジンには 2 つの出力ストリーム ポートがあるため、物理ポートの割り当ては AI エンジン コンパイラによって自動的に実行され、ストリーム データ構造の一部として伝搬されます。データ値は、一度に 1 つずつ出力ストリームに書き込むことも、ベクターとして書き込むこともできます。ベクターとして書き込む場合、すべての値が書き込まれるまでストリームの処理はストールします。データのグループは、基礎となる 1 サイクル、32 ビットのストリーム処理、または 4 サイクル、128 ビット幅のストリーム処理に基づきます。カスケード接続では、すべての値を並列に書き込みます。

void writeincr(output_stream_int32 *w, int32 v);
void writeincr(output_stream_uint32 *w, uint32 v);
void writeincr(output_stream_cint16 *w, cint16 v);
void writeincr(output_stream_float *w, float v);
void writeincr(output_stream_cfloat *w, cfloat v);

void writeincr_v16(output_stream_int8 *w, v16int8 v);
void writeincr_v16(output_stream_uint8 *w, v16uint8 v);
void writeincr_v8(output_stream_int16 *w, v8int16 v);
void writeincr_v4(output_stream_cint16 *w, v4cint16 v);
void writeincr_v4(output_stream_int32 *w, v4int32 v);
void writeincr_v2(output_stream_cint32 *w, v2cint32 v);
void writeincr_v4(output_stream_float *w, v4float v);

void writeincr_v8(output_stream_acc48 *w, v8acc48 v);
void writeincr_v4(output_stream_cacc48 *w, v4cacc48 v);

並列ストリームの使用

ストリーミング入力および出力インターフェイスで、パフォーマンスがストリーミング インターフェイスによって制限される場合、2 つのストリーミング入力または 2 つのストリーミング出力を並列で使用することが可能です。2 つの並列ストリームを使用するには、次のマクロのペアを使用することを推奨します。ここで、idx1idx2 は 2 つのストリームです。ストリーム ポートに restrict キーワードを追加して、並列処理用にポートを最適化します。このマクロは、1 サイクルごとに 32 ビット、または 4 サイクルごとに 128 ビットを処理します。

READINCR(SS_rsrc1, idx1) and READINCR(SS_rsrc2, idx2)
READINCRW(WSS_rsrc1, idx1) and READINCRW(WSS_rsrc2, idx2)
WRITEINCR(MS_rsrc1, idx1, val) and WRITEINCR(MS_rsrc2, idx2, val)
WRITEINCRW(WMS_rsrc1, idx1, val) and WRITEINCRW(WMS_rsrc2, idx2, val)

次のサンプル コードは、1 の間隔でパイプライン処理を使用する 2 つの入力ストリームを示しています。

void simple( input_stream_int32 * restrict data0, input_stream_int32 * restrict data1, 
    output_stream_int32 * restrict out) {
   for(int i=0; i<1024; i++)
   chess_prepare_for_pipelining
 {
     int32_t d = READINCR(SS_rsrc1, data0) ;
     int32_t e = READINCR(SS_rsrc2, data1) ;
     WRITEINCR(MS_rsrc1,out,d+e);
 }
}

パケット ストリーム動作

表 3. サポートしているパケット ストリーム データ型
入力ストリーム型 出力ストリーム型
input_pktstream output_pktstream

さらに 2 つのストリーム データ型があり、これらは複数の異なるストリームをパケット化してインターリーブしたストリーミング データを示します。これらのデータ型は、プログラム内の独立したデータ ストリームの数が、利用可能なハードウェア ストリーム チャネルまたはポートの数を超える場合に役立ちます。このメカニズムの詳細は、明示的パケット スイッチング で説明します。

パケット ストリームの呼び出しと書き込み

データ パケットは、1 ワード (32 ビット) のパケット ヘッダーと、後続するいくつかのデータ ワード (最後のデータ ワードにはパケット終了を示す TLAST フィールドがある) で構成されます。次の処理を使用して、入力パケット ストリームの読み出しと前方移動、および出力パケット ストリームの書き込みと前方移動を実行できます。

int32 readincr(input_pktstream *w);
int32 readincr(input_pktstream *w, bool &tlast);

void writeincr(output_pktstream *w, int32 value);
void writeincr(output_pktstream *w, int32 value, bool tlast);

TLAST 引数を持つ API は、パケット サイズが固定されていない場合に、パケット終了条件の読み出しまたは書き込みに役立ちます。

パケット処理

パケットの最初の 32 ビット ワードは常にパケット ヘッダーである必要があります。このヘッダーは、次の表に示すように、数個のビット フィールドをエンコードします。

表 4. パケットのビット フィールド
ビット フィールド
4 ~ 0 パケット ID
11 ~ 5 7'b0000000
14 ~ 12 パケット タイプ
15 1'b0
20 ~ 16 ソース行
27 ~ 21 ソース列
30 ~ 28 3'b000
31 ビット[30:0] の奇数パリティ

パケット ID は、配線の必要条件に基づいてコンパイラによって割り当てられます。パケット タイプは、パケットのタイプを特定するために挿入される、任意の 3 ビット パターンです。ソース行とソース列は、パケットが発生した AI エンジン タイル座標を示します。規則により、PL 内で発生したパケットのソース行とソース列は、-1,-1 になります。

各パケットの先頭に適切なパケット ヘッダーを構築し、送信するのは、ユーザーの役割です。受信側では、パケット ヘッダーは、データを読み出す前に受信され、デコードされる必要があります。

次の処理は、AI エンジン カーネル内のパケット ヘッダーのアセンブルまたはディアセンブルに役立ちます。

uint32 generateHeader(uint32 pktType, uint32 ID);
uint32 generateHeader(uint32 pktType, uint32 srcCol, uint32 srcRow, uint32
ID);

uint32 getPacketid(input_pktstream *w, int index);
uint32 getPacketid(output_pktstream *w, int index);

generateHeader API により、指定したパケット ID とパケット タイプを使用してパケット ヘッダーをアセンブルできます。ソース行とソース列は、明示的に指定することも (PL コードの場合)、API が実行される AI エンジン タイルの座標を使用して自動的に挿入することもできます。

getPacketid API により、コンパイラによって割り当てられたパケット ID を、入力または出力パケット ストリーム データ構造上で問い合わせることができます。インデックス引数は、グラフ仕様内の分岐エッジの分割または結合を指定します。

重要: generateHeader() および getPacketid() API は、PL カーネルではサポートされません。

詳細は、明示的パケット スイッチングを参照してください。