クロック同期と非同期設計 ─ メタステーブルとCDC
別クロック間で信号を渡すとなぜ稀に回路が壊れるのか。メタステーブルの正体とMTBF、2段FFシンクロナイザやグレイコード・非同期FIFOまで、CDCを安全に設計する勘所を原理から掴めます。
- 1.送信側と無関係なタイミングで変化する信号を受信FFがサンプルすると、セットアップ/ホールド時間を破ってメタステーブル(中間電位で長く滞留する不定状態)に陥り、出力確定が遅れて下流がビット化けやプロトコル破綻を起こす。
- 2.2段FFシンクロナイザは1段目がメタステーブルに落ちても1クロック分の解決時間を与え、MTBFを指数的に伸ばす定石。ただし救えるのは1ビットだけで、複数ビットを同時に渡すとビット間スキューで一瞬の不正値が生じるため使えない。
- 3.マルチビットはグレイコード(隣接値が1ビット差)やハンドシェイク、非同期FIFOで安全化し、検証はRTLにシンクロナイザ構造とメタステーブル注入を加える静的CDCチェックで網羅的に確認する。
なぜ別クロックの信号を直接受けると壊れるのか
現代のSoCは1つの周波数では動きません。CPUコア、メモリインターフェース、PCIe、USB、各種ペリフェラルがそれぞれ独立した発振源やPLLによるクロック生成を持ち、互いに位相も周波数も無関係に進みます。この独立した時間軸の領域をクロックドメインと呼び、ドメインをまたいで信号を受け渡すことを CDC(Clock Domain Crossing) と言います。
問題は、フリップフロップ(FF)が信号を正しく取り込むには条件があることです。クロックエッジの前後に、入力Dが安定していなければならない時間窓があります。エッジ前の セットアップ時間、エッジ後の ホールド時間 です。同一ドメイン内なら静的タイミング解析(STA)でこの窓を守れますが、無関係なクロックで生成された信号は受信エッジに対しいつ変化するか予測できません。遅かれ早かれ、ちょうど窓の最中に変化が訪れます。
受信FFのタイミング窓
clk ___|‾‾‾|___|‾‾‾|___
setup/hold [<-->] 要安定区間
D (別ドメイン) ~~~~~^~~~~~ この瞬間に遷移すると窓を侵犯
メタステーブル ─ 不定状態が時間とともに崩れる
セットアップ/ホールドを破ると、FFの出力は0でも1でもないメタステーブル状態に陥ります。これは比喩ではなく、内部の正帰還ループが不安定平衡(鉛筆を芯で立てた状態)に置かれ、出力電圧がしきい値付近の中間値にしばらく留まる物理現象です。
重要なのは、メタステーブルが「いつ」「どちらへ」崩れるか確定的に予測できない点です。ごく短時間で0/1へ落ち着くこともあれば、稀に長く滞留します。滞留が次段のクロックエッジまで及ぶと、下流のFFは確定していない値を取り込み、ビット化けや、複数の受け側で異なる値を見る不整合を引き起こします。
非同期な遷移が存在する限り、どんなFFでもメタステーブルに入る確率はゼロにできません。CDC設計の目標は「発生を防ぐ」ことではなく、「発生しても次段が取り込む前に解決している確率を限りなく高める」ことです。この発想が以降のすべての技法の土台になります。
メタステーブルが残存する確率は時間とともに指数関数的に減衰します。解決のために与えられた時間を t とすると、未解決確率はおよそ exp(-t / τ) に比例します。ここで τ はFFの再生ゲインで決まる時定数です。つまり解決に使える時間 t を稼ぐほど、失敗確率は指数的に下がる——これがシンクロナイザの設計原理です。
MTBF ─ 故障間隔を定量化する
CDCの信頼性は MTBF(Mean Time Between Failures、平均故障間隔) で評価します。標準的なモデルは次の形です。
MTBF = exp(t_r / τ) / (T0 * f_clk * f_data)
t_r : メタステーブル解決に許された時間(解決窓)
τ : FFの解決時定数(小さいほど速く崩れる)
T0 : メタステーブルに入りやすさを表す係数
f_clk : 受信クロック周波数
f_data : 送信側でデータが変化する頻度
分子に解決時間 t_r が指数の肩で効くのが核心です。t_r をわずかに増やすだけでMTBFは桁で伸びます。逆に分母は、クロックが速いほど・データ変化が頻繁なほどサンプル機会が増え、MTBFを縮めます。設計では「t_r を稼ぐ」ことが最も費用対効果の高いレバーになります。その t_r を確保する具体策が、FFを直列に足すことです。
2段FFシンクロナイザ ─ CDCの定石
最も基本的な構造が 2段FFシンクロナイザ です。受信ドメインのクロックで動くFFを2段直列につなぎ、1段目の出力を2段目で受け直します。
// 1ビット信号を受信ドメイン clk_dst へ同期化
reg sync_ff1, sync_ff2;
always @(posedge clk_dst) begin
sync_ff1 <= async_in; // ここでメタステーブルになり得る
sync_ff2 <= sync_ff1; // 1クロック分の解決時間を与える
end
// sync_ff2 を以降のロジックで使う
仕掛けは単純です。1段目がメタステーブルに入っても、2段目がそれを取り込むまでにまるまる1クロック周期の解決時間が与えられます。前述のMTBF式の t_r が「受信周期 − 2段目のセットアップ時間」へと大きく確保され、未解決確率 exp(-t_r / τ) が桁違いに小さくなります。動作周波数が高くMTBFが足りなければ3段にして t_r をさらに積み増します。
2段FFの効果を出すには、1段目と2段目を物理的に近接させ、両者間の配線遅延を最小化して解決時間を最大化します。論理合成では1段目の入力パスにSTAを適用せず(タイミングは保証できないため)、代わりに「ここはシンクロナイザだ」と明示する制約(set_false_path や set_max_delay)を与えます。この宣言を忘れるとツールが普通のパスとして扱い、CDCバグが解析をすり抜けます。
マルチビットの壁 ─ 2段FFでは救えない
2段FFが守れるのは1ビットだけです。複数ビットのバスをビットごとに2段FFへ通すと、各ビットのメタステーブル解決タイミングが微妙にずれ(収束スキュー)、ある受信エッジで「一部のビットは新しい値、残りは古い値」という実在しない中間値が一瞬出力されます。
2bitカウンタ 01 -> 10 への遷移を別ドメインで個別同期
bit1: 0 -> 1 (このエッジで確定)
bit0: 1 -> 0 (次のエッジまで遅れる)
受信側が見る瞬間の値 = 11 (旧値01でも新値10でもない、本来通らない偽値)
カウンタ値やポインタを生でCDCすると、この偽値で下流が誤動作します。対策の方向は2つ。値の符号化を工夫して同時に変わるビットを1本に減らすか、多ビットをひとまとめに渡すプロトコルを使うかです。
グレイコード ─ 一度に1ビットしか変えない
連続的に増減するカウンタには グレイコード が効きます。グレイコードは隣接する値どうしが必ず1ビットだけ異なる符号です。
2進 グレイ
000 -> 000
001 -> 001
010 -> 011
011 -> 010
100 -> 110
隣り合う値の遷移で変化するビットが常に1本なら、CDCの最中に複数ビットがずれて偽値を生む余地がありません。受信側がたまたま遷移中をサンプルしても、見えるのは「遷移前の値」か「遷移後の値」のどちらかに限られ、必ず有効な値になります。各ビットは2段FFで同期すれば足ります。連番を1ずつ進めるポインタ系——とりわけ非同期FIFOのアドレス——でグレイコードが定番なのはこのためです。
ハンドシェイクと非同期FIFO ─ まとまったデータを渡す
任意の多ビットデータ(飛び飛びの値も取る)には ハンドシェイク が基本です。送信側がデータを安定させてから req を上げ、受信側は req を2段FFで同期して安定を確認し、データを取り込んでから ack を返す。ack も送信側で同期します。データ線自体は同期せず安定保持されているため、メタステーブルになるのは1ビットの req/ack だけで済みます。
4相ハンドシェイク
src: data確定 -> req=1 ............ req=0
dst: (reqを同期) ack=1 -> ack=0
※ data はreqが立つ前に確定し、ackまで保持
ハンドシェイクは確実ですが、1語ごとに往復のレイテンシがかかり高スループットには不向きです。連続データには 非同期FIFO を使います。デュアルポートメモリの書き込み側を送信クロック、読み出し側を受信クロックで駆動し、満杯(full)・空(empty)の判定に使うライトポインタとリードポインタをグレイコードで相手ドメインへ同期します。
ポインタがグレイコードなのは、フラグ生成のために多ビットのポインタをCDCする必要があるからです。1ビットずつしか変わらないので2段FFで安全に渡せ、相手ドメインで同期したポインタと自分のポインタを比較してfull/emptyを正しく判定できます。これにより、片側がデータを連続投入し他方が別速度で連続取り出しするメモリコントローラやI/O経路のような高スループットCDCが成立します。
信号の性質で選びます。レベル信号や単一フラグなら2段FF。連続的に増減する値(カウンタ・ポインタ)ならグレイコード+2段FF。任意の多ビットを確実に1語ずつ渡すならハンドシェイク。高スループットなストリームなら非同期FIFO(内部でグレイコードを使う)。1ビットしか守れない2段FFを多ビットに流用しないのが鉄則です。
| 技法 | 対象 | 守れる幅 | スループット | 代表用途 |
|---|---|---|---|---|
| 2段FFシンクロナイザ | レベル/フラグ | 1ビット | 高 | 割り込み・状態通知 |
| グレイコード+2段FF | 連番カウンタ/ポインタ | 多ビット(連番) | 高 | FIFOポインタ |
| ハンドシェイク(req/ack) | 任意の多ビット | 多ビット(任意) | 低 | 設定レジスタ転送 |
| 非同期FIFO | 連続ストリーム | 多ビット(任意) | 高 | ドメイン間バッファ |
検証 ─ シミュレーションでは捕まらない
CDCバグの厄介さは、機能シミュレーションでまず再現しない点にあります。メタステーブルは確率的かつアナログな現象で、論理シミュレータは0/1の理想値しか扱わないため、たまたま正しい値に崩れた波形しか見えません。実機で数時間〜数日に一度だけ起きる、再現困難な不具合になりがちです。
そこで 静的CDC解析ツール を使います。RTLを構造的に走査し、(1) 別クロックドメイン間のパスを自動抽出し、(2) 各クロスに正しくシンクロナイザが入っているかを確認し、(3) 多ビットの生CDCや、収束(複数の同期信号が下流で論理結合され再びメタステーブル起因の不整合を生む)といったアンチパターンを検出します。
別々に同期した複数のCDC信号を下流で組み合わせると、各信号がメタステーブル解決のタイミングずれで「異なるクロックで確定」する結果、論理的にあり得ない組み合わせが一瞬生じます。2段FFを正しく入れても、この収束を見落とすとバグが残ります。グレイコードやハンドシェイクで「束ねて1つの整合点として渡す」のは、収束を構造的に防ぐためでもあります。
さらに精度を上げるには メタステーブル注入シミュレーション を併用します。同期前段の出力にランダムな遅延や反転を意図的に注入し、メタステーブルが下流の機能を壊さないか(=正しくシンクロナイザで吸収され、収束問題もないか)を動的に確認します。静的解析で構造を、注入シミュレーションで挙動を押さえる二段構えが実務の標準です。
「セットアップ/ホールド違反 → メタステーブル(中間電位で滞留する不定状態)」「未解決確率 exp(-t/τ)、MTBFは解決時間 t を指数の肩に持つ」「2段FFは1クロック分の解決時間を稼ぐが救えるのは1ビットのみ」「多ビットはグレイコード(隣接1ビット差)かハンドシェイクか非同期FIFO」「機能シミュレーションでは捕まらず静的CDC解析+メタステーブル注入で検証」の対応を押さえましょう。
まとめ
- 無関係なクロックの信号を受けるとセットアップ/ホールドを破り、出力が中間電位で滞留するメタステーブルに陥る。発生は消せず、解決時間を稼いで確率を下げるしかない。
- 信頼性は MTBF で測り、未解決確率
exp(-t/τ)ゆえ解決時間を増やすことが最も効くレバー。2段FFシンクロナイザは1クロック分の解決時間を与える定石だが、守れるのは1ビットだけ。 - 多ビットは収束スキューで偽値が出るため、隣接1ビット差のグレイコード、req/ackのハンドシェイク、内部でグレイポインタを使う非同期FIFOで安全化する。
- CDCバグは機能シミュレーションで再現しにくく、静的CDC解析で構造を網羅検査し、メタステーブル注入で挙動を確認する二段構えが標準。
クロックそのものの生成と分配は電源・クロックゲーティングが、ドメインをまたぐ大規模なデータ流通はオンチップネットワークが、CDC越しの不可分なやり取りはアトミック命令のハード実装が掘り下げます。
CPU/メモリ/ディスク Article
クロック同期と非同期設計 ─ メタステーブルとCDCを実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
CDC
比較で見る軸
難易度: advanced / カテゴリ: CPU/メモリ/ディスク / タグ数: 5
導入後に効く点
2段FFシンクロナイザは1段目がメタステーブルに落ちても1クロック分の解決時間を与え、MTBFを指数的に伸ばす定石。ただし救えるのは1ビットだけで、複数ビットを同時に渡すとビット間スキューで一瞬の不正値が生じるため使えない。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- CPU/メモリ/ディスク
- タグ数
- 5
判断チェックリスト
- 自社の用途が「CDC / メタステーブル」に近いか確認する。
- 強みである「送信側と無関係なタイミングで変化する信号を受信FFがサンプルすると、セットアップ/ホールド時間を破ってメタステーブル(中間電位で長く滞留する不定状態)に陥り、出力確定が遅れて下流がビット化けやプロトコル破綻を起こす。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。