このページは、タイミングに関する連載ページの一部です。タイミング制約(timing constraints)の背後にある理論の簡単な紹介と、クロック周期制約に関する最初のページを終えたところで、今回はこの制約に関するいくつかの現実的なシナリオを見ていきます。
次のステップ:PLL の使用
前のページで示した例では、外部クロックピンがロジックに直接接続されていました。実際の設計のほとんどでは、何らかの PLL を使ってロジック用のクロックを生成します。その最もわかりやすい理由は、ロジックが必要とする周波数が外部クロックの周波数と異なることです。しかし、PLL を使うことは、外部クロックに含まれる不完全さ、特にジッタ(jitter)を取り除くという点でも役立ちます。
PLL は、次のような Verilog コードで回路に追加できます。
module top(
input clk,
input foo,
output reg bar_reg
);
reg foo_reg;
reg bar;
wire pll_clk;
clk_wiz_0 pll_i
(.clk_in1(clk),
.clk_out1(pll_clk));
always @(posedge pll_clk)
begin
foo_reg <= foo;
bar <= !foo_reg;
bar_reg <= bar;
end
endmodule
これは前の例と同じですが、今回はフリップフロップのクロックが @clk ではなく @pll_clk になっています。PLL は Vivado の Clocking Wizard IP によって生成されます。この Verilog コードでは、clk_wiz_0 という名前のモジュールとして使われています。
この例では、Clocking Wizard は 250 MHz のリファレンスクロックを受け取り、出力ポート(つまり @clk_out1)に 125 MHz のクロックを生成するように設定されています。この例を簡単にするため、clk_wiz_0 にはリセット入力も locked 出力もありません。実際の設計のほとんどでは、これらのポートを有効にして使うことをお勧めします。
clk_wiz_0 にはもう 1 つ、位相調整(phase alignment)オプションが有効になっているという点があります。このオプションにより、@pll_clk のクロックエッジが @clk のクロックエッジに揃えられます。このオプションは、設計に外部クロックと同期した I/O ポートがある場合に役立ちます。位相調整が有効だと、外部クロックと内部クロックのタイミング関係が予測可能になるからです。これは、外部クロックを基準としたタイミング要件を満たす必要がある I/O ポートで特に便利です。
Xilinx の用語を正確に言うと、Xilinx の FPGA には 2 種類の PLL があります。1 つは PLL と呼ばれるもので、もう 1 つは MMCM と呼ばれるものです。この例に関して言えば、その違いは重要ではありません。clk_wiz_0 は MMCM ですが、ここではわかりやすくするために PLL という言葉を使います。
ここで PLL について述べていることは、市場に出回っているすべての FPGA に当てはまることを、もう一度強調しておきます。この例は Vivado で示していますが、clk_wiz_0 とまったく同じ動作をする PLL は、どの FPGA 向けにも生成できます。
PLL を使う場合のタイミング制約
PLL を使う場合のタイミング制約について最も重要なことは、特別なことをする必要がないということです。タイミング制約は外部ピン(この例では @clk)に対して記述します。PLL が別の周波数のクロックを生成する場合、それを考慮するのはツールの役目です。
もう一度言います。PLL を使うからといって、追加のタイミング制約を書く必要は決してありません。もし書く必要があると感じたなら、設計に何か問題がある可能性が高いです。追加のタイミング制約で問題を「修正」しても、本当の問題は解決しません。
したがって、前と同じように、タイミング制約は次の 1 行だけです。
create_clock -period 4.000 -name clk [get_ports clk]
Quartus を使う人は、このページで説明している落とし穴に注意してください。
PLL を使った場合のタイミングレポート
それでは、前のページの例と同じパスについてのタイミングレポートを見てみましょう。唯一の違いは、上で示したように PLL が追加されたことです。ここでは、関連するパスの解析を、タイミングレポートに現れるのと同じ順序で示します。まず、解析結果の要約です。
Slack (MET) : 7.288ns (required time - arrival time) Source: foo_reg_reg/C (rising edge-triggered cell FDRE clocked by clk_out1_clk_wiz_0 {rise@0.000ns fall@4.000ns period=8.000ns}) Destination: bar_reg__0/D (rising edge-triggered cell FDRE clocked by clk_out1_clk_wiz_0 {rise@0.000ns fall@4.000ns period=8.000ns}) Path Group: clk_out1_clk_wiz_0 Path Type: Setup (Max at Slow Process Corner) Requirement: 8.000ns (clk_out1_clk_wiz_0 rise@8.000ns - clk_out1_clk_wiz_0 rise@0.000ns) Data Path Delay: 0.669ns (logic 0.382ns (57.100%) route 0.287ns (42.900%)) Logic Levels: 1 (LUT1=1) Clock Path Skew: -0.048ns (DCD - SCD + CPR) Destination Clock Delay (DCD): -0.715ns = ( 7.285 - 8.000 ) Source Clock Delay (SCD): -0.616ns Clock Pessimism Removal (CPR): 0.051ns Clock Uncertainty: 0.062ns ((TSJ^2 + DJ^2)^1/2) / 2 + PE Total System Jitter (TSJ): 0.071ns Discrete Jitter (DJ): 0.103ns Phase Error (PE): 0.000ns Clock Net Delay (Source): 1.389ns (routing 0.002ns, distribution 1.387ns) Clock Net Delay (Destination): 1.218ns (routing 0.002ns, distribution 1.216ns)
いくつか注目すべき違いがあります。まず、Requirement が以前の 4 ns ではなく 8 ns になっています。これは当然のことです。PLL の出力が 125 MHz だからです。ツールはこの出力に対して、クロック周期 8 ns のタイミング制約を自動的に追加で作成しました。クロック周期が 4 ns 長くなり、データパスは変わらないため、スラック(slack)は約 4 ns 増加しています。
自動生成されたタイミング制約を示すもう 1 つの証拠は、このレポートの Path Group が「clk_out1_clk_wiz_0」になっていることです。以前は「clk」でした。実際、以前「clk」と書かれていたすべての箇所が、このレポートでは「clk_out1_clk_wiz_0」になっています。自動生成されたタイミング制約がタイミングレポートでどのように表されるかについては、後で複数クロックの文脈で説明します。
PLL による小さな影響として、Clock Uncertainty が 0.062 ns に増えています。前の例では 0.035 ns でした。これは、Discrete Jitter がゼロではなく 0.103 ns になったためです。
それでは、タイミング解析本体に移りましょう。今回は、ソースクロックパス、データパス、宛先クロックパスを、実際のレポートに現れるとおりにまとめて示します。
Location Delay type Incr(ns) Path(ns) Netlist Resource(s)
------------------------------------------------------------------- -------------------
(clock clk_out1_clk_wiz_0 rise edge)
0.000 0.000 r
AG12 0.000 0.000 r clk (IN)
net (fo=0) 0.000 0.000 pll_i/inst/clkin1_ibuf/I
AG12 INBUF (Prop_INBUF_HRIO_PAD_O)
0.738 0.738 r pll_i/inst/clkin1_ibuf/INBUF_INST/O
net (fo=1, routed) 0.105 0.843 pll_i/inst/clkin1_ibuf/OUT
AG12 IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O)
0.049 0.892 r pll_i/inst/clkin1_ibuf/IBUFCTRL_INST/O
net (fo=1, routed) 0.975 1.867 pll_i/inst/clk_in1_clk_wiz_0
MMCME3_ADV_X1Y0 MMCME3_ADV (Prop_MMCME3_ADV_CLKIN1_CLKOUT0)
-4.474 -2.607 r pll_i/inst/mmcme3_adv_inst/CLKOUT0
net (fo=1, routed) 0.501 -2.106 pll_i/inst/clk_out1_clk_wiz_0
BUFGCE_X1Y0 BUFGCE (Prop_BUFCE_BUFGCE_I_O)
0.101 -2.005 r pll_i/inst/clkout1_buf/O
X2Y0 (CLOCK_ROOT) net (fo=3, routed) 1.389 -0.616 pll_clk
SLICE_X49Y58 FDRE r foo_reg_reg/C
------------------------------------------------------------------- -------------------
SLICE_X49Y58 FDRE (Prop_EFF2_SLICEL_C_Q)
0.138 -0.478 f foo_reg_reg/Q
net (fo=1, routed) 0.241 -0.237 foo_reg
SLICE_X49Y58 LUT1 (Prop_D5LUT_SLICEL_I0_O)
0.244 0.007 r bar__0_i_1/O
net (fo=1, routed) 0.046 0.053 p_0_in
SLICE_X49Y58 FDRE r bar_reg__0/D
------------------------------------------------------------------- -------------------
(clock clk_out1_clk_wiz_0 rise edge)
8.000 8.000 r
AG12 0.000 8.000 r clk (IN)
net (fo=0) 0.000 8.000 pll_i/inst/clkin1_ibuf/I
AG12 INBUF (Prop_INBUF_HRIO_PAD_O)
0.515 8.515 r pll_i/inst/clkin1_ibuf/INBUF_INST/O
net (fo=1, routed) 0.066 8.581 pll_i/inst/clkin1_ibuf/OUT
AG12 IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O)
0.034 8.615 r pll_i/inst/clkin1_ibuf/IBUFCTRL_INST/O
net (fo=1, routed) 0.873 9.488 pll_i/inst/clk_in1_clk_wiz_0
MMCME3_ADV_X1Y0 MMCME3_ADV (Prop_MMCME3_ADV_CLKIN1_CLKOUT0)
-3.934 5.554 r pll_i/inst/mmcme3_adv_inst/CLKOUT0
net (fo=1, routed) 0.422 5.976 pll_i/inst/clk_out1_clk_wiz_0
BUFGCE_X1Y0 BUFGCE (Prop_BUFCE_BUFGCE_I_O)
0.091 6.067 r pll_i/inst/clkout1_buf/O
X2Y0 (CLOCK_ROOT) net (fo=3, routed) 1.218 7.285 pll_clk
SLICE_X49Y58 FDRE r bar_reg__0/C
clock pessimism 0.051 7.336
clock uncertainty -0.062 7.274
SLICE_X49Y58 FDRE (Setup_DFF2_SLICEL_C_D)
0.067 7.341 bar_reg__0
-------------------------------------------------------------------
required time 7.341
arrival time -0.053
-------------------------------------------------------------------
slack 7.288
前の例と比較すると、パス上の唯一の違いは、外部クロックピンとグローバルクロックバッファの間に PLL(レポートでは MMCME3_ADV_X1Y0 と表示される)が挿入されたことです。
この PLL は劇的な効果をもたらします。ソースクロックパスでは PLL の遅延が −4.474 ns、宛先クロックパスでは同じ遅延が −3.934 ns です。この負の遅延は、PLL がクロックエッジを調整し、グローバルクロックが入力ピンのクロックよりわずかに早く現れるようにしていることを表しています。ソースクロックパスでは、グローバルクロックバッファ出力でのクロックの合計遅延が −0.616 ns であることに注意してください。同じ遅延は、宛先クロックパスでは 7.285 ns です。これは 2 番目のクロックエッジ(8 ns)より 0.715 ns 早いことになります。
言い換えると、外部クロックピンと(ロジックに供給される)グローバルクロックの時間差は、両方のクロックパスではとんど同じになります。一方のクロックパスは最大遅延で計算され、もう一方のクロックパスは最小遅延で計算されているにもかかわらず、合計結果はほぼ同じです。
これは偶然ではありません。PLL はグローバルクロック出力を基準として使うため、クロック入力ピンとの関係が保証されるようにグローバルクロックバッファ入力の位相が調整されます。最小遅延と最大遅延の差は PLL によって補償されます。タイミング計算では、最速ケースと最遅ケースの差がわずか 0.1 ns であるという事実として、これが反映されています。前の例では PLL がなかったため、この差ははるかに大きくなっていました(0.575 ns。前のページの「クロック悲観性の除去」を参照)。
グローバルクロックがなぜ外部入力より約 0.6 ns 前になるように調整されるのか、他の値ではないのかは、また別の話です。多くの場合、この調整によって I/O ピンに関連するタイミング制約を達成しやすくなるため、ツールはこの選択を自動的に行います。とはいえ、どの FPGA にもこの遅延を操作するオプションはあります。
関連する 2 つのクロック
論理設計では、複数のクロックが必要になることがよくあります。FPGA 設計に複数のクロックが存在することは、それ自体が 1 つのテーマであり、クロックドメインの紹介で説明しています。クロックドメイン(clock domain)とタイミングは切り離せない関係にあるため、ここに進む前に(簡単にでもよいので)その紹介に目を通すことをお勧めします。この 2 つのテーマは密接に関係しているため、その紹介ページとこの連載の間には重複する内容がいくつかあります。
以下の議論では、「信号 X は @clk に同期している(synchronous)」のような表現をよく使います。これは、X が、「clk」という名前のクロックの立ち上がりエッジにのみ応答して値が変化するフリップフロップの出力であることを意味します(非同期リセットを除きますが、ここでは関係ありません)。もちろん、同じクロックに応答するフリップフロップの出力が 2 つあれば、その 2 つの信号は「同じクロックに同期している」ことになります。
それでは、同じ PLL によって生成される 2 つのクロックを見てみましょう。これは、ほとんどの場合、この 2 つのクロックが関連クロック(related clocks)と見なされるため、興味深い話題です。なぜこれが興味深いのかを理解するために、一方のクロックに同期するフリップフロップと、もう一方のクロックに同期する別のフリップフロップがあるとしましょう。この場合、これらのフリップフロップ間で信号をあたかも同じクロックに同期しているかのように接続しても問題ありません。FPGA ツールが、この場合のタイミング要件が満たされることを保証します。
複数のクロックの扱い方をより深く理解するために、関連クロックと無関係クロック(unrelated clocks)についての専用ページがあります。そのページはクロックドメイン横断(clock domain crossing)の導入です。ここでは、関連クロックのタイミング的側面、特にそのようなクロックに関するタイミングレポートに焦点を当てます。
以下のタイミングレポートを生成するために、別の PLL(つまり Clocking Wizard IP)を例で使いました。この新しい PLL の名前は clk_wiz_1 です。使用した Verilog コードは次のとおりです。
module top(
input clk,
input foo,
output reg bar_reg
);
reg foo_reg;
reg bar;
wire pll_clk_8, pll_clk_6;
clk_wiz_1 pll_i
(.clk_in1(clk),
.clk_out1(pll_clk_8),
.clk_out2(pll_clk_6));
always @(posedge pll_clk_8)
foo_reg <= foo;
always @(posedge pll_clk_6)
begin
bar <= !foo_reg;
bar_reg <= bar;
end
前と同様、この PLL の入力(つまり @clk)は 250 MHz ですが、出力が 2 つあります。1 つは @pll_clk_8 に接続されており、125 MHz で動作します(つまりクロック周期は 8 ns。それが信号名の由来です)。これは前の例の @pll_clk とまったく同じです。2 つ目の出力は @pll_clk_6 に接続されており、クロック周期は 6 ns、つまり約 166.67 MHz です。
@pll_clk_8 と @pll_clk_6 は同じ PLL によって生成されるため、これらは関連クロックです。
clk_wiz_1 も位相調整オプションが有効になっています。特に、前の例と一貫性を持たせるためです。疑問に思う方もいるかもしれませんが、タイミング制約は依然として 1 つだけで、内容も前と同じです。
create_clock -period 4.000 -name clk [get_ports clk]
クロックサマリーを理解する
すべてのクロックに関する情報は、タイミングレポートの冒頭にまとめられています。今になってこの話を持ち出したのは、クロックサマリーはクロックが複数あるときのほうが興味深いからです。すべての FPGA ツールは、この種のサマリーをレポートに生成します。常にこの部分に目を通すことをお勧めします。
-------------------------------------------------------------------------
| Clock Summary
| -------------
-------------------------------------------------------------------------
Clock Waveform(ns) Period(ns) Frequency(MHz)
----- ------------ ---------- --------------
clk {0.000 2.000} 4.000 250.000
clk_out1_clk_wiz_1 {0.000 4.000} 8.000 125.000
clk_out2_clk_wiz_1 {0.000 3.000} 6.000 166.667
clkfbout_clk_wiz_1 {0.000 2.000} 4.000 250.000
この部分の主な利点は、理解しやすく、タイミング制約に関する最も一般的な間違い、つまりクロックの周波数が正しいかどうかを確認しやすいことです。
このクロックサマリーは、タイミング制約が正しく解釈されたことを示しています。clk という名前で外部クロックが 1 つ定義され、そのクロック周期は 4 ns です。さらに、派生クロックが 3 つあります。clk_out1_clk_wiz_1、clk_out2_clk_wiz_1、clkfbout_clk_wiz_1 です。その名前が示すとおり、これらは clk_wiz_1 という名前の PLL のために自動的に生成されました。
最初の 2 つのクロック(clk_out1_clk_wiz_1 と clk_out2_clk_wiz_1)は PLL の 2 つの出力です。3 つ目のクロック(clkfbout_clk_wiz_1)は、グローバルクロックの位相を外部クロックに合わせるために PLL が使うものです。clkfbout_clk_wiz_1 の周波数は @clk と同じです。
位相調整オプションが有効な場合、PLL のフィードバッククロック(clkfbout_clk_wiz_1)はグローバルクロックバッファに接続されます。PLL は常に入力クロックとフィードバッククロックを同期させる(2 つのクロックを整列させるか、それらの間に一定の遅延を保つ)ため、clkfbout_clk_wiz_1 がグローバルクロックであるということは、入力クロックと他の出力クロックとの間にも既知の遅延が保証されることを意味します。
clk_out1_clk_wiz_1、clk_out2_clk_wiz_1、clkfbout_clk_wiz_1 は、実際に存在するクロックを定義しているわけではないことに注意することが重要です。これらは、ソフトウェアがタイミング計算に使うクロックのシンボルにすぎません。これらのクロックが理論上のものであることを示す 1 つの証拠は、クロックサマリーに示されている波形です。この波形は、各クロックのデューティサイクルを反映しています。しかし、4 つのクロックすべて(clk と 3 つの理論クロック)の立ち上がりエッジがちょうど 0 ns にあることは、何の意味もありません。特に、このことは 4 つのクロックが完全に整列していることを意味するものではありません。たとえ整列していたとしても、それはタイミング計算を通して見えるものであり、現実の整列は完全ではありません。
これらの理論クロックがどのように使われるかについては、後で、これらのクロックのうち 2 つを含むタイミング計算に関連して説明します。
これらの理論クロックについてもう 1 つ重要なことは、それらを作成するための明示的なタイミング制約が存在しないということです。clk_out1_clk_wiz_* の作成は、設計ソースにもツールが生成するファイルにもどこにも存在しません。ほとんどの場合、そのようなタイミング制約を書こうとすることは誤りです。そうすると、クロックパスの遅延が正しく考慮されないからです。そのような制約を書くと、ツールはクロック間の相対タイミングを誤って計算し、関連クロックドメイン間のパスが正しく計算されなくなります。
したがって、繰り返しになりますが、PLL のすべての出力クロックに対するタイミング制約は、ただ 1 つのタイミング制約から自動的に生成されるべきなのです。
関連する 2 つのクロックのタイミングレポート
上の Verilog コードから明らかなように、@foo_reg は @pll_clk_8 に同期し、@bar は @pll_clk_6 に同期しています。したがって、@bar を更新するステートメントはクロックドメイン横断を伴います。
bar <= !foo_reg;
2 つのクロックは関連クロックなので、ツールはこの計算(tsu 用)によって @bar のタイミング要件が満たされることを保証します。
Slack (MET) : 0.475ns (required time - arrival time)
Source: foo_reg_reg/C
(rising edge-triggered cell FDRE clocked by clk_out1_clk_wiz_1 {rise@0.000ns fall@4.000ns period=8.000ns})
Destination: bar_reg__0/D
(rising edge-triggered cell FDRE clocked by clk_out2_clk_wiz_1 {rise@0.000ns fall@3.000ns period=6.000ns})
Path Group: clk_out2_clk_wiz_1
Path Type: Setup (Max at Slow Process Corner)
Requirement: 2.000ns (clk_out2_clk_wiz_1 rise@18.000ns - clk_out1_clk_wiz_1 rise@16.000ns)
Data Path Delay: 1.160ns (logic 0.307ns (26.466%) route 0.853ns (73.534%))
Logic Levels: 1 (LUT1=1)
Clock Path Skew: -0.250ns (DCD - SCD + CPR)
Destination Clock Delay (DCD): -0.681ns = ( 17.319 - 18.000 )
Source Clock Delay (SCD): -0.600ns = ( 15.400 - 16.000 )
Clock Pessimism Removal (CPR): -0.169ns
Clock Uncertainty: 0.182ns ((TSJ^2 + DJ^2)^1/2) / 2 + PE
Total System Jitter (TSJ): 0.071ns
Discrete Jitter (DJ): 0.103ns
Phase Error (PE): 0.120ns
Clock Net Delay (Source): 1.369ns (routing 0.002ns, distribution 1.367ns)
Clock Net Delay (Destination): 1.208ns (routing 0.002ns, distribution 1.206ns)
Location Delay type Incr(ns) Path(ns) Netlist Resource(s)
------------------------------------------------------------------- -------------------
(clock clk_out1_clk_wiz_1 rise edge)
16.000 16.000 r
AG12 0.000 16.000 r clk (IN)
net (fo=0) 0.000 16.000 pll_i/inst/clkin1_ibuf/I
AG12 INBUF (Prop_INBUF_HRIO_PAD_O)
0.738 16.738 r pll_i/inst/clkin1_ibuf/INBUF_INST/O
net (fo=1, routed) 0.105 16.843 pll_i/inst/clkin1_ibuf/OUT
AG12 IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O)
0.049 16.892 r pll_i/inst/clkin1_ibuf/IBUFCTRL_INST/O
net (fo=1, routed) 0.975 17.867 pll_i/inst/clk_in1_clk_wiz_1
MMCME3_ADV_X1Y0 MMCME3_ADV (Prop_MMCME3_ADV_CLKIN1_CLKOUT0)
-4.438 13.429 r pll_i/inst/mmcme3_adv_inst/CLKOUT0
net (fo=1, routed) 0.501 13.930 pll_i/inst/clk_out1_clk_wiz_1
BUFGCE_X1Y1 BUFGCE (Prop_BUFCE_BUFGCE_I_O)
0.101 14.031 r pll_i/inst/clkout1_buf/O
X2Y0 (CLOCK_ROOT) net (fo=1, routed) 1.369 15.400 pll_clk_8
SLICE_X49Y58 FDRE r foo_reg_reg/C
------------------------------------------------------------------- -------------------
SLICE_X49Y58 FDRE (Prop_EFF_SLICEL_C_Q)
0.139 15.539 f foo_reg_reg/Q
net (fo=1, routed) 0.807 16.346 foo_reg
SLICE_X49Y58 LUT1 (Prop_D5LUT_SLICEL_I0_O)
0.168 16.514 r bar__0_i_1/O
net (fo=1, routed) 0.046 16.560 p_0_in
SLICE_X49Y58 FDRE r bar_reg__0/D
------------------------------------------------------------------- -------------------
(clock clk_out2_clk_wiz_1 rise edge)
18.000 18.000 r
AG12 0.000 18.000 r clk (IN)
net (fo=0) 0.000 18.000 pll_i/inst/clkin1_ibuf/I
AG12 INBUF (Prop_INBUF_HRIO_PAD_O)
0.515 18.515 r pll_i/inst/clkin1_ibuf/INBUF_INST/O
net (fo=1, routed) 0.066 18.581 pll_i/inst/clkin1_ibuf/OUT
AG12 IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O)
0.034 18.615 r pll_i/inst/clkin1_ibuf/IBUFCTRL_INST/O
net (fo=1, routed) 0.873 19.488 pll_i/inst/clk_in1_clk_wiz_1
MMCME3_ADV_X1Y0 MMCME3_ADV (Prop_MMCME3_ADV_CLKIN1_CLKOUT1)
-3.890 15.598 r pll_i/inst/mmcme3_adv_inst/CLKOUT1
net (fo=1, routed) 0.422 16.020 pll_i/inst/clk_out2_clk_wiz_1
BUFGCE_X1Y0 BUFGCE (Prop_BUFCE_BUFGCE_I_O)
0.091 16.111 r pll_i/inst/clkout2_buf/O
X2Y0 (CLOCK_ROOT) net (fo=2, routed) 1.208 17.319 pll_clk_6
SLICE_X49Y58 FDRE r bar_reg__0/C
clock pessimism -0.169 17.150
clock uncertainty -0.182 16.967
SLICE_X49Y58 FDRE (Setup_DFF2_SLICEL_C_D)
0.067 17.034 bar_reg__0
-------------------------------------------------------------------
required time 17.034
arrival time -16.560
-------------------------------------------------------------------
slack 0.475
前述のように、タイミング計算は仮想的な実験です。そこでは、クロックエッジと一緒に仮想的なストップウォッチがスタートします。前の例では、このストップウォッチは 0 ns でスタートしました。しかし、この計算では、16 ns のクロックエッジとともにスタートします。これは、2 つのクロックのクロック周期が等しくないためです。この計算は、1 つ目のクロックと 2 つ目のクロックの最悪ケースの組み合わせに対して行われます。
1 つ目のクロックの立ち上がりエッジは、0 ns、8 ns、16 ns、24 ns、... です。2 つ目のクロックの立ち上がりエッジは、0 ns、6 ns、12 ns、18 ns、24 ns、... です。したがって、1 つ目のクロックと 2 つ目のクロックの間の最小時間間隔は、1 つ目のクロックの 16 ns から 2 つ目のクロックの 18 ns までです。このタイミング計算が調べているのは、まさにこの状況です。
これは、データパスに許される時間が約 2 ns しかないことを意味し、いわば 500 MHz 相当です。これは非常に厳しい要件ですが、データパス内に LUT が 1 つしかなく、両方のフリップフロップが同じスライス上にあるため、この目標を達成するのは簡単でした。しかし、この例は、関連クロックには互いにうまく調和する周波数を選ぶことがなぜ重要かを示しています。多くの場合、一方のクロックの周波数は、もう一方のクロックの周波数の整数倍になるように選ばれます。そうすれば、この例のような 2 ns の隙間というシナリオを避けられます。
ちなみに、うまく調和する周波数を選べない場合は、クロックを無関係クロックとして扱うという解決策があります。
派生クロック
先ほど、clk_out1_clk_wiz_1 と clk_out2_clk_wiz_1 は理論上のクロックだと述べましたが、そのことがタイミングレポートに次のように反映されています。両方のパスが、外部ピン(AG12)を出発点として計算されていることに注目してください。どうしてそんなことがあり得るのでしょうか。実際には、このピン上の信号は基準クロックであり、これらの 2 つのクロックのいずれでもありません。
たとえば clk_out1_clk_wiz_1 を考えてみましょう。この計算の背後にある考え方は、外部ピンに 125 MHz のクロックがあるかのように仮定するというものです。実際には、125 MHz のクロックは PLL の出力、つまり MMCME3_ADV_X1Y0 の出力にしか存在しません。しかし、タイミング計算に PLL の周波数変換を含める代わりに、理論クロックが使われます。このクロックは、0 ns から始まる理想的な波形を持ちます。PLL は、どのクロックの周波数も変えず、遅延を追加するだけのものとして扱われます。
つまり、理論クロック(たとえば clk_out1_clk_wiz_1)は、クロックの波形(周波数、デューティサイクル、ジッタなど)を定義します。しかし、この理論クロックは、FPGA 上に実際の信号として存在する他のクロックとのタイミング関係を定義するものではありません。
では、@pll_clk_6 と @pll_clk_8 が実際に整列していることを、どうやって確認できるのでしょうか。答えは、これらのクロックの実際のタイミングと理想的なタイミングを比較することにあります。たとえば、上の計算では、clk_out1_clk_wiz_1 の理論クロックエッジは 16 ns にあります。一方、clk_out2_clk_wiz_1 のクロックエッジは 18 ns にあり、2 ns 遅くなっています。次に、グローバルクロックツリーの出力でのクロックエッジを比較してみましょう。タイミングレポートによると、1 つ目のクロックのエッジは 15.400 ns に到着します。2 つ目のクロックエッジについては、レポートは 17.319 ns と述べています。したがって、計算上は時間差が 2 ns ではなく 1.919 ns になります。これは理想的な差よりわずか 0.081 ns 小さいだけです。つまり、これらのクロックは間違いなく整列しています。
クロックが 1 つだけだった前の例と比較してみましょう。2 つのクロックエッジ間の理想的な時間差はクロック周期、つまり 8 ns でした。しかし、関連するタイミングレポート(上記参照)によると、1 つ目のクロックエッジは −0.616 ns に、2 つ目のクロックエッジは 7.285 ns に到着しました。理想的な時間差は 8 ns でしたが、実際には 7.901 ns でした。つまり、2 つ目のクロックエッジは期待より 0.099 ns 早かったのです。
つまり、関連する 2 つのクロックの場合、理想的な時間差からのずれは 0.081 ns です。クロックが 1 つだけの場合、このずれはほぼ同じ 0.099 ns でした。どちらの場合も、このずれの理由は、1 つ目のクロックエッジの計算に最大遅延が使われ、2 つ目のクロックエッジには最小遅延が使われるためです。
したがって、結論として、@pll_clk_6 と @pll_clk_8 は、あたかも 1 つのクロックであるかのような精度で整列しています。
これらのクロックは、PLL の位相調整を有効にするオプションがなくても、互いに整列していたことに注意してください。PLL の出力は、通常、どうせ整列しています。この整列は、ファンアウト(fan-out)に関係なくほぼ同じ遅延を持つグローバルクロックバッファを使うことで保証されています。つまり、各クロックバッファがいくつの論理エレメントに接続されているかに関係なく、PLL の出力から宛先までの遅延はほぼ同じなのです。
関連クロックについて学んだこと
このタイミングレポートの解析は、関連する 2 つのクロックドメイン間のパスが、クロックドメイン内のパスとほぼ同等であることを示しています。とはいえ、完全に同じというわけではありません。特に、Clock Uncertainty は 0.062 ns から 0.182 ns に増えています。各クロックにそれぞれジッタがあり、さらに整列も完全ではないからです。
また、このタイミングレポートは、2 つのクロックの整列がタイミング計算にどのように反映されるかも示しました。
FPGA 設計にクロックドメイン横断がある場合、タイミングレポートでこれらのクロック間の相互作用を調べることをお勧めします。その目的は、ツールが期待どおりにクロックを扱っていることを確認することです。確認すべき最も重要な点は次の 2 つです。
- ロジックが 2 つのクロックを関連クロックと見なしている場合:これらのクロック間のすべてのパスについてタイミング計算が行われていることを確認します。
- ロジックが 2 つのクロックを無関係クロックと見なしている場合:これらの 2 つのクロック間のパスについてタイミング計算が行われていないことを確認します。
Vivado は Clock Interaction Report を生成でき、これは設計内のクロックドメイン横断と、各横断がツールによってどのように扱われるかをグラフィカルに表示します。他の FPGA ツールにも同様の機能があります。たとえば Quartus Pro の CDC Viewer です。可能であれば、このレポートを作成して確認することをお勧めします。
もう 1 つ確認すべきことは、クロックが整列しているかどうかです。設計が誤って整列していないクロックを使うと、タイミング制約を達成する際に不必要な困難が生じることがあります。たとえば、@clk と @pll_clk_8 の間にパスがある場合、ツールはタイミング制約を適用し、そのパスが確実に動作するようにします。ただし、@clk は PLL に入る基準クロックであり、@pll_clk_8 はこの PLL の出力であることに注意してください。したがって、これらの 2 つのクロックは整列していません。その結果、ツールはこのパスのタイミング制約を達成するために、不必要に苦労するかもしれません。そして、その不必要な努力が原因で、他のパスがタイミング制約を達成できないこともあります。
繰り返しになりますが、クロックドメインの話題はこの連載で取り上げています。
thold も重要
これまで示してきたすべてのタイミング計算は、tsu 要件に関するものでした。この要件に注目するのは自然なことです。ツールがタイミング制約を達成できない場合、ほとんどの場合、少なくとも 1 つのパスが tsu の要件を達成できなかったからです。
とはいえ、thold を念頭に置くことも重要です。この要件を満たすために、ツールは配線遅延を追加してデータパスを人為的に遅くすることがあります。したがって、thold 要件がタイミング制約の未達の理由として挙げられることはめったにありませんが、この要件が未達の背後に隠れた理由であることがあります。
実際、2 つのフリップフロップ間を接続する配線の遅延に関連したことが起きています。クロックが 1 つだけだったすべてのタイミングレポートでは、この配線は同じスライス(SLICE_X49Y58)内にありました。したがって、これらのレポートすべてで、この配線の遅延は 0.241 ns でした。しかし、パスに 2 つのクロックが関与すると、この遅延は 0.807 ns に増加しました。
説明すると、0.241 ns は、同じスライスに配置された 2 つのフリップフロップ間で達成できる最小遅延です。より長い遅延(0.807 ns)は、この配線の経路が変更された結果です。これは偶然ではありません。ツールは、thold 要件を満たすために、意図的にこの配線を長くしました。これは、レポートの「Data Path Delay」の行にも反映されています。ロジックの遅延はわずか 26.5% で、残りは配線です。それだけで、何かが起きたことを示す兆候です。これについては後で詳しく説明します。
thold 要件の解析
この連載の理論ページを思い出してください。thold とは、2 番目のフリップフロップのデータ入力がクロックエッジ後に安定していなければならない時間のことです。thold が違反される状況を説明しましょう。クロックエッジが最初のフリップフロップに到着し、2 番目のフリップフロップにもほぼ同時にクロックエッジが届きます(これらのクロックエッジは、同じクロックまたは異なるクロックからのものであり得ることに注意してください)。最初のフリップフロップは、そのクロックエッジに応答して、遅延(クロックから出力まで)の後に出力を更新します。しかし、更新された値が 2 番目のフリップフロップに早く到達しすぎます。その結果、このフリップフロップは直前の値を確実にサンプリングできません。新しい値は、2 番目のフリップフロップがそのクロックエッジへの反応を完了する時間の前に到着したからです。言い換えれば、thold 要件が違反されています。
同じクロックが両方のフリップフロップで使われる場合、これは主にクロックスキュー(clock skew)が原因で発生します。クロックエッジが最初のフリップフロップに早く到着すると、最初のフリップフロップがその出力を早く変えすぎる可能性があります。そうすると、更新された信号が 2 番目のフリップフロップに十分速く到達し、thold 要件を違反する可能性が生じます。両方のフリップフロップに到達するのは同じクロックエッジであるため、クロックの周波数やクロックジッタの量は関係ありません。遅延の違い(つまりクロックスキュー)だけが影響します。
しかし、以下のタイミング解析では、2 つのクロック @pll_clk_8 と @pll_clk_6 を含む最後の例を使い続けます。クロックが 1 つだけの場合のタイミング解析も似ていますが、thold 要件を満たすのが簡単すぎて、あまり興味深くありません。
これから見るタイミングレポートは、関連する 2 つのクロックに対して作成されたものです。この 2 つのクロックは周波数が異なるため、前と同様に、1 つ目のクロックエッジと 2 つ目のクロックエッジの時刻にはさまざまな組み合わせがあります。しかし、tsu の計算とは異なり、thold の最悪ケースは両方のクロックエッジが 0 ns のときです。thold の違反は、2 つのクロックエッジがほぼ同時に発生するときに起こるため、これより悪い組み合わせはありません。
それでは、これらの知見を踏まえて、タイミングレポートを見てみましょう。
Slack (MET) : 0.093ns (arrival time - required time) Source: foo_reg_reg/C (rising edge-triggered cell FDRE clocked by clk_out1_clk_wiz_1 {rise@0.000ns fall@4.000ns period=8.000ns}) Destination: bar_reg__0/D (rising edge-triggered cell FDRE clocked by clk_out2_clk_wiz_1 {rise@0.000ns fall@3.000ns period=6.000ns}) Path Group: clk_out2_clk_wiz_1 Path Type: Hold (Min at Fast Process Corner) Requirement: 0.000ns (clk_out2_clk_wiz_1 rise@0.000ns - clk_out1_clk_wiz_1 rise@0.000ns) Data Path Delay: 0.458ns (logic 0.104ns (22.707%) route 0.354ns (77.293%)) Logic Levels: 1 (LUT1=1) Clock Path Skew: 0.127ns (DCD - SCD - CPR) Destination Clock Delay (DCD): -0.542ns Source Clock Delay (SCD): -0.248ns Clock Pessimism Removal (CPR): -0.421ns Clock Uncertainty: 0.182ns ((TSJ^2 + DJ^2)^1/2) / 2 + PE Total System Jitter (TSJ): 0.071ns Discrete Jitter (DJ): 0.103ns Phase Error (PE): 0.120ns Clock Net Delay (Source): 0.495ns (routing 0.002ns, distribution 0.493ns) Clock Net Delay (Destination): 0.576ns (routing 0.002ns, distribution 0.574ns) Location Delay type Incr(ns) Path(ns) Netlist Resource(s) ------------------------------------------------------------------- ------------------- (clock clk_out1_clk_wiz_1 rise edge) 0.000 0.000 r AG12 0.000 0.000 r clk (IN) net (fo=0) 0.000 0.000 pll_i/inst/clkin1_ibuf/I AG12 INBUF (Prop_INBUF_HRIO_PAD_O) 0.339 0.339 r pll_i/inst/clkin1_ibuf/INBUF_INST/O net (fo=1, routed) 0.025 0.364 pll_i/inst/clkin1_ibuf/OUT AG12 IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O) 0.015 0.379 r pll_i/inst/clkin1_ibuf/IBUFCTRL_INST/O net (fo=1, routed) 0.405 0.784 pll_i/inst/clk_in1_clk_wiz_1 MMCME3_ADV_X1Y0 MMCME3_ADV (Prop_MMCME3_ADV_CLKIN1_CLKOUT0) -1.721 -0.937 r pll_i/inst/mmcme3_adv_inst/CLKOUT0 net (fo=1, routed) 0.167 -0.770 pll_i/inst/clk_out1_clk_wiz_1 BUFGCE_X1Y1 BUFGCE (Prop_BUFCE_BUFGCE_I_O) 0.027 -0.743 r pll_i/inst/clkout1_buf/O X2Y0 (CLOCK_ROOT) net (fo=1, routed) 0.495 -0.248 pll_clk_8 SLICE_X49Y58 FDRE r foo_reg_reg/C ------------------------------------------------------------------- ------------------- SLICE_X49Y58 FDRE (Prop_EFF_SLICEL_C_Q) 0.049 -0.199 f foo_reg_reg/Q net (fo=1, routed) 0.343 0.144 foo_reg SLICE_X49Y58 LUT1 (Prop_D5LUT_SLICEL_I0_O) 0.055 0.199 r bar__0_i_1/O net (fo=1, routed) 0.011 0.210 p_0_in SLICE_X49Y58 FDRE r bar_reg__0/D ------------------------------------------------------------------- ------------------- (clock clk_out2_clk_wiz_1 rise edge) 0.000 0.000 r AG12 0.000 0.000 r clk (IN) net (fo=0) 0.000 0.000 pll_i/inst/clkin1_ibuf/I AG12 INBUF (Prop_INBUF_HRIO_PAD_O) 0.595 0.595 r pll_i/inst/clkin1_ibuf/INBUF_INST/O net (fo=1, routed) 0.042 0.637 pll_i/inst/clkin1_ibuf/OUT AG12 IBUFCTRL (Prop_IBUFCTRL_HRIO_I_O) 0.022 0.659 r pll_i/inst/clkin1_ibuf/IBUFCTRL_INST/O net (fo=1, routed) 0.457 1.116 pll_i/inst/clk_in1_clk_wiz_1 MMCME3_ADV_X1Y0 MMCME3_ADV (Prop_MMCME3_ADV_CLKIN1_CLKOUT1) -2.474 -1.358 r pll_i/inst/mmcme3_adv_inst/CLKOUT1 net (fo=1, routed) 0.209 -1.149 pll_i/inst/clk_out2_clk_wiz_1 BUFGCE_X1Y0 BUFGCE (Prop_BUFCE_BUFGCE_I_O) 0.031 -1.118 r pll_i/inst/clkout2_buf/O X2Y0 (CLOCK_ROOT) net (fo=2, routed) 0.576 -0.542 pll_clk_6 SLICE_X49Y58 FDRE r bar_reg__0/C clock pessimism 0.421 -0.121 clock uncertainty 0.182 0.061 SLICE_X49Y58 FDRE (Hold_DFF2_SLICEL_C_D) 0.056 0.117 bar_reg__0 ------------------------------------------------------------------- required time -0.117 arrival time 0.210 ------------------------------------------------------------------- slack 0.093
まず、いくつか明らかな違いがあります。Path Type が、以前の Setup ではなく Hold です。これは予想どおりです。また、「Min at Fast Process Corner」とありますが、これはセットアップパスの場合とは逆です。この計算では、データパスに最大遅延ではなく最小遅延を使います。これは、データ入力が早く変わりすぎる状況に関する最悪ケースの計算に適しています。
Requirement は 0 ns です。これはホールドパスでは典型的です。クロックの周波数はここでは関係ありません。ここで調べているシナリオは、両方のクロックが同時に立ち上がりエッジを持つ場合です。
クロックパスについては、ソースクロックパス上の各コンポーネントの遅延が、宛先クロックパスの同じ遅延より一貫して短い(長くはない)ことに注意してください。これも、この計算の目的と整合しています。最悪ケースは、2 番目のフリップフロップへのクロックエッジの到着に対してデータが早く変わりすぎる場合だからです。マルチコーナータイミング解析(multi-corner timing analysis)については、前のページで説明しました。
しかし、このタイミングレポートで最も重要なのは、スラックが小さいことです。わずか 0.093 ns です。これは、ツールが要件を満たすために努力をしなければならなかったことを示すことがよくあります。ただし、スラックが小さいからといって、必ずしも解決すべき問題があったとは限らないことに注意してください。
thold のタイミング解析では、スラックが小さいことはよくあります。では、なぜこのパスが怪しいのでしょうか。主な理由は、前述のように、同じスライス(SLICE_X49Y58)上の 2 つのフリップフロップ間の配線遅延が大きいことです。おそらく、配置配線(place and route)の初期段階で、ソフトウェアがこれらの 2 つのフリップフロップ間の thold 要件の未達を検出したのでしょう。では、どうやって修正されたのでしょうか。
thold 要件の未達は、データ信号が 2 番目のフリップフロップのクロックエッジに対して早く到着しすぎることを意味します。これは、データパスに人為的に遅延を追加することで修正されます。その結果、2 番目のフリップフロップでは、データ入力の値が少し遅れて変化します。ツールはおそらく、2 つのフリップフロップ間の配線を長くしたのでしょう。これにより配線遅延が増加し、thold の問題が解決します。このような遅延の増加は、tsu 要件を満たす上での問題を生み出す可能性がありますが、この場合はそのような問題はありませんでした。このパスではタイミング制約が達成されています(つまり、tsu と thold の両方の要件が満たされました)。
それでも、この例は、thold の問題を解決する必要性が、一見無関係に見える tsu の問題を生み出す可能性があることを示しています。パスのロジック遅延と配線遅延の比率が非常に低い場合には、このことを念頭に置く必要があります。配線遅延が大きくなる理由は他にももちろんあります。特にファンアウトが大きい場合です。しかし、ファンアウトが小さい場合(この例のようにファンアウトが 1 の場合)、その大きな配線遅延が、thold の問題を解決するためにツールによって意図的に挿入されたのかどうかを問いかける価値があります。
しかし、なぜ 2 つのクロックの場合にだけ thold の問題が発生したのでしょうか。答えは、2 つのクロックがある場合、各フリップフロップにクロックエッジが到着する時刻の不確かさが大きくなるからです。この不確かさには、いくつかの要因が寄与します。特にクロックスキューとジッタです。thold の計算は 0 ns から 0 ns までで行われるため、この計算はクロックエッジの到着時刻の小さな不確かさに対してより敏感なのです。
したがって、関連する 2 つのクロックに関する不確かさは、thold 要件を満たすために、しばしば是正措置を必要とします。もちろん、これらの是正はツールによって自動的に行われます。それでも、タイミング制約を達成するのに問題がある場合には、これらの是正措置を認識しておくことが重要です。
まとめ
この連載の最後の 2 ページでは、特定の 1 つのタイミング制約の結果であるタイミングレポートの例をいくつか示しました。これらのタイミングレポートはすべて、特定の単純なロジックの例に関するものでした。これらの例が、タイミングの基礎を理解するのに役立つことを願っています。
ここまで来たら、同じ原理が複数の LUT を含むパスにどのように適用されるかを確認するために、ご自身の設計のタイミングレポートを見てみることをお勧めします。
タイミング問題とその解決方法に関する議論は、次のページから始まります。