異なるクロック間の信号乗せ換え:バス編
前回の記事で「異なるクロック間の信号乗せ換えの基本」と題して1bitの信号のクロック乗せ換えについて説明しました。
そんなわけで今回は複数bitの信号の場合です。
クロックが違うとセットアップタイム、ホールドタイムの違反が必ず発生します。1bitであれば、変化点にあたっても変化前を取ったのか、変化後を取ったのかくらいの話で済みますから、変な中間電位が伝わることだけ防げれば問題ありませんでした。
複数bitの場合には、この、「変化前を取ったのか、変化後を取ったのか」が重要になります。1bit目は変化前を、2bit目は変化後を取ってしまうと、バス信号として見たときに出鱈目なデータになってしまうからです。
そのため、複数bitのバス信号を乗せ換える場合には、変化していないタイミングで乗せ換えるか、非同期のFIFOを使用します。
変化していないタイミングで乗せ換える回路の例です。
module DiffClkCnvBus(
RESETn, CLK_A, DATA_A, CLK_B, DATA_B
);
input RESETn; // system reset
input CLK_A; // system clock A
input [7:0] DATA_A; // input data A
input CLK_B; // system clock B
output [7:0] DATA_B; // output data B
reg [7:0] tmp_A; // tmp register A clock
reg [7:0] tmp_B1; // tmp register B clock
reg [7:0] tmp_B2; // tmp register B clock
reg [7:0] tmp_B3; // tmp register B clock
reg [7:0] tmp_B4; // tmp register B clock
always @ ( posedge CLK_A or negedge RESETn ) begin
if( !RESETn )
tmp_A <= 8'h0;
else
tmp_A <= DATA_A;
end
always @ ( posedge CLK_B or negedge RESETn ) begin
if( !RESETn ) begin
tmp_B1 <= 8'h0;
tmp_B2 <= 8'h0;
tmp_B3 <= 8'h0;
end
else begin
tmp_B1 <= tmp_A;
tmp_B2 <= tmp_B1;
tmp_B3 <= tmp_B2;
end
end
always @ ( posedge CLK_B or negedge RESETn ) begin
if( !RESETn )
tmp_B4 <= 8'h0;
else if( tmp_B2 == tmp_B3 )
tmp_B4 <= tmp_B3;
else
tmp_B3 <= tmp_B3;
end
assign DATA_B = tmp_B4;
まずは、1bitの時と同様に2段のフリップフロップを使ってCLK_Bに乗せ換えます。
複数bitの場合には、その後にもう一段、フリップフロップtmp_B3にも代入し、前段のtmp_B2と等しい値かどうかをチェックします。これは変化していないタイミングを検知するためのものです。
tmp_B2とtmp_B3の値が等しければ、入力が変化していないと判断し、最後のtmp_B4に代入します。
変化していないタイミングを計ることで「変化前を取ったのか、変化後を取ったのか」という問題を回避する方法です。
しかし、この方法は、入力が絶えず変化している場合には適しません。
この方法で絶えず変化する入力信号の、変化しないタイミングを計るためには、CLK_Aの数倍の速度がCLK_Bに必要になります。
入力が絶えず変化し、入出力のクロック周波数に大きな差がない場合には、非同期のFIFOを使用します。
非同期のFIFOは、FPGA自体が非同期FIFOに対応した構造を持っている必要があります。
FPGAの機能としての非同期FIFOですので、使う際にはメーカーのIPを使います。
Vivadoの場合ですとIP Catalogから「FIFO Generator」を呼び出して使用します。
非同期FIFOを使えば、入出力クロックに差があまりない環境で、入力データが常に変化していても対応出来ます。
ただし、入力クロックの周波数が高かった場合にはFIFOが頻繁に溢れますし、出力クロックの周波数が高かった場合にはFIFOは常に空の状態に近いでしょう。
そのあたりの制御はFullやEmptyのフラグを管理して行う必要があります。制御回路が複雑になりがちです。必要な条件を精査してからロジックを組むことをお勧めします。
二つの方法を説明しました。
いずれも、入出力のクロック周波数の差、入力信号を全て伝えたいのか、最新のデータだけが見えればいいのか、そういったいくつかの条件で細かい手法が変わってきます。
出力クロックが入力クロックよりも明らかに遅いのに、全ての入力データを出力で見たい、というのは不可能です。繰り返しになりますが、必要な条件を精査してからロジックを組むことをお勧めします。
この記事が気に入ったらサポートをしてみませんか?