配列引数は、デフォルトではワード アドレス指定を使用して ap_memory
インターフェイスとしてインプリメントされます。これは、データ ポート、アドレス ポート、チップイネーブル ポート、ライトイネーブル ポートを含む標準ブロック RAM インターフェイスです。
ap_memory
インターフェイスは、デュアル ポート インターフェイスのシングル ポートとしてインプリメントできます。Vitis HLS でデュアル ポート インターフェイスを使用することで開始間隔 (II) が削減されると判断された場合は、デュアル ポート インターフェイスが自動的にインプリメントされます。BIND_STORAGE プラグマまたは指示子を使用してメモリ リソースを指定し、シングル ポート ブロック RAM を含む配列に指定した場合は、シングル ポート インターフェイスをインプリメントできます。また、BIND_STORAGE プラグマでデュアル ポート インターフェイスを指定していても、このインターフェイスを使用しても利点がないと Vitis HLS で判断された場合は、シングル ポート インターフェイスが自動的にインプリメントされます。
配列がシーケンシャルにアクセスされる場合は、ap_fifo
インターフェイスを使用できます。ap_hs
インターフェイスを使用した場合と同様、データ アクセスがシーケンシャルでないと判断されると Vitis HLS が停止します。アクセスがシーケンシャルかどうかを判断できない場合は警告メッセージが表示され、シーケンシャルであると判断された場合はメッセージは表示されません。ap_fifo
は、読み出しまたは書き込みのいずれかにのみ使用可能で、両方には使用できません。
ap_memory、bram
ap_memory
および bram
インターフェイス ポート レベル I/O プロトコルは、配列引数をインプリメントするために使用されます。このタイプのポート レベル I/O プロトコルは、インプリメンテーションでメモリのアドレス ロケーションにランダム アクセスが必要な場合に、メモリ エレメント (RAM、ROM など) と通信するために使用されます。
ap_fifo
インターフェイスを使用してください。ap_fifo
インターフェイスを使用すると、アドレス生成は実行されないので、ハードウェア オーバーヘッドが削減します。
ap_memory
と bram
インターフェイスのポート レベル I/O プロトコルは、同じではありませんが、類似しています。ap_memory
インターフェイスはワード ベースのアドレス指定を使用し、追加のチップ イネーブル制御信号を生成し、bram
インターフェイスはバイト アドレス指定を使用します。次の表は、その違いをまとめています。
ap_memory | bram | |
---|---|---|
n 番目のワードのアドレス | n*1 | n*(バイトのワード サイズ) |
アドレス ビット幅 | ceil(log2(depth)) | 32 ビット |
サポートされるワード サイズ | 任意の値 | 8*2 のべき乗ビット |
バイト イネーブルのサポート | あり (ワード サイズが複数バイトの場合) | 〇 |
IP インテグレーターのサポート | なし | ブロック メモリ ジェネレーターとエンベデッド メモリ ジェネレーターのいずれかまたは両方のサポート |
Vivado ツールでは、インターフェイスの表記法も異なっています。
-
ap_memory
インターフェイスは個別のポートとして表示される。 -
bram
インターフェイスは 1 つのポートとして表示される。IP インテグレーターでは、1 つの接続を使用して、すべてのポートへの接続を作成できます。
メモリ インターフェイスを使用する場合は、BIND_STORAGE 指示子を使用してインプリメンテーションを指定してください。配列に対してターゲットを指定しない場合は、Vitis HLS でシングル ポートまたはデュアル ポート RAM インターフェイスのいずれかが指定されます。
次の図では、d
という配列がシングル ポート ブロック RAM として指定されています。ポート名は、C/C++ 関数引数に基づいています。たとえば、C/C++ 関数が d
の場合、チップ イネーブルは d_ce
、入力データはブロック RAM の output/q
ポートに基づいて d_q0
になります。
リセット後は、次にようになります。
- ap_start が High になると、ブロックが通常の動作を開始します。
- 出力信号
d_ce
をアサートしたときに出力アドレス ポートにアドレスを供給することにより、読み出しが実行されます。注記: デフォルトのブロック RAM では、入力データd_q0
が次のクロック サイクルで有効になると想定されます。BIND_STORAGE プラグマを使用すると、RAM の読み出しレイテンシを長くできます。 - 書き込み操作は、出力ポート
d_ce
とd_we
がアサートされ、同時にアドレスと出力データd_d0
が供給されると実行されます。
ap_fifo
出力ポートが書き込まれると、デザインがメモリ エレメントにアクセスする必要があり、そのアクセスが常に順番に実行される、つまりランダム アクセスが必要ない場合、ap_fifo に関連する出力 valid
信号インターフェイスを使用するのが最もハードウェア効率の良いアプローチです。ap_fifo
ポート レベル I/O プロトコルでは、次がサポートされます。
- ポートを FIFO に接続できるようになる
- 完全な双方向の
empty-full
通信をイネーブル - 配列、ポインター、参照渡し引数タイプに使用できる
ap_fifo
インターフェイスを使用可能な関数では、ポインターがよく使用され、同じ変数に複数回アクセスする可能性があります。インターフェイスのマルチアクセス ポインターを参照し、このコーディング スタイルを使用する場合の volatile
修飾子の重要性を理解してください。次の例では、in1
は現在のアドレスにアクセスし、その後現在のアドレスの上 2 つのアドレスにアクセスして、最後に 1 つ下のアドレスにアクセスするポインターです。
void foo(int* in1, ...) {
int data1, data2, data3;
...
data1= *in1;
data2= *(in1+2);
data3= *(in1-1);
...
}
in1
を ap_fifo
インターフェイスとして指定すると、Vitis HLS でアクセスがチェックされ、アクセスが順次でない場合はエラー メッセージが表示され、停止します。順次アドレスではないアドレス位置から読み出すには、ap_memory
または bram
インターフェイスを使用します。
読み出しおよび書き込みの両方に使用される場合、引数に ap_fifo
インターフェイスは指定できません。ap_fifo
インターフェイスは、入力引数または出力引数にのみ指定可能です。入力引数 in
、出力引数 out
を ap_fifo
インターフェイスとして指定したデザインは、次の図のように動作します。
入力では、次のようになります。
- ap_start が High になると、ブロックが通常の動作を開始します。
- 入力ポートで読み出し準備ができたのに FIFO が空の場合 (
in_empty_n
入力ポートが Low)、デザインは停止し、データを読み出せるようになるまで待機します。 -
in_empty_n
入力ポートが High になって FIFO にデータが含まれていることが示されると、出力 ACK のin_read
が High にアサートされてデータがこのサイクルで読み出されたことが示されます。
出力では、次のようになります。
- ap_start が High になると、ブロックが通常の動作を開始します。
- 出力ポートで書き込み準備ができても、FIFO がフルの場合 (
out_full_n
が Low)、データは出力ポートに配置されますが、デザインは停止し、FIFO に書き込むスペースができるまで待機します。 - FIFO に書き込むスペースができると (
out_full_n
入力が High)、出力 ACK 信号のout_write
が High になり、出力データがvalid
であることが示されます。 -
-rewind
オプションで最上位関数または最上位ループがパイプライン処理されると、Vitis HLS では_lwr
が接尾語に付いた追加の出力ポートが作成されます。FIFO インターフェイスへの最後の書き込みが終了すると、_lwr
ポートがアクティブ High になります。