Vitis ツール フローでは、バースト アクセスを向上するため、Vitis HLS で m_axi
インターフェイス ポートのサイズを自動的に変更できます。ただし、ポート幅の自動変更は、標準 C データ型と 2 のべき乗サイズの struct
のみをサポートし、ポインターは予測される拡張バイト サイズにアライメントされます。ポート幅を自動的に大きくできない場合は、ベクターまたは任意精度 (AP) をポートのデータ型として使用すると、ポート幅を手動で変更できます。
重要: インターフェイスの構造体では、自動ポート幅拡張は実行されません。この機能をイネーブルにするには、構造体を個別の要素に分割する必要があります。
Vitis HLS では、次の 2 つのコマンドを使用してポート幅の自動変更を制御できます。
-
syn.interface.m_axi_max_widen_bitwidth=<N>
: M-AXI インターフェイスのバーストを指定した幅まで自動的に広げます。<N> の値には、0 ~ 1024 の 2 のべき乗を指定する必要があります。 -
syn.interface.m_axi_alignment_byte_size=<N>
: バースト幅の拡張には、アライメント プロパティも必要となります。m_axi
インターフェイスにマップされるポインターが少なくとも指定したバイト幅 (2 のべき乗) に揃えられるとするとします。これにより、自動バースト幅拡張が実行されやすくなります。
Vitis カーネル フローでは、自動ポート幅変更はデフォルトでは次のように設定されています。
syn.interface.m_axi_max_widen_bitwidth=512
syn.interface.m_axi_alignment_byte_size=64
Vivado IP フローでは、この機能はデフォルトでディスエーブルになっています。
syn.interface.m_axi_max_widen_bitwidth=0
syn.interface.m_axi_alignment_byte_size=1
自動ポート幅サイズ変更は、ツールでバースト アクセスが認識された場合にのみポートのサイズが変更されます。そのため、AXI バースト転送 に説明されているバーストのすべての前提条件が、ポート サイズ変更でも満たされている必要があります。これらの条件には、次が含まれます。
- アクセスするメモリのロケーションおよび時間が単調に増加する必要があります。以前にアクセスされた 2 つのメモリ ロケーション間のメモリ ロケーションにアクセスすることはできません (オーバーラップなしということ)。
- グローバル メモリからのアクセス パターンはシーケンシャル順で、次の追加要件に従っている必要があります。
- 順次アクセスは、プリミティブ型またはベクター以外の 2 べき乗サイズの集合型である必要があります。
- シーケンシャル アクセスの開始は、拡張されたワード サイズにアラインメントする必要があります。
- シーケンシャル アクセスの長さはその拡張係数で割り切れるようにする必要があります。
次のコード例は、その後の計算で使用されます。
vadd_pipeline:
for (int i = 0; i < iterations; i++) {
#pragma HLS LOOP_TRIPCOUNT min = c_len/c_n max = c_len/c_n
// Pipelining loops that access only one variable is the ideal way to
// increase the global memory bandwidth.
read_a:
for (int x = 0; x < N; ++x) {
#pragma HLS LOOP_TRIPCOUNT min = c_n max = c_n
#pragma HLS PIPELINE II = 1
result[x] = a[i * N + x];
}
read_b:
for (int x = 0; x < N; ++x) {
#pragma HLS LOOP_TRIPCOUNT min = c_n max = c_n
#pragma HLS PIPELINE II = 1
result[x] += b[i * N + x];
}
write_c:
for (int x = 0; x < N; ++x) {
#pragma HLS LOOP_TRIPCOUNT min = c_n max = c_n
#pragma HLS PIPELINE II = 1
c[i * N + x] = result[x];
}
}
}
}
上記のコードの自動最適化の幅は、次の 3 段階で実行されます。
- ツールにより read_a ループのアクセス パターン数がチェックされます。1 つのループ反復で 1 回アクセスされるので、最適化によりインターフェイスのビット幅が 32= 32 × 1 (int 変数のビット幅 × アクセス) と決定されます。
- 次の式の項を使用して、
config_interface -m_axi_max_widen_bitwidth 512
で指定されたデフォルトの最大値を到達することが試みられます。length = (ceil((loop-bound of index inner loops) * (loop-bound of index - outer loops)) * #(of access-patterns))
- 上記のコードでは、ツールは不完全なループ ネストをサポートしています。a および b が同じポートにバンドルされる場合、ツールは競合のために a および b のバーストを延長しません。a および b が異なるポートにバンドルされる場合、ツールは a および b のバーストを外側のループに延長します。計算式は次のように短縮できます。
length = (ceil((loop-bound of index inner loops)) * #(of access-patterns))
または、長さ = ceil(128) × 32 = 4096 となります。
- 上記のコードでは、ツールは不完全なループ ネストをサポートしています。a および b が同じポートにバンドルされる場合、ツールは競合のために a および b のバーストを延長しません。a および b が異なるポートにバンドルされる場合、ツールは a および b のバーストを外側のループに延長します。計算式は次のように短縮できます。
- 計算された長さが 2 のべき乗かどうか確認され、2 のべき乗の場合は長さが
syn.interface.m_axi_max_widen_bitwidth
で指定された幅に制限されます。
ポート幅の自動変更機能を使用する前に、その利点と問題点について考慮してください。この機能は、データ型サイズではなく、アクセス スループットを向上させます。大きなベクターをバッファリングして、データをデータパス サイズに合わせてシフトする必要があることがあるので、リソースも増えます。