HLS コンパイラは、加算-乗算、乗算-加算、および AMA 演算 (および減算-乗算、乗算-減算) を識別して、物理デバイス上の DSP への割り当てと一致するようにします。HLS コンパイラは、次のようなプロセスで演算を DSP と一致させます。
- 必要に応じたインライン関数
- 共有の部分式を抽出
- DSP のビット幅制限を超えないファンアウトのない
add->mul
、mul->add
、add->mul->add
(add
はsub
にもなることあり) コード部分 - [Schedule]
- BIND_OP プラグマに従って DSP または LUT でのインプリメンテーションを選択
HLS コンパイラが演算や式を DSP インプリメンテーションに適合させる能力は、次によって異なります。
- データ型およびビット幅
- コード形式および式
- BIND_OP とほかのプラグマの使用
データ型およびビット幅
DSP マッチングは、ターゲット デバイスの DSP48 と DSP58 のデザイン上の制約によって制限されます。DSP48 に関する具体的な制限事項については、『UltraScale アーキテクチャ DSP スライス ユーザー ガイド』 (UG579) を、DSP58 に関する制限事項については、『Versal アダプティブ SoC DSP エンジン アーキテクチャ マニュアル』 (AM004) を参照してください。
たとえば、Versal デバイスの場合、DSP58 のポート幅は次のとおりです。
- B 24 ビット
- A 34 ビット
- D 27 ビット
- C 58 ビット
- P 58 ビット
コーディング スタイル
コードを記述する際は、次の点に注意してください。
- ビット幅は、中間結果を含め、DSP に適合するのに十分な小ささである必要があります。
- 共有の部分式を消去した結果であっても、ファンアウトは使用できません。たとえば、次のコードは
a*b
という部分式が抽出されるため、DSP 割り当てに一致しません。f1 = a*b+c; f2= a*b+d;
ヒント: この問題を回避するには、一致させる式だけを含むインライン処理された関数以外の関数を使用します。 - 指定されたレイテンシのインライン処理された関数以外の関数、たとえばレイテンシ 2 の MULADD は、II=1 のアキュムレータに一致させることはできません。その理由は、乗算器入力と加算器入力の両方が、累積出力が生成される 2 サイクル前に準備できている必要があるからです。その場合、MULADD または MAC 関数 (ある場合のみ) をインライン処理する必要があります。
BIND_OP およびその他のプラグマ
DSP マッチングでは、プラグマや指示子の中に、DSP にインプリメントされるコードのマッチングを妨げるものがあり、ほかのプラグマや指示子で実行できることがあります。次のコード例では、BIND_OP プラグマがあるため、実際に MULADD 式の DSP への割り当てがされないようになっています。mul
を代入すると、HLS コンパイラが MULADD 式を認識して代入されないようにできます。この場合、プラグマを削除すると、コンパイラが代入を実行するようになります。
static const int NFRAC = 14;
typedef ap_fixed<3+NFRAC, 3, AP_TRN, AP_WRAP> DATA_T;
…
ACC_T MAC( DATA_T din0, COEF_T coef, ACC_T acc ) {
acc = din0 * coef + acc;
#pragma HLS BIND_OP variable=acc op=mul impl=dsp latency=2
return acc;
}
void process ( DATA_T din, DATA_T* dout0) {
#pragma HLS pipeline II=1
…
LOOP_MAC: for (int i=0; i<l_COEFF; i++) {
acc = MAC (sr[tdl_index], coeff[i], acc);
tdl_index = tdl_index-1;
}
PIPELINE プラグマは、ループが演算式バランス調整を使用して展開されるようにしていますが、そのために DSP マッチングがされないようにもなっています。この場合、EXPRESSION_BALANCE OFF を追加して、演算式バランス調整をディスエーブルにすると、HLS コンパイラが DSP マッチング用の複数演算式を認識しやすくなります。次のコード例では、DSP マッチングが改善されます。
static const int NFRAC = 14;
typedef ap_fixed<3+NFRAC, 3, AP_TRN, AP_WRAP> DATA_T;
…
ACC_T MAC( DATA_T din0, COEF_T coef, ACC_T acc ) {
acc = din0 * coef + acc;
return acc;
}
void process ( DATA_T din, DATA_T* dout0) {
#pragma HLS pipeline II=1
#pragma HLS expression_balance off
…
LOOP_MAC: for (int i=0; i<l_COEFF; i++) {
acc = MAC (sr[tdl_index], coeff[i], acc);
tdl_index = tdl_index-1;
}