MUXシンクロナイザ
2FFシンクロナイザは1ビットの信号には使えるが、多ビットの信号にそのまま使うと、現実の回路では信号間にスキューが生じるので各ビットが同時にサンプリングされるとは限らない。例えば3'b011→3'b100と変化したとき、過渡値3'b010をサンプリングしうる。
多ビット信号をCDC転送するにはどうすればよいだろうか
◇
1つの方法は、転送元のFFと転送先のFFが更新されるタイミングが重ならないように上位プロトコルで保証することである。例えば、両方のFFをソフトウェアで更新していれば逐次的にしか更新できないので、回路上は何もしなくても更新タイミングが重なることはない。
ここで、非同期転送FF間に組合せ回路(マルチプレクサ)が入っているので、前項で見たようにハザードをサンプリングしないかという心配がある。ハザードが出ると困るのは、マルチプレクサy = (en_b)? dat_a : dat_b においてen_b=0の間に、選択してない方の入力dat_aが変化した時である。一般のAND-ORゲートで組んだマルチプレクサでは、en_b=0でdat_aがANDされているので、dat_aが変化してもyにハザードは出ることはなく大丈夫である。
FPGAでは組合せ回路はAND-ORゲートでなくルックアップテーブル(LUT)で実現されるが、実は1個のLUTに収まっていれば大丈夫である。これは次項で詳しく調べる。
◇◇
上位プロトコルによるのではなく回路的に更新タイミングが重ならないようにするには、1ビットのイネーブル信号を使って更新タイミングを作ればよい。(マルチプレクサを使うのでここではMUXシンクロナイザとよぶ)
MUXシンクロナイザを使うとき、en_aとdat_aの更新周期tCLKAとclk_bの周期tCLKBの間には制約がある。
図においてclk_aのエッジがclk_bのエッジ0-1間にあるとき、dat_aはclk_bのエッジ3でサンプリングされるので、
3 * tCLKB +Δ< tCLKA (Δはen_aとdat_aのスキュー)
と、clk_bはclk_aより少なくとも3倍速くなければならない。(実際はΔを考慮して4倍以上にした方がよい)
clk_bがもう少し遅くてもよいようにするには、dat_aの方も2FFで受ければよい。このときen_bが変化するよりも前にdat_bの入力が確定していなければならないという条件(→補足)からen_aの方も1段増やす必要がある。
このとき、clk_aのエッジがclk_bのエッジ0-1間にあるとき、en_bはclk_bのエッジ4で有効になるので、dat_aはclk_bのエッジ2でサンプリングすればよく、
2 * tCLKB +Δ< tCLKA (Δはen_aとdat_aのスキュー)
と、clk_bはclk_aより少なくとも2倍速ければよい。(実際はを考慮して3倍以上にした方がよい)
◇◇◇
(補足) イネーブルen_aとデータdat_aの両方を2FFで受けると不都合な理由
en_aとdat_aの変化タイミングがclk_bのサンプリングと重なった場合、en_a=1かつdat_a=過渡値をサンプリングしうるので、このときdat_bが過渡値になってしまう。