異なるクロック間での信号の乗せ変えNGパターン
異なる2つのクロック信号で動作する回路があった場合、その間での信号のやり取りにはなにを注意したらいいか、簡単に説明します。
多くのICでは、入力ピンのセットアップタイム、ホールドタイムが規定されています。
クロックの変化点の前後、セットアップタイム、ホールドタイムで指定された時間は入力信号を変化させてはいけないという制限です。
FPGAの内部回路でも同様の制限があります。同期回路の入力信号にはクロックの前後に制限が設けられています。しかし、1種類のクロックを使用している限りでは、タイミング調整はコンパイラが行ってくれますので、あまり気にしなくても回路が組めてしまいます。
2つ以上のクロックを入力して使用する場合、その間でのタイミング制限にはコンパイラは基本的に感知しません。
というよりも複数のクロックでは必ずセットアップタイム、ホールドタイムが違反する状態が存在するため、制限のしようがないのです。
ですから、設計者がタイミング違反を前提として回路を組んでやる必要があります。
タイミング違反のとき具体的にはどんなことが起こるのか、以下のモジュールを例に説明しましょう。
module DiffClkCount(
RESETn, CLK_A, CLK_B, COUNT
);
input RESETn; // system reset
input CLK_A; // system clock A
input CLK_B; // system clock B
output [3:0] COUNT;
reg [3:0] COUNT_A; // count register A
reg [3:0] COUNT_B; // count register B
always @ ( posedge CLK_A or negedge RESETn ) begin
if( !RESETn )
COUNT_A <= 4'h0;
else
COUNT_A <= COUNT_A + 1'b1;
end
always @ ( posedge CLK_B or negedge RESETn ) begin
if( !RESETn )
COUNT_B <= 4'h0;
else
COUNT_B <= COUNT_A + 1'b1;
end
assign COUNT = COUNT_B;
endmodule
COUNT_Aは順次カウントアップし、COUNT_BにはCOUNT_Aの値を代入しています。CLK_AとCLK_Bは違う信号です。しかし、CLK_AとCLK_Bにまったく同じ周波数のクロックを入れた場合には、COUNT_Bも同じようにカウントアップするはずです。
しかし、現実にこの回路をFPGAで組んだ場合、COUNT_Aは順番にカウントアップしているのに、COUNT_Bの値が崩れる場合があります。これは常にそうなるのではありません。例えば、FPGA内に上記の回路しか入らない場合だと、正常に動作するかもしれません。
FPGA内のロジックの配置状況、特定のタイミングで起こる現象ですので、気付かずに設計を進めてしまうと「たまに動作がおかしい」「今までは動作していたのに、別の機能を追加したら動かなくなった」という現象が発生することになります。
この書き方で正常に動くのは、二つのクロックの位相も含めて完全に同期している時だけです。その場合は、位相のずれがないように配線し、位相のずれがない前提でタイミング制約をかければ上手くいきます。まあ、そんなことを気にするよりも回路を変更したほうがいいですね。
セットアップタイム、ホールドタイムで違反が発生した場合、レジスタの入力は変化前、変化後、どちらの信号を取り込むのか不定になります。それどころか、レジスタの出力にも一時的な中間電位が現れ、後段の回路によって解釈が異なるということすら起こります。
また、FPGAの場合にはレジスタの配置がコンパイル毎に変更されます。コンパイルの度に、レジスタ間の信号遅延が変化してしまいますから、何が悪いのかさっぱりという事態になりかねません。
今回のように4bitという複数のレジスタでクロックの載せ変えを行う場合には、ビット毎に出力されるタイミング、取り込むタイミングが違います。そのため、同じタイミング違反、同じ不定であっても、あるビットは変化前を取り込み、あるビットは変化後を取り込んで出力に反映させるという結果になるのです。
この記事が気に入ったらサポートをしてみませんか?