レビュー
FPGA 設計では、FF 間に組み合わせロジックが必然的に散在します。では、これらの組み合わせロジックをどのように定量化して分析するか? 収束を最適化するにはどうすればよいでしょうか? RTL 設計から発生する可能性のある遅延を見積もるにはどうすればよいですか?
次に、簡単なプロジェクトを使用して実際のデモンストレーションを行います。
オリジナルプロジェクト
メインクロック周波数が 50M であると仮定して、一定の間隔で 80 秒をカウントする 32 カウントのタイマーを定義します。コードは次のようになります。
module TEST_TOP(
input clk_sys, // 50M
input rst ,
input plus ,
output reg [15:0] d
);
function [31:0]count_s( input [7:0] s_n );
count_s = 50_000_000* s_n ;
endfunction
reg [31:0] cnt_s ;
always@(posedge clk_sys or negedge rst)begin
if(rst)begin
cnt_s <= 'd0 ;
end else if(cnt_s >= count_s(80)) begin
cnt_s <= 'd0 ;
end else begin
cnt_s <= cnt_s + 1 ;
end
end
reg plus_d1,plus_d2;
always@(posedge clk_sys)begin
plus_d1 <= plus ;
plus_d2 <= plus_d1 ;
end
always@(posedge clk_sys)begin
if(s_carry_en)
d <= d + plus_d2 ;
end
endmodule
上記のコードで、各パスの遅延を取得するにはどうすればよいでしょうか? ザイリンクスは、ロジック レベル (logic_level) と呼ばれる評価方法を提供しています。これは、単純に直列の組み合わせロジックの数です。では、現在のデザインのロジック レベルを取得するにはどうすればよいでしょうか?
このコードが合成された後にファイルを開き、Tcl コンソールで前のクエリ コマンドを実行して、現在のデザインの各ロジック レベルのパスの数を取得します。
論理進行クエリコマンド
report_design_analysis -logic_level_distribution
-logic_level_dist_paths 5000 -name design_analysis_prePlace
次の図に示すように、最高の論理レベルは 12 であり、12 の論理レベルを持つパスが 4 つあります。
一般に、最も高いレベルのパスが最初に分析され、特定のパス情報はレポート コマンドを通じて取得できます。
Path1 を例として取り上げ、パスを選択してショートカット キー F4 を押すと、パスの概略図が表示されます。
回路図からわかるように、合計 1LUT5+2LUT6+8CARRY4 = 11 個のロジックレベルが 2 つの FF 間を通過しました。
まず概念を普及させます。
LUTとは何ですか? キャリーとは何ですか?
LUT: ルックアップ テーブル (ルックアップ テーブル) は、FPGA が組み合わせロジックを実装する方法であり、基礎となるリソースを説明する他のブログで説明されます。
お客様情報;
CARRY: キャリーチェーン、キャリーオーバーフロー、これは大学のマイコンの原理で習いますが、ビット幅が大きすぎるアキュムレータを接続するために存在します。
ロジックツール。
if-elseの判定条件はLUTで実現する必要があり、アキュムレータのキャリーはCARRYで実現する必要があります。
2 つの FF が直接接続されている場合、logic_level = 1。
上の図では 11 個の論理ユニットが挿入されているため、logic_level = 12;
このパスの合計伝送遅延は 3.015ns、ロジック遅延は 1.46ns です。
最適化の最初のステップ - 大きなビット幅のアキュムレータを分割する
書き方を変更して、32 ビット カウンタを 2 つの 16 ビット カウンタに分割してみましょう。
function [15:0]count_ms( input [7:0] ms_n );
count_ms = 50_000*ms_n ;
endfunction
function [15:0]count_s( input [7:0] s_n );
count_s = 1_000* s_n ;
endfunction
reg [15:0] cnt_ms ;
reg [15:0] cnt_s ;
always@(posedge clk_sys or negedge rst)begin
if(rst)begin
cnt_ms <= 'd0 ;
end else if(cnt_ms >= count_ms(1)) begin
cnt_ms <= 'd0 ;
end else begin
cnt_ms <= cnt_ms + 1 ;
end
end
always@(posedge clk_sys or negedge rst)begin
if(rst)begin
cnt_s <= 'd0 ;
end else if(cnt_ms >= count_ms(1)) begin
if(cnt_s >= count_s(80))
cnt_s <= 'd0 ;
else
cnt_s <= cnt_s + 1 ;
end
end
reg plus_d1,plus_d2;
always@(posedge clk_sys)begin
plus_d1 <= plus ;
plus_d2 <= plus_d1 ;
end
always@(posedge clk_sys)begin
if(cnt_ms >= count_ms(1))
d <= d + plus_d2 ;
end
再合成後の出力解析レポートには、新しいデザインの最大ロジック ステージ数が 7 つしかないことが示されています。
論理レベル 7 でパスを開きます
伝送経路は2LUT + 4 CARRY4となり、ロジック部はオリジナルに比べてLUT6が1つ、CARRY4が4つ削減されます。
ロジック遅延は以前の 1.46ns から 1.16ns に減少し、0.3ns、20% の減少です。
CARRY の削減は、32 ビット アキュムレータを 2 つの 16 ビット アキュムレータに分割しているため、理解しやすいです。
元の 1 レベルの累算は、分割後は 2 レベルの累算になります。分割後の各レベルの幅は 16 ビットのみであるため、FF の各レベル間で必要なキャリー チェーンもそれに応じて減少します。
このステップを通じて、次のことがわかります。
1. CARRY4 には 4 つの入力があります。アキュムレータまたはカウンタのビット幅が 4 を超えると、さらに 1 つの CARRY4 が消費されます。
たとえば、例 1 では、カウンタ定義は 32 ビットで、最終的に 8 つのキャリー チェーンを消費します。例 2 では、16 ビットに最適化された後、4 つのキャリー チェーンのみが消費されます。
2. 通常、全体の配線遅延とロジック遅延は 1:1 に近くなりますが、ロジック段数を減らすとロジック遅延が減少し、それに伴って配線遅延も減少します。
パスの特定のタイミング レポートをもう一度確認すると、ロジックの各レベルの特定の遅延がわかります。
Incr は追加された遅延、Path は中間の各ノードの瞬間です。
最適化の 2 番目のステップ - if-else 決定条件を簡素化する
前述のことから、アキュムレータのビット幅を縮小すると、キャリー チェーンのステージ数が大幅に削減され、それによってロジック遅延と配線遅延が削減されることがわかります。組み合わせロジック遅延を削減する他の方法はありますか? 組み合わせロジック遅延は、前から主に 1. キャリー チェーン、2. LUT の 2 つの部分で構成されます。
キャリーチェーンの段数はアキュムレータのビット幅で決まりますが、LUTの数はどうなるのでしょうか?LUT は組み合わせロジックの実装に使用され、LUT には 6 つの入力しかありませんが、組み合わせロジックの複雑さが高く、入力信号のビット幅が大きい場合、消費する必要のある LUT の数は自然に増加します。もっと。前回のプロジェクトを例に挙げると、assign の組み合わせロジック代入ステートメントを使用しませんでした。では、どこで組み合わせロジックが使用されているのでしょうか?
答えはif-elseの論理的な判定条件です。if-else 決定条件には複数ビット幅のデータ比較が含まれ、複数条件の入れ子により、決定機能を実現するための組み合わせロジックの複雑さが増加します。
元のコードの always ブロックは次のように記述されます。
always@(posedge clk_sys or negedge rst)begin
if(rst)begin
cnt_s <= 'd0 ;
end else if(cnt_ms >= count_ms(1)) begin
if(cnt_s >= count_s(80))
cnt_s <= 'd0 ;
else
cnt_s <= cnt_s + 1 ;
end
end
それを変更しましょう:
module TEST_TOP(
input clk_sys, // 50M
input rst ,
input plus ,
output reg [15:0] d
);
function [15:0]count_ms( input [7:0] ms_n );
count_ms = 50_000*ms_n ;
endfunction
function [15:0]count_s( input [7:0] s_n );
count_s = 1_000* s_n ;
endfunction
reg ms_carry_en ;
always@(posedge clk_sys)begin
if(cnt_ms == count_ms(1)-1)
ms_carry_en <= 'd1 ;
else
ms_carry_en <= 0 ;
end
reg s_carry_en ;
always@(posedge clk_sys)begin
if(cnt_s == count_s(80)-1)
s_carry_en <= 'd1 ;
else
s_carry_en <= 0 ;
end
reg [15:0] cnt_ms ;
reg [15:0] cnt_s ;
always@(posedge clk_sys or negedge rst)begin
if(rst)begin
cnt_ms <= 'd0 ;
end else if(ms_carry_en) begin
cnt_ms <= 'd0 ;
end else begin
cnt_ms <= cnt_ms + 1 ;
end
end
always@(posedge clk_sys or negedge rst)begin
if(rst)begin
cnt_s <= 'd0 ;
end else if(ms_carry_en) begin
if(s_carry_en)
cnt_s <= 'd0 ;
else
cnt_s <= cnt_s + 1 ;
end
end
組み合わせた効果を見てみましょう。
最大論理レベルはわずか 6 で、例 2 に比べて元の LUT4+LUT5 から 1 つの LUT1 に比べて 1 レベル減少します (最適化された判定条件は 1 ビット入力のみ)。
総遅延は以前の 2.356 から 1.451 に減少し、0.9ns 減少し、減少率は 38% に達します。
ロジック遅延は以前の1.16から減少しており、減少量はそれほど大きくありませんが、データパスデータを比較すると、最適化後は主に1つのLUT5とLUT5の前段と後段の接続が減少していることがわかります。
最適化の 3 番目のステップ - 代入式の分割 (速度重視の領域)
実際、これは理解するのが簡単で、1 ステップの操作を複数のステップの操作に分割し、パイプラインを構築することです。
例: S = A + B + C;
次のように設計できます。
S1 = A+B ;
S = S1+C 。
このステップの目的は、実際には 2 番目のステップの目的と似ています。代入式の右辺の実装方法も、LUT とキャリー チェーンの組み合わせによって実現されます。過度に複雑な代入式は、過度に長い組み合わせになります。ロジックカスケード。
元のルーチンにはそれほど長い代入式はなく、この状況は非常に一般的で理解しやすいため、当面は例を使って分析しません。
要約する
1. FF間のdata_delayは主に論理遅延と配線遅延の2つで構成され、論理段数が増加し、ノードの配線が必要となります。
増加すると、配線遅延もそれに応じて増加します。
2. 配線遅延とロジック遅延の比率は 1:1 に近い必要があります。
ロジック遅延が配線遅延の 50% を超える場合は、ロジック遅延を最適化してください。
配線遅延がロジック遅延の 50% を超える場合は、配線遅延を最適化してください (UG1292 を参照)。
遅延が満足できない場合は、最初にロジック遅延を最適化することをお勧めします。これは私たちができることだからです。
配線遅延はツールの戦略でしか最適化できませんが、多くの場合、組み合わせ論理に無理があり、同じ信号群が異なる列のCLBに配置され、配線が困難になる場合があります。
3. カウンタのビット幅が大きすぎると、キャリー チェーンが多すぎて、論理進行が多すぎます。
大きなビット幅のカウンタを避けるようにしてください。250M 以内の設計では、16 ビットを超えないことが最善です。
4 ビットのビット幅はキャリー チェーンを占有します。
4. 複雑な if - else 判定条件には複数レベルの LUT 実装が必要ですが、これにより論理進行が多すぎます。
設計内での if-else ネストと if-case ネストを避けるようにしてください。
if-else 判定条件の入力変数ビット幅が大きくなりすぎないように注意してください。
判定条件では複数条件の論理演算を行わないようにして、事前にクリックして単一ビット条件に変換してください。
5. 代入式が長すぎる場合は、設計パフォーマンスを向上させるために、代入式を複数レベルの処理に分割することを検討してください。
6. 組み合わせ論理系列の合理的な経験値: ≤2N (N は現在のクロック ドメインのクロック周期)。
最後に、ロジックレベルは可能な限り低くするべきではなく、ロジックレベルをある程度最適化すると追加のリソース消費が発生しますが、設計が性能要件を満たしていない場合は最適化が必要です。最終的に設計の収束が達成できず、戻って 1 つずつ修正して時間を無駄にしないように、設計時にその点を意識するのが最善です。