見出し画像

異なるクロック間の信号乗せ換えの基本

 クロックが違うとセットアップタイム、ホールドタイムの違反が必ず発生します。
 しかし、昔ならともかく、今のFPGAでクロックが一系統しか存在しないというデザインは稀です。
 そのため、異なるクロックに乗せ換えても問題が発生しないように設計することが必要です。

 やり方は幾つかあります。
 今回はその中でも一番基本的なやり方を説明します。
 そのやり方とは「二つのフリップフロップを通す」です。
 Duble Frip Fropとか、単に2FFとか、呼び名はいくつかありますが、やることは単純です。

 以下、1bitの信号をクロック乗せ換えする例です。

module DiffClkCnv(
    RESETn, CLK_A, DATA_A, CLK_B, DATA_B
);

input RESETn; // system reset
input CLK_A; // system clock A
input DATA_A; // input data A
input CLK_B; // system clock B
output DATA_B; // output data B

reg tmp_A; // tmp register A clock
reg tmp_B1; // tmp register B clock
reg tmp_B2; // tmp register B clock

always @ ( posedge CLK_A or negedge RESETn ) begin
    if( !RESETn )
        tmp_A <= 1'b0;
    else
        tmp_A <= DATA_A;
    end

always @ ( posedge CLK_B or negedge RESETn ) begin
    if( !RESETn ) begin
        tmp_B1 <= 1'b0;
        tmp_B2 <= 1'b0;
    end
    else begin
        tmp_B1 <= tmp_A;
        tmp_B2 <= tmp_B1;
    end
end

assign DATA_B = tmp_B2;


 入力のDATA_AはCLK_Aに同期しています。
 これをCLK_Bに同期させるには、tmp_B1, tmp_B2という2つのフリップフロップを使ってCLK_Bに乗せ換えます。

 さて、なぜフリップフロップを2つ使うのでしょうか。
 これはセットアップタイム、ホールドタイムの違反が必ず発生することへの対処のためです。

 セットアップタイム、ホールドタイムの違反が起きた場合、tmp_B1の出力はHでもLでもない中間電圧が出てしまったり、本来の出力遅延よりも長い時間を掛けて、信号が変化することがあります。
 これを後段のtmp_B2で受けることで、HかLかをハッキリさせることが出来ます。

 これを後段のtmp_B2が存在せず、他のロジックに繋げた場合には問題が発生します。
 接続先のロジックがフリップフロップであれば、どちらでも問題ないようにも、見えますが、それも接続先が1つである場合だけです。

 セットアップタイム、ホールドタイムの違反が起きた場合、tmp_B1の出力はHでもLでもない中間電圧が出てしまったと仮定します。
 接続先の回路が2つ以上あった場合、1つ目の回路ではHと認識、2つ目の回路ではLと認識するということが起こりえます。

 こうなるといくらロジックを追いかけても「ありえない動作をする」ということになってしまいます。
 後段のフリップフロップがHと認識しようと、Lと認識しようと、どうせセットアップタイム、ホールドタイムの違反なのですから、変化前を取ったのか、変化後を取ったのかくらいの話です。
 ですが、同じタイミングで、同じ信号を受けているのに、HとLが異なると言われてしまうと困ってしまいます。
 ですから、必ず2段のフリップフロップを使い、HかLか、どちらかに安定させることが必要です。

この記事が気に入ったらサポートをしてみませんか?