このページは、クロックドメインに関する全3回のシリーズの第1回です。
はじめに
ごく単純な FPGA 設計を除けば、複数のクロックが同期要素(フリップフロップ、ブロックRAM、シフトレジスタなど)を駆動します。しかし、ロジック設計内の大半の機能ユニットは単一のクロックで動作するため、複数のクロックが話題になることはほとんどなく、特別な注意は必要ありません。あるクロックに基づくロジックと、別のクロックに基づくロジックを接続するときになって、話は難しくなります。このシリーズでは、設計の中で複数のクロックをどう扱うかを解説します。
異なるクロックに依存するロジック同士を接続するとき、最初に答えるべき最も重要な問いは、再同期ロジック(resynchronization logic)が必要かどうかです。これは2つのクロックが関連クロック(related clocks)であるかどうかを問うことにほかなりません。このページでは、この問いとその答え方、および関連する話題を説明します。以下の議論の多くは、タイミング制約(timing constraints)と、それをロジックの特定の要素に適用できるかどうかに関係します。そこでまず、タイミングについて簡単に復習します。
このシリーズの解説は、ポジティブエッジトリガのフリップフロップ、つまりクロック入力の立ち上がりエッジに反応するフリップフロップに限定します。もちろん、クロックに基づいて信号をサンプリング(sampling)して生成する同期要素も他にあります。シフトレジスタ、ブロックRAM、その他多数の機能要素です。中にはクロックの立ち下がりエッジや、その両方のエッジで反応するものもありますが、ここでは簡単のためそれらはすべて無視します。
また、「X は Y に同期している」という表現は、同期要素 X のクロック入力がクロック Y に接続されていることを意味するものとして使います。したがって、この同期要素は、そのクロックで入力(複数の場合もある)をサンプリングし、出力もそのクロックで更新します。
タイミングの基礎を簡単に
ここではタイミング理論の要点を簡単にまとめます。より詳しい説明は別のページにあります。
次の図は、LUT を経由して、あるフリップフロップから別のフリップフロップへと信号が伝わる信号パス(path)を示しています。
この図の LUT(Look-Up Table、ルックアップテーブル)は、任意の組み合わせロジック(combinatorial logic)のまとまりを表しています。I1、I2、I3、I4 のいずれかが変化すると、出力 O は伝搬遅延(propagation delay)を伴ってすぐに変化します。
この信号パスは次のように動作します。左のフリップフロップの Q 出力(@foo)は、入力クロック @clk1 の立ち上がりエッジの後に変化します。この出力は I1 に接続されているので、LUT の出力 O は少しの遅延の後に変化します。この O は右のフリップフロップのデータ入力 D に入ります。右のフリップフロップは @clk2 の立ち上がりエッジの後に D を Q(@bar)へコピーします。
しかし、それほど単純ではありません。すべてのフリップフロップにはタイミング要件があります。データ入力 D は、@clk2 の立ち上がりエッジの前に tsu(セットアップ時間)だけ安定していなければならず、このエッジの後も thold(ホールド時間)だけ安定していなければなりません。
FPGA 内の信号パスの大部分は単一クロックに関係しています。したがって、@clk1 と @clk2 は正確に同じクロック信号です(ここではクロックスキュー(clock skew)は無視します)。そのようなパスでは、2つのタイミング要件を保証できるかどうかを計算できます。
たとえば、上の図の tsu に関する要件を考えてみましょう。ここでは、@clk1 の立ち上がりエッジから、右のフリップフロップの D 入力が更新されて安定するまでにどれだけの時間がかかるかを求めます。これはこのパス上のすべての遅延の合計です。まず、@clk1 の立ち上がりエッジから @foo が更新されるまでの遅延(clock to output)があり、その後、右のフリップフロップの D 入力に届くまでの遅延がすべて続きます。これには LUT の遅延だけでなく、ロジック要素間の配線遅延(routing delay)も含まれます。
@clk1 と @clk2 が同じクロックであれば、両方のフリップフロップの次の立ち上がりエッジがいつ来るかは明らかです。1クロック周期後です(たとえば 100 MHz クロックなら 10 ns)。したがって、パスの合計遅延は、tsu のマージンを確保したうえで、クロック周期より短くなければなりません。これを保証できれば、tsu の要件、つまり右のフリップフロップの D 入力が @clk2 の立ち上がりエッジの前に tsu のマージンを持って安定していることが保証されます。数値を使った例はタイミング理論のページを参照してください。
thold についても同様の計算ができます。tsu と異なり、右のフリップフロップの D 入力が @clk2 の立ち上がりエッジの後も一定時間(thold)安定し続けることが要件です。したがって、クロック周期は無関係であり、計算には入りません(@clk1 と @clk2 が同じ場合)。重要なのは、次のクロックサイクルではなく、同じクロックサイクルの中で何が起こるかです。
この種の計算が可能なのは、@clk1 と @clk2 の立ち上がりエッジの時間差が分かっているからです。特に、@clk1 と @clk2 が同じクロックなら、tsu の計算に使う時間差は、そのクロックの周期になります。しかし、2つのクロックの時間差が不明なら、tsu も thold も保証できません。
tsu と thold は、すべてのフリップフロップに適用されます。これはもちろん、FPGA 上のすべてのフリップフロップだけでなく、外部デバイス上のフリップフロップにも当てはまります(たとえば FPGA の出力ピンから、クロックで信号をサンプリングする外部デバイスへの経路)。したがって、システム内の各フリップフロップについて、これら2つの要件を満たすことを保証できているかどうかを確認する必要があります。保証できないフリップフロップについては、それを補って確実に動作させる仕組み(つまり再同期ロジック)を用意しなければなりません。これが、要するにクロックドメインをまたぐ話の核心です。
では、もう一度:タイミングはいつ保証されるのか?
前の節で混乱してしまった場合に備え、要点をまとめます。
FPGA 設計には、クロックの周波数を設計ツールに知らせるタイミング制約が必ず含まれていることを思い出してください。ツールはこの情報に基づいて、2つのタイミング要件(tsu と thold)が満たされるようにします。あるいは、ツールがこれらの要件を達成できない場合は、その失敗をレポートします。
前述のとおり、tsu と thold を保証できるのは、パスの始点にあるクロックの立ち上がりエッジと、パスの終点にあるクロックの立ち上がりエッジの時間差が分かっている場合だけです。この条件は、ほとんどの場合に成立します。ロジック設計の大部分は、同じクロックに同期した別のレジスタに依存するレジスタで構成されているからです。
しかし、2つの異なるクロックを使う場合はどうでしょう。パスの始点にあるフリップフロップには一方のクロックが接続され、終点にあるフリップフロップには別のクロックが接続されているとしたら?言い換えれば、@clk1 と @clk2 が同じでない場合は?それでもタイミング計算をして、タイミング要件を保証できるのでしょうか?それは場合によります。このページの残りでは、まさにこの問題を扱います。
クロックドメインとクロックドメインクロッシング
クロックドメイン(clock domain)とは、特定のクロック信号に同期するすべての同期要素(フリップフロップなど)の集まりのことです。
次の簡単な Verilog コードを見てください。
reg foo, bar;
always @(posedge clk1)
foo <= !foo;
always @(posedge clk2)
bar <= foo;
この例では、@foo は @clk1 に同期し、@bar は @clk2 に同期しています。したがって、@foo と @bar は、それぞれ @clk1 と @clk2 という別々のクロックドメインに属します。
@foo については心配する必要はありません。@foo は自分自身にだけ依存しています。一方 @bar は @clk2 に同期し、@clk1 に同期する @foo に依存しています。では、@bar を普通のレジスタとして使ってよいのでしょうか。@bar は常にタイミング的に正しい状態で @foo の値を取り込むので、その動作は既知で再現可能だと仮定できるでしょうか?
この質問に答える前に、いま起きたことを名前で呼んでおきましょう。これはクロックドメインクロッシング(clock domain crossing)です。@foo と @bar は、互いに異なるクロックに同期する2つのフリップフロップとして実装されています。つまり、@foo から @bar へのパスは、あるクロックドメインから別のクロックドメインへとまたがっています。
より一般的には、クロックドメインクロッシングとは、あるクロックドメインに属する同期要素の出力が、別のクロックドメインに属する同期要素の入力に届く状況を指します。この2つの同期要素の間には、組み合わせロジックが入っていることもよくあります。
したがって、仮に @bar が次のように定義されていたとしても、
always @(posedge clk2)
bar <= !foo || !bar;
そこにはやはりクロックドメインクロッシングがあります。この場合、パスは @foo から始まり、論理関数を実装する LUT を通って @bar で終わります。先ほどの図と同じです。
関連クロックと無関係クロック
関連クロック(related clocks)とは、同じ基準クロックから派生し、立ち上がりエッジ間と立ち下がりエッジ間の時間差が(既知の誤差とジッタ(jitter)を除けば)予測可能なクロック群を指します。
関連クロックの代わりに「同期クロック(synchronous clocks)」という用語が使われることもよくあります。同様に、無関係クロック(unrelated clocks)の代わりに「非同期クロック(asynchronous clocks)」という用語が使われることもよくあります。
関連クロックの一般的な例は、1つの FPGA PLL から複数のクロックを生成し、それらの周波数の間に既知の関係がある場合です。このシナリオでは、FPGA ツールは通常、クロックエッジが可能な限り整列するようにクロックバッファを配置します。
たとえば、基準クロックを 2 倍および 3 倍にする場合を考えます。
この例では、x1 clk、x2 clk、x3 clk は関連クロックです。これらのどのペアについても、クロック間のタイミングが予測可能だからです。
一般的なケースでは、基準クロックはこれら他のどのクロックに対しても無関係クロックです。基準クロックのエッジと他のクロックのエッジの間のタイミングは、温度などの要因で変化し得るからです。ただし、PLL が基準クロックと PLL 出力の間で予測可能な整列を保証するように設定されていれば、基準クロックも関連クロックになります。
クロック間の時間関係が分かっていれば、それらのクロックドメイン間をまたぐパスのタイミング計算が可能になります。たとえば、x1 clk と x2 clk のドメイン間のパスタイミングは、x2 clk 同士のパスと同じ要件で計算されます。これは、これら2つのクロックの最短時間差が、x2 clk の連続する2つの立ち上がりエッジの間隔と同じだからです。
同様に、x2 clk と x3 clk の間のパスも計算できますが、その最短時間差は x1 clk の周期のわずか6分の1です。したがって、最悪ケースのタイミング要件は、仮想的な x6 clk の要件に相当します。理由は、x2 clk の2番目の立ち上がりエッジと、x3 clk の3番目の立ち上がりエッジの時間差にあります。
タイミング計算の詳細は、こちらのページでさらに詳しく説明しています。
この例で言いたいのは、一般的にも当てはまる次のことです。関連クロック同士であれば、それらのクロック間のパスにタイミング制約を適用することで、同じクロックドメイン内のパスと同じようにタイミングを保証できます。これは、FPGA ツールが意図的にクロックエッジを整列させている場合に可能です。例で見たように、タイミング要件は個々のクロック単独の場合より厳しくなることが多く、時にはかなり厳しくなります。
ただし、2つのクロックが同じ基準クロックから派生しているからといって、必ずしも関連クロックになるわけではないことに注意してください。特に、それらのクロック間のスキューが制御されていない、または不明な場合(設計ツールが等遅延のクロック分配リソースを明示的に使っていない限り、そうなります)は、無関係クロックとして扱うべきです。
また、x1 clk でさえ、基準クロックとまったく同じ周波数であっても、基準クロックと関連しているとは限りません。これらのクロックが意図的に互いに整列されていない限り、それらの位相関係は不明です。
この位相の話があるため、先ほどのクロックドメインの定義では、「特定のクロック」ではなく「特定のクロック信号」と書きました。「特定のクロック」という表現は、たとえば基板上の同じクロックが FPGA の異なる2つの入力ピンに接続されている場合などを意味し得ます。一方、「特定のクロック信号」とは、上の例の @clk1 や @clk2 のように、Verilog や設計のネットリスト上でクロック信号を表す配線を指します。このクロック信号は、インスタンシエーション(instantiation)でのポート接続や、単純な assign 文によって Verilog 設計内に分配されます。
Verilog 上でクロックがまったく同じ信号であるということは、FPGA ツールが、ハードウェア上でクロックスキューが低くなるように保証されたリソースを使うことを意味します。また、ツールがそれらのクロックを関連クロックとみなすかどうかにも影響します(これについては後述します)。
関連クロック、タイミング制約、再同期ロジック
元の質問に戻りましょう。上の例の @bar は、通常のレジスタと同じように使えるでしょうか。もう少し一般的に言えば、あるフリップフロップが、あるクロックドメインから別のクロックドメインへまたがるパスの終点にあるとき、その出力をほかのフリップフロップの出力と同じように信頼して使えるでしょうか。これは、そのフリップフロップのデータ入力に至るパスのうち少なくとも1本が別のクロックに同期している場合に、そのフリップフロップのセットアップ時間とホールド時間を保証できるかという問いと同じです。
答えは簡単で短いです。両側のクロック(例では @clk1 と @clk2)が関連クロックであれば、終点のフリップフロップの出力はまったく問題なく、通常のレジスタとして使えます。ただし、そのパスに対する適切なタイミング制約が達成されていることが条件です。そうでない場合、終点でのタイミングは保証できないため、再同期ロジックを追加して対処しなければなりません。
2つの関連クロック間のパスのタイミング解析の完全な例は、こちらのページで示しています。
長い説明になりましたが、ここで簡単な規則にまとめましょう。
- 無関係クロックに属するクロックドメイン間のパスに対しては、タイミング制約を課しても保証は得られません。
- 2つのクロックドメイン間のすべてのパスに再同期ロジックがあれば、これらのパスにタイミング制約を適用する必要はありません。
- 2つのクロックドメイン間のあるパスに再同期ロジックがない場合、そのパスにはタイミング制約を適用しなければなりません。
最初の規則は最も単純です。2つのクロックが関連クロックであると確信できない場合は、クロックドメイン間のすべてのパスに再同期ロジックを入れるようにしてください(方法は次のページで説明します)。また、これらのパスにタイミング制約が適用されないようにしてください。2つ目の規則により、それは問題ありません。不要なタイミング制約は、FPGA ツールの作業を難しくするだけだからです。
これらの規則から導かれるもう1つの結果として、たとえクロックが関連クロックであっても、それらを無関係クロックとして扱って構いません。先ほど述べたように、すべてのパスに再同期ロジックを入れ、タイミング制約の適用をオフにすればよいのです(詳細は以下で説明します)。
そして最後に、クロックが関連クロックであると確信できる場合は、再同期ロジックは不要ですが、クロックドメイン間のすべてのパスに、正しく適用されたタイミング制約がなければなりません。
次の表にこの節をまとめます。表の行はパスの終点に再同期ロジックがあるかどうかを表し、列はクロックが関連クロックかどうかを表しています。表の中央は、そのパスにタイミング制約が必要かどうかを示します。
| クロックは | |||
| 関連クロック | 無関係クロック | ||
|
再同期 |
未適用 | パスにはタイミング制約が必要 | これは誤りです |
| 適用済み | パスにタイミング制約は不要 | ||
よくある誤り
複雑な設計では、信号がさまざまなモジュールにまたがって配線されるため、どの信号がどのクロックに同期しているかを見落としがちです。その結果、気づかないうちにあるクロックドメインから別のクロックドメインへ移ってしまうことがあります。
有害な誤りには2つのタイプがあります。1つ目は、無関係クロック同士のクロックドメイン間に、再同期ロジックなしでパスを作ってしまうことです。これは、そのようなパスの終点でタイミング違反が時折発生する可能性があることを意味します。タイミングに関する誤りは、目に見える問題が非常に誤解を招きやすいという特徴があります。さらに、ツールがタイミング制約から2つのクロックは関連クロックだと推定し、そのパスに不要なタイミング制約を適用すると、混乱に拍車がかかります。無関係クロック間のパスにそのような制約は意味を持ちませんが、レポート上ではあたかも適切に処理されたかのように表示されます。そのため、タイミングレポートを読む人間が、すべて問題ないと思い込んだり、あるいはそれらのクロックが本当に関連クロックだと誤解したりする恐れがあります。
2つ目の有害な誤りは、2つのクロックが実際には関連クロックであり、ロジックもそのように扱っているのに、ツールが関連クロックとして認識しない場合です。その結果、クロックドメイン間のパスにはタイミング制約が適用されず、終点でタイミング要件が満たされる保証がありません。これもまた、信頼性の低い動作につながる可能性があります。ただし、この種の誤りは、設計のタイミング妥当性の検証で見つけられる可能性があります。
クロックドメインクロッシングに気づかないことが本当に無害なのは、クロック同士が関連クロックであり、FPGA ツールもそのようにみなしている場合だけです(その場合、関連するパスにはタイミング制約が適用されます)。クロックの周波数が異なるのにロジックがそれを考慮していなければ、機能的なバグは依然として起こり得ます。ただし、それは通常のロジックのバグと同じです。
不要なタイミング制約を避ける
1つの PLL から異なる周波数のクロックを生成し、それぞれを異なる機能ユニットで使うことはよくあります。設計者の視点では、それらは無関係クロックですが、実際には関連クロックであり、ツールも通常は関連クロックとして扱います。
たとえば、PLL が 10 MHz の基準クロックから2つのクロックを生成するとしましょう。1つは 90 MHz、もう1つは 100 MHz です。これらはプロジェクトの異なる部分で使うつもりなので、概念的には無関係クロックです。ところが、あるフリップフロップが一方のクロックに同期し、別のフリップフロップがもう一方のクロックに同期するような接続があったらどうなるでしょうか?
最初のクロックの周期は 11.11 ns、2番目のクロックの周期は 10 ns なので、立ち上がりエッジ間の時間差の最悪値は 1.11 ns です(可能なすべての位相の組み合わせを考慮した場合)。これは 900 MHz のクロック周期に相当します。したがって、これら2つのフリップフロップ間のパスのタイミングは非常に厳しく、たとえ要件を達成できる場合でも、ツールにとっては難題です。特に、そのようなパスが多数ある場合はなおさらです。
これは理論上の話ではありません。よくある落とし穴は、クロックが関連クロックかどうかに注意を払わず、デュアルクロック FIFO を使ってクロックドメイン間を接続することです。この誤りに機能的な問題はありません。ただし、デュアルクロック FIFO には常に再同期ロジックがあるため、2つのクロックドメイン間のパスにタイミング制約を適用するようツールに強いるのは無意味です。ツールは、無意味なタイミング制約を達成しようと苦労するかもしれません。
したがって、関連クロックでありながら関連クロックとして使われていないクロック、特に同じ PLL から出力されているクロックに注意することが重要です。あるクロックドメインから別のクロックドメインへのパスにタイミング制約が適用されている可能性が高いからです。この適用には利点がありません。再同期ロジックがタイミング違反から守ってくれるからです。その一方で、ツールがそれらのパスのタイミング制約を達成しようと努力するせいで、設計全体のタイミング制約を達成するのが難しくなることがあります。
これを解決するには、クロックを無関係クロックとして宣言するタイミング制約を追加します。あるいは、それらのパスにフォールスパス(false path)または最大遅延を定義します。ただし、場合によってはその必要がないこともあるので、対処する前にこれらのパスについてタイミングレポートを確認する価値があります。たとえば、FPGA ツールが提供するデュアルクロック FIFO を使う場合、クロックドメイン間を接続するパスには、適切なタイミング制約が自動的に追加されることがよくあります。
誤解を招くタイミング制約
FPGA ツールは通常、無関係クロック間のタイミング制約も受け入れ、適用してしまうことを強調しておきます。そのような制約は無意味であるだけでなく、混乱の元です。特に、それらのパスが、あたかもタイミング要件を保証されているかのようにタイミングレポートに現れるからです。すでに述べたとおり、無関係クロックに属するクロックドメイン間のパスのタイミングを保証することは不可能です。
タイミング制約は、FPGA ツールに設計に関する情報を伝える手段にすぎないことを覚えておくことが重要です。設計がタイミング制約を達成できたとしても、その制約が正しい場合にのみ意味があります。したがって、クロックが関連クロックだと確信できないのであれば、タイミング制約を追加するだけでクロックドメインクロッシングを解決しようとしないでください。
繰り返しになりますが、該当する場合には、クロックを無関係クロックと定義するタイミング制約や、フォールスパスを定義するとよいでしょう。それにより FPGA ツールの作業が楽になるだけでなく、混乱も避けられます。
ツールに正しい情報を確実に伝える
上で述べたすべての理由から、FPGA 設計ツールが、どのクロックが関連クロックで、どれがそうでないかについて正しい情報を持っていることが極めて重要です。より正確には、FPGA ツールが、再同期ロジックによって保護されていないすべてのパスにタイミング制約を適用することが重要です(これにはクロックドメイン内のパスも含まれますが、ここでは関係ありません)。
ただし、ツールにロジック設計と同じ認識を持たせるのは難しい場合があります。FPGA 設計ソフトウェアは、それぞれ独自の方法でクロック間の関係を自動推定します。すべてのツールに共通しているように思える唯一の点は、ツール専用のクロッキング IP を使って同じ PLL で2つ以上のクロックを生成した場合、ツールはそれらのクロックを関連クロックとみなす、ということです。それに伴い、関連するクロックドメイン間のパスはタイミング解析され、タイミング制約が適用されます。この適用は通常、基準クロックに対して与えられたタイミング制約に基づきます。しかし、その点さえ当然視してはいけません。
それ以外については、各ツールが独自の方法でクロック間の関係を推定します。同じ FPGA ベンダーの異なるツールでも、状況によっては異なる判断を下すことがあります。特に、Xilinx の Vivado は、Xilinx の旧フラッグシップツールである ISE と比較して、クロックを関連クロックとみなす傾向が強いです。
したがって、すべての FPGA 設計ツールに当てはまる普遍的な原則はありません。特定のツールでさえ、驚くような判断をすることがあります。このテーマに真剣に取り組む唯一の方法は、タイミングレポートを確認し、特定のパスグループについてタイミングレポートを出力して、必要な場所ではタイミング要件が正しく、不要な場所にはタイミング要件が存在しないことを確認することです。これは大変な作業ですが、やる価値はあります。

