ポート レベル I/O: メモリ インターフェイス プロトコル - 2023.2 日本語

Vitis 高位合成ユーザー ガイド (UG1399)

Document ID
UG1399
Release Date
2023-12-18
Version
2023.2 日本語

配列引数は、デフォルトではワード アドレス指定を使用して 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_memorybram インターフェイスのポート レベル I/O プロトコルは、同じではありませんが、類似しています。ap_memory インターフェイスはワード ベースのアドレス指定を使用し、追加のチップ イネーブル制御信号を生成し、bram インターフェイスはバイト アドレス指定を使用します。次の表は、その違いをまとめています。

表 1. ap_memory vs. 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 インターフェイスのいずれかが指定されます。

ヒント: 合成を実行する前に、配列引数が BIND_STORAGE プラグマを使用して正しいメモリ タイプをターゲットにしているかどうかを確認してください。変更されたメモリを使用して合成し直すと、スケジューリングおよび RTL の結果が異なることがあります。

次の図では、d という配列がシングル ポート ブロック RAM として指定されています。ポート名は、C/C++ 関数引数に基づいています。たとえば、C/C++ 関数が d の場合、チップ イネーブルは d_ce、入力データはブロック RAM の output/q ポートに基づいて d_q0 になります。

図 1. ap_memory インターフェイスの動作

リセット後は、次にようになります。

  • ap_start が High になると、ブロックが通常の動作を開始します。
  • 出力信号 d_ce をアサートしたときに出力アドレス ポートにアドレスを供給することにより、読み出しが実行されます。
    注記: デフォルトのブロック RAM では、入力データ d_q0 が次のクロック サイクルで有効になると想定されます。BIND_STORAGE プラグマを使用すると、RAM の読み出しレイテンシを長くできます。
  • 書き込み操作は、出力ポート d_ced_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);
 ...
}

in1ap_fifo インターフェイスとして指定すると、Vitis HLS でアクセスがチェックされ、アクセスが順次でない場合はエラー メッセージが表示され、停止します。順次アドレスではないアドレス位置から読み出すには、ap_memory または bram インターフェイスを使用します。

読み出しおよび書き込みの両方に使用される場合、引数に ap_fifo インターフェイスは指定できません。ap_fifo インターフェイスは、入力引数または出力引数にのみ指定可能です。入力引数 in、出力引数 outap_fifo インターフェイスとして指定したデザインは、次の図のように動作します。

図 2. 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 になります。