このページは、タイミングに関する一連のページの一部です。
このページについて
タイミングを正しく理解するには、ロジック設計の基礎をいくつか知っておくことが不可欠です。このページでは、この連載の残りのページの基礎となる、いくつかの基本概念を説明します。
以下に書かれていることは、すべて大学のロジック設計の講義で教えられる内容です。しかし、FPGA に関わる人全員がそのような講義を受けているわけではありませんし、受けた人でもすべてを覚えているとは限りません。このページは、もし抜け落ちている部分があれば、それを埋めることを目的としています。
既にご存知の部分は読み飛ばして構いませんが、ざっとでも全体に目を通すことをお勧めします。このページの後半は、この連載の次ページ以降を理解するうえで特に重要です。
簡単なおさらい
タイミングに関連する概念に入る前に、ロジック設計の関連用語を簡単におさらいしておきます。次の用語をご存じない場合は、先に確認してからこのページを続けることをお勧めします。
まず、組み合わせ論理(combinatorial logic)です。この用語は、AND ゲート、OR ゲート、NOT ゲートなどの論理ゲートを表すために使われます。こうした論理素子は記憶を持たないため、組み合わせ論理と見なされます。言い換えれば、その動作は過去に何が起こったかに依存しません。出力の値は入力の値にのみ依存します。
組み合わせ論理の重要なタイプとして、ルックアップテーブル(LUT)があります。これは多目的の論理素子で、複数の入力に依存する任意の論理関数を実装します。LUT が重要なのは、FPGA 内部のほとんどすべての組み合わせ論理に使われるからです。FPGA 内部の LUT は非同期 ROM(すなわちクロックのない ROM)として実装されています。入力は LUT 内部のデータに対するアドレスとして扱われます。出力は通常 1 ビットまたは 2 ビットです。
市場に出回っているほとんどすべての FPGA で、この LUT への入力数は 4 または 6 です。したがって、各 LUT のメモリセル数は 16 または 64 になります。
次の重要な用語は順序論理です。これには、フリップフロップや同期 RAM、その他動作にクロックを必要とするさまざまな構成要素が含まれます。これらの論理素子はすべて、クロックの特定の変化に反応して動作します。動作の瞬間の合間には、順序素子は入力を無視し、内部状態を保持し、出力を変えません。
たとえば、立ち上がりエッジで動作する論理素子は、クロックが Low から High へ変化するとき、すなわち立ち上がりクロックエッジのときに動作します。同様に、立ち下がりエッジで動作する論理素子は、クロックが High から Low へ変化するとき、すなわち立ち下がりクロックエッジのときに動作します。両方のクロックエッジで動作する論理素子もありますが、そのような論理素子が使われるのは、ほとんどの場合 I/O 信号のサンプリング(sampling)または生成に限られます。
すべての順序素子は何らかのメモリを持ちます。これは、クロックエッジが来るまで出力を変えないという事実からすぐに導かれる結論です。最小限のメモリしか持たない順序素子は、出力ごとにちょうど 1 ビットのメモリを持ちます。一方、シフトレジスタや RAM など、より多くのメモリを持つ順序素子もあります。
タイミングを論じるうえで重要な事実は次の 2 つだけです。入力はクロックエッジとともにのみサンプリングされること、そして出力はほとんどクロックエッジの結果としてのみ変化することです。例外は 1 つだけあり、一部の順序素子に非同期リセット入力(asynchronous reset)があることです。この入力がアクティブ(論理素子によって High または Low)になると、順序素子の内部状態はクロックとは無関係に、即座にあらかじめ定義された値へ変わります。その結果、この素子の一部またはすべての出力も即座に既知の値へ変わります。
FPGA では、非同期リセットを持つ順序素子もあれば、持たない順序素子もあります。FPGA 上のほとんどすべての順序素子で可能な非同期入力は、この非同期リセットだけです。論理設計の理論には、複数の非同期入力を持つ素子(たとえば S-R フリップフロップ)が存在するにもかかわらず、このようになっています。
以降はフリップフロップについて解説します
簡単のため、すべての順序素子が立ち上がりエッジで動作するフリップフロップ、すなわちクロックの立ち上がりエッジに反応して動作するフリップフロップであると仮定します。言い換えれば、ここではすべての順序素子をフリップフロップで代表させます。これらのフリップフロップは、クロックが Low から High へ変化したときだけ入力に応答し、出力を更新します。
このようにすると、タイミングを理解しやすくなります。また、フリップフロップについての議論は、他のどの順序素子にも容易に一般化できます。
セットアップ時間とホールド時間
フリップフロップが正しく確実に動作するためには、入力が次の 2 つのタイミング要件を満たす形で安定している(すなわち値が変化しない)必要があります。
- 入力は、クロックエッジより前の一定時間、安定していなければなりません。この時間をセットアップ時間と呼び、tsu と表記します。
- 入力は、クロックエッジより後の一定時間も安定していなければなりません。この時間をホールド時間と呼び、thold と表記します。
上の図は tsu と thold の意味を示しています。黄色で示した時間帯の間、D 入力の値は変化してはいけません。この例では、D は、黄色い時間帯の外側、すなわちタイミング要件を満たす時点で High から Low へ変化しています。
この 2 つのタイミングパラメータを理解する 1 つの方法は次のとおりです。フリップフロップへの入力がクロックエッジとまったく同時に変化した場合、その入力が High として扱われるのか Low として扱われるのかは不明瞭です。クロックエッジ直前の状態と直後の状態のどちらを選ぶべきでしょうか。
では、「クロックエッジとまったく同時に変化した」とは、どの程度正確に同時だった場合を言うのでしょうか。tsu と thold の 2 つのタイミングパラメータは、クロックエッジからどれだけ離れていれば、入力の値を安全に変更できるかを定義します。これらのパラメータは、すべての順序素子に対して同じ意味で定義されています。
このタイミング要件が守られない場合、クロックエッジ後のフリップフロップの出力がランダムになる、というだけにとどまらず、はるかに深刻な結果になり得ることに注意してください。その理由は主に次の 2 つです。
- 場合によっては、FPGA ツールはプロジェクトの実装中に、ロジック設計内のフリップフロップを自動的に複製することがあります。特にファンアウト(fan-out)を減らすためです。こうすることで、このフリップフロップの値に依存する論理の一部は一方のフリップフロップへ、別の一部はもう一方のフリップフロップへ接続されます。両方のフリップフロップが常に同じ出力を持つ限り問題ありません。しかし、タイミング要件(tsu と thold)が満たされないと、これら 2 つのフリップフロップの出力が別々の値になる可能性があります。
- また、タイミング要件が守られないと、フリップフロップがメタステイビリティ(metastability)の状態に陥ることがあります。この状態では、フリップフロップの出力はしばらくの間、ハイでもローでもありません。メタステイビリティとその悪影響の詳細は、こちらのページで説明しています。
クロックから出力まで
すべての順序素子に対して定義される 3 つ目のタイミングパラメータは、クロックから出力までの時間(clock-to-output)です。これは tcko、tco、tC_Q などの記号で表されることがよくあります。このパラメータはタイミング要件ではありません。むしろ、順序素子の出力(Q)が有効であることが保証される時刻を示します。正確には、クロックエッジからどれだけ経過した後に出力が有効になるかです(上のタイミング図を参照)。
実際、この点については 2 つのパラメータがあります。
- 最大のクロックから出力までの時間:クロックエッジ後、出力が有効になるまでにかかる時間。
- 最小のクロックから出力までの時間:クロックエッジ後、出力が変わらないことが保証される時間。
ほとんどの場合、注目するのは最大のクロックから出力までの時間だけです。したがって、データシートにこのパラメータが載っているときは、ほぼ間違いなく最大値です。
フリップフロップのタイミング要件(tsu と thold)が満たされない場合、出力がいつ安定するかについての保証はありません。この場合、フリップフロップがしばらく未定義の状態(メタステイビリティ)にとどまる可能性があるため、最大のクロックから出力までの時間は意味を持ちません。
tsu と thold は負の値になり得る
上の図では tsu と thold が正の値として示されていますが、どちらかのパラメータが負の値になることもあり得ます。実際、FPGA 内部のフリップフロップでは、これはよく起こります。
たとえば、tsu が負の場合、クロックエッジが来た時点でデータが安定している必要はありません。むしろ、データはクロックエッジよりわずかに後で安定していればよいことになります。ただし、クロックエッジからどれだけ後まで許容されるかは、やはり tsu によって制限されます。
同様に、thold が負の場合、データはクロックエッジより前で変化しても構いません。この場合も、どれだけ前まで許容されるかには制限があり、それが thold に反映されています。
しかし、tsu と thold が負になり得るため、理論的には無意味なタイミング要件を定義することも可能です。
これを説明するため、フリップフロップが実際に入力をサンプリングする時刻を tsamp とします。tsamp は事前には分かりませんが、tsu の定義から −tsu < tsamp が分かります。言い換えると、フリップフロップは、データが変化して安定した後に入力をサンプリングします。これを保証しているのが tsu です。同じ原理で、tsamp < thold です。つまり、サンプリングは、クロックエッジに応答してデータが変化する前に行われなければなりません。これらを合わせると、−tsu < tsamp < thold、すなわち −tsu < thold となります。この関係は、あらゆる tsu と thold の組について成り立つ必要があります。
つまり、tsu または thold は、この条件を満たす限り負でも構いません。ただし、両方が同時に負になることはできません。
クロックから出力までの時間は常に正です。フリップフロップがクロックエッジより先に反応することはあり得ません。一方、tsamp が負になり得るのは、サンプリングがクロックエッジより前に行われたことを意味するわけではありません。これはむしろ、データ信号の遅延によって起こり得ることです。
伝搬遅延
上の図は、2 つのフリップフロップの間に LUT を挟んだ単純な接続を示しています。簡単のため、LUT の出力は I1 だけに依存すると仮定します。たとえば、このロジックは次の Verilog コードの結果であり、LUT は NOT ゲートを実装しています。
always @(posedge clk)
begin
foo_reg <= foo; // FF1 = foo_reg
bar <= !foo_reg; // FF2 = bar
end
2 つのフリップフロップが同じクロックに接続されていることに注意してください。このクロックの最大周波数はいくらになるでしょうか?
この質問に答えるには、情報が 1 つ欠けています。FF1 の出力が安定した値になってから、FF2 の入力が安定した値になるまでに、どれだけの時間がかかるかです。この時間を tpd と表記し、伝搬遅延(propagation delay)と呼びます。
伝搬遅延という用語は、常に特定の組み合わせ論理の区間に対して定義されることに注意してください。どの区間に対する遅延なのかを明確に定義することが重要です。たとえば、LUT の I1 から同じ LUT の O(入力から出力)までの時間も、伝搬遅延として定義できます。この遅延は、先ほどの tpd の定義とはおそらく異なります。
特に FPGA では、FF1 の出力と LUT の入力の間に配線遅延があります。したがって実際には、FF1 の Q と LUT の I1 は同じノードではなく、この 2 点間を信号が伝わるには時間がかかります。
このような曖昧さがあるため、FPGA のデータシートで tpd という記号を見ることはまれです。また、そうしたデータシートに伝搬遅延が記載されている場合、そのパラメータの正確な意味が明記されているのが普通です。
クロックの最大周波数の話には、後で戻ります。
パス
パス(path)を簡潔に定義するのは難しいですが、すでにその例は出てきています。先ほど、tpd を FF1 の Q から FF2 の D までの伝搬遅延と定義しました。この tpd は、特定のシナリオに対応しています。FF1 の値が変化し、更新された値が LUT に届き、LUT が出力を更新し、最後に更新された値が FF2 に届く、という一連の流れです。この一連のイベントは、ただ 1 つの信号(FF1 の出力)の変化によって始まり、別の地点(FF2 の入力)の信号が安定したところで終わります。
すなわち、tpd は FF1 の Q から FF2 の D に至るパスの伝搬遅延として定義されます。略して、FF1 から FF2 へのパスと呼びます。
パスは、この一連の流れの開始から終了までに遅延を生じさせる要素すべてから構成されます。パス内の要素には 2 種類あります。
- 組み合わせ論理の要素。電子回路が出力の信号を更新するのに時間がかかるため、遅延に寄与します。これはしばしばロジック遅延(logic delay)と呼ばれます。上の例では、LUT がこの種の要素です。
- 配線。論理素子の間の単なる電線です。信号が空間を伝わるのに時間がかかること、さらに電圧の変化にともなって途中の容量を充電する必要があることから、これらの区間も遅延に寄与します。
パスの目的は、その伝搬遅延を計算することです。この計算結果がどのように使われるかは、次に示します。
パスは多くの場合、あるフリップフロップの出力が変化し、その信号が別のフリップフロップの入力へ至る特定の経路をたどる、仮想的な実験を表しています。この仮想的な実験では、最初のフリップフロップの出力が変化したときに仮想のストップウォッチをスタートさせます。2 番目のフリップフロップの入力が変化したときに、そのストップウォッチを止めます。
この仮想的な実験によって、ストップウォッチが示す時間が長すぎるかどうか(すなわち tsu の要件が満たされていないかどうか)、あるいは短すぎるかどうか(すなわち thold が満たされていないかどうか)を判断できます。
パスの経路には配線と組み合わせ論理しか含まれないことに注意してください。したがって、目的地で信号が安定するまでにかかる時間は、そのパス上の組み合わせ論理の要素と配線にのみ依存します。仮想的な実験をいつ行っても結果は常に同じです。
実際の FPGA 設計では、各フリップフロップに到達するパスも、その出力から始まるパスも、通常は多数あります。実際、1 組のフリップフロップの間にも複数のパスが存在することがあります。それでも、タイミング計算は常に、1 つのフリップフロップだけが出力を変化させ、FPGA のロジック内で起こるすべてはその変化による直接の結果である、という仮定に基づいて行われます。FPGA 設計で計算されるパスの数は膨大になり得ますが、これはもちろんソフトウェアが自動的に行います。
簡単な静的タイミング解析
説明用に、上記の 2 つのフリップフロップの例で簡単なタイミング解析を行います。タイミング制約(timing constraints)の話題は後で扱いますが、ここでは @clk の周波数が 250 MHz(4 ns)であり、ロジックに直接接続されていると仮定します(PLL を介さない構成は実設計では推奨されませんが、タイミング解析を簡単にするためです)。タイミング制約(SDC スタイル)は、たとえば次のようになります。
create_clock -period 4.000 -name clk [get_ports clk]
この連載の次のページには実際のタイミング解析の例がありますが、そちらは正確な解析のため、理解を難しくする詳細が多く含まれます。ここでは、その原理を示すだけの簡単な解析を行います。
この解析は、先ほど説明した仮想的な実験を行います。@clk の立ち上がりエッジと同時に仮想のストップウォッチをスタートさせます。以下は、各イベントがもたらす(架空の)遅延とともに示した一連の流れです。
- FF1 のクロックから出力まで(0.2 ns): フリップフロップの入力(D)の値が FF1 の出力(Q)に反映されるまでにかかる時間。
- I1 までの配線遅延(0.3 ns): 信号が FF1 の出力から LUT の入力(I1)まで伝わるのにかかる時間。
- LUT の伝搬遅延(0.3 ns): いずれかの入力(この場合は I1)が変化した後、LUT が出力(O)を更新するのに必要な時間。
- FF2 の入力までの配線遅延(0.4 ns): 信号が LUT の出力から FF2 の入力(D)まで伝わるのにかかる時間。
このパスの伝搬遅延(tpd)は、これらすべての遅延の合計、つまり 0.2 + 0.3 + 0.3 + 0.4 = 1.2 ns です。例として、FF2 の tsu が 0.1 ns だと仮定します。これは、FF2 の入力(D)が @clk の次の立ち上がりエッジの 0.1 ns 前に安定していなければならないことを意味します。言い換えれば、許容される最大の tpd は 4 - 0.1 = 3.9 ns です。
しかし、tpd は 1.2 ns しかないため、この計算によると、このパスは大きな余裕をもってタイミング制約を満たしています。この余裕をスラック(slack)と呼び、この場合は 3.9 - 1.2 = 2.7 ns です。この値がソフトウェアのタイミング計算に表れるとき、ツールがタイミング制約を達成するのに苦戦したかどうかを示しています。スラックがゼロに近い場合は、ソフトウェアがそのパスをタイミング要件に適合させるために懸命に作業したことを示すことがよくあります。
伝搬遅延が分かれば、このパスがタイミングを満たすことのできる @clk の最大周波数も計算できます。tpd が 1.2 ns で、tsu の要件により、次の立ち上がりエッジはさらに 0.1 ns 後に来てもよいことになります。言い換えれば、立ち上がりエッジの間隔は少なくとも 1.3 ns 必要です。これは周波数にすると約 769 MHz です。非常に高い周波数ですが、パスに LUT が 1 つしか含まれていないため、現実的な結果です。実際のロジックは通常もっと複雑で、そのため実際の動作周波数もずっと低くなることがよくあります。
実際の静的タイミング解析では、この計算を正確に行いますが、これは物語の一部にすぎません。ここで計算したパスは、実際の計算ではデータパス(data path)と呼ばれます。しかし、実際の静的タイミング解析では、クロックエッジが両方のフリップフロップにまったく同時に到達するわけではないことも考慮されます。これは、クロックバッファから各フリップフロップまでの遅延がわずかに異なるためです。この遅延の差はクロックスキュー(clock skew)と呼ばれます。さらに、クロックジッタ(jitter)によって、各クロックエッジの間隔も正確には同じではありません。こうしたクロックに関する問題があるため、正確な計算はより複雑になります。次のページで示すとおりです。
リカバリとリムーバル
フリップフロップに非同期リセット入力がある場合(本当にそれを使いたいですか?)、この入力が非アクティブになるタイミングに関する要件があります。リセットがアクティブになるタイミングは問題にならないことに注意してください。アクティブになれば、フリップフロップはとにかく既知の状態に変化するからです。
しかし、リセットが非アクティブになると、フリップフロップはクロックに反応し始めます。このリセットの解除がクロックエッジの近くで起こると、フリップフロップがそのクロックエッジに応答すべきかどうかが不明瞭になります。tsetup と thold と同様に、リセットはクロックエッジの前後の一定時間、安定している必要があります。もう少し具体的に言うと次のとおりです。
- リセットは、クロックエッジより前の一定時間、アクティブから非アクティブへ変化してはいけません。この時間をリカバリ時間(recovery time)と呼びます。これは、フリップフロップがリセットから回復してクロックエッジを受け取る準備ができるまでに必要な時間です。
- リセットは、クロックエッジより後の一定時間も、アクティブから非アクティブへ変化してはいけません。この時間をリムーバル時間(removal time)と呼びます。
これらの定義は tsetup と thold の定義に似ていますが、これは偶然ではありません。リカバリ時間はセットアップ時間の特別な一種だからです。タイミング解析も同じように行います。唯一の違いは、セットアップ時間はデータ信号の値にかかわらず適用されるのに対し、リカバリ時間は非同期リセット信号がアクティブへ変化するときには適用されない点です。リムーバル時間とホールド時間の関係も同様です。
この類似性のため、リカバリとリムーバルについては、ここで触れただけで詳しい説明は行いません。また、上記のことは非同期リセットだけでなく、すべての非同期入力に当てはまることにも注意してください。
RTL パラダイムとタイミング
上に示した 2 つのフリップフロップの例は単純ですが、RTL パラダイムで作られるすべてのロジックを代表しています。各パスはフリップフロップで始まり、同じクロック(または関連クロック、related clock)で動作するフリップフロップで終わります。パス自体は組み合わせ論理と配線で構成されます。この例では組み合わせ論理が LUT 1 つだけですが、パス内に論理素子が複数ある場合と本質的な違いはありません。構造は同じです。
RTL パラダイムがこれほど重要なのは、この手法を使うと、ほとんどすべてのデータパスがこの同じ単純な構造になるからです。さらに、ロジック設計内のパス数は多くの場合膨大なので、タイミング解析が単純であることはミスを防ぐうえで役立ちます。とりわけ、タイミング解析がある特定のパターンを持つことで、タイミングレポートを読んで、それが理にかなっているかを問い直すことが可能になります。
したがって、可能な限り、すべての信号経路は順序素子で始まり、順序素子で終わるようにすべきです。これは、Verilog コードを書くときにも、ロジック全体の構造を計画するときにも役立つ指針です。
以上で、タイミング制約の背後にある理論の簡単な紹介を終わります。クロック周期の制約と関連するタイミングレポートについては、次のページで説明します。


