FPGA設計におけるクロスオーバークロックドメイン問題(回転)

7033 ワード

1つのFPGA設計では複数のクロックが使用される場合があり、各クロックはFPGA内部に1つのクロックドメインを形成し、1つのクロックドメインで生成された信号が別のクロックドメインで使用される必要がある場合は、特に注意が必要である.
別のクロックドメインへの信号
クロックドメインCLKAで生成された信号をクロックドメインCLKBで使用する必要があると仮定すると、クロックドメインCLKBからの信号を受信し、新しい信号をCLKBに出力する「同期」設計が必要となる.
第1の設計では、クロックドメインCLKAおよびCLKBのクロックに対して信号の変化が遅いと仮定し、典型的には、2つのトリガを用いてクロックドメインCLKBに信号を同期させる.(具体的な理由は、その後私が翻訳したblogを参照)
module signal_crossdomain(
        clka,
        signalin,
        clkb,
        signalout
        );
input clka;
input signalin;
input clkb;
output signalout;
//信号のクロックドメイン間転送は、2つのシフトレジスタで「同期」
reg [1:0] synca_clkb;
always @(posedge clkb) synca_clkb[0] <= signalin;//clkbを使用していることに注意
always @(posedge clkb) synca_clkb[1] <= synca_clkb[0];//clkbを使用していることに注意
assign signalout = synca_clkb[1];
endmodule
この2つのトリガの使用により、信号に一定の遅延が生じます.例えば、次の図は、2つのトリガ同期時代波形図を使用します.
別のクロックドメインへのフラグ(FLAG)
さて、クロック領域にわたって伝達する必要がある信号が1クロック周期のパルス(フラグ信号FLAGと呼ばれる)であると仮定すると、前の設計は正常に動作しない可能性がある.このFLAGはCLKBによって見逃されたり延長されたり(複数のFLAGになる)、具体的にはCLKBの速度によって決定される可能性が高いからである.
同期器を使用していますが、FLAG信号のために設計されています.
設計のテクニックは、FLAG信号をレベル信号に変換してから、2つのトリガを使用して同期することです.
module Flag_CrossDomain(
        rst,
        clkA, 
        FlagIn_clkA, 
        clkB, 
        FlagOut_clkB
        );
//クロックドメインclkAの信号:clkA,FlagIn_clkA;  
//クロックドメインclkBの信号input clkB;     
input rst;
input clkA;
input FlagIn_clkA;
input clkB;
output FlagOut_clkB;
reg FlagToggle_clkA;
reg [2:0] SyncA_clkB;
always @(posedge clkA or negedge rst)
begin
        if(!rst) begin
                FlagToggle_clkA <= 1'b0;
        end
        else if(FlagIn_clkA) begin
                FlagToggle_clkA <= ~FlagToggle_clkA;//FLAGが来た時、レベルの状態を変える
        end
end
doalways @(posedge clkB or negedge rst)
begin
        if(!rst) begin
                SyncA_clkB <= 3'd0;
        end
        else begin
                SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA};//clk Bと同期
        end
end
assign FlagOut_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);//FLAG再生信号
endmodule
得られたシミュレーションの結果は以下の通りである.
この方法は、出力信号の2つのパルス間のclkbが2つの立ち上がりエッジを満たす必要がある場合、次の図に示すように、異なるクロック領域間の信号伝達を実現するためにいくつかの問題がある.
これにより、clkAドメインにbusy信号を設定して、clkBドメインが信号を処理していることを示すことができ、clkAドメインで再入力信号が無効になります.
 
module FlagAck_CrossDomain(      clkA, FlagIn_clkA, Busy_clkA,       clkB, FlagOut_clkB);  // clkA domain signals  input clkA, FlagIn_clkA;  output Busy_clkA;  // clkB domain signals  input clkB;  output FlagOut_clkB;  reg FlagToggle_clkA;  reg [2:0] SyncA_clkB;  reg [1:0] SyncB_clkA;  always @(posedge clkA) if(FlagIn_clkA & ~Busy_clkA) FlagToggle_clkA <= ~FlagToggle_clkA;  always @(posedge clkB) SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA};  always @(posedge clkA) SyncB_clkA <= {SyncB_clkA[0], SyncA_clkB[1]};  assign FlagOut_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);  assign Busy_clkA = FlagToggle_clkA ^ SyncB_clkA[1];  endmodule  

完了信号をclkBに追加することもできます
module TaskAck_CrossDomain(     clkA, TaskStart_clkA, TaskBusy_clkA, TaskDone_clkA,      clkB, TaskStart_clkB, TaskBusy_clkB, TaskDone_clkB);//clkA domain signalsinput clkA;input TaskStart_clkA;output TaskBusy_clkA, TaskDone_clkA;//clkB domain signalsinput clkB;output TaskBusy_clkB, TaskStart_clkB;input TaskDone_clkB;reg FlagToggle_clkA, Busyhold_clkB; reg [2:0] SyncA_clkB, SyncB_clkA;always @(posedge clkA) if(TaskStart_clkA & ~TaskBusy_clkA) FlagToggle_clkA <= ~FlagToggle_clkA;always @(posedge clkB) SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA};assign TaskStart_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);assign TaskBusy_clkB = TaskStart_clkB | Busyhold_clkB;always @(posedge clkB) Busyhold_clkB <= ~TaskDone_clkB & TaskBusy_clkB;always @(posedge clkA) SyncB_clkA <= {SyncB_clkA[1:0], Busyhold_clkB ^ SyncA_clkB[2]};assign TaskBusy_clkA = FlagToggle_clkA ^ SyncB_clkA[2];assign TaskDone_clkA = SyncB_clkA[2] ^ SyncB_clkA[1];endmoduleinput clkB;output TaskBusy_clkB, TaskStart_clkB;input TaskDone_clkB;reg FlagToggle_clkA, Busyhold_clkB; reg [2:0] SyncA_clkB, SyncB_clkA;always @(posedge clkA) if(TaskStart_clkA & ~TaskBusy_clkA) FlagToggle_clkA <= ~FlagToggle_clkA;always @(posedge clkB) SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA};assign TaskStart_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);assign TaskBusy_clkB = TaskStart_clkB | Busyhold_clkB;always @(posedge clkB) Busyhold_clkB <= ~TaskDone_clkB & TaskBusy_clkB;always @(posedge clkA) SyncB_clkA <= {SyncB_clkA[1:0], Busyhold_clkB ^ SyncA_clkB[2]};assign TaskBusy_clkA = FlagToggle_clkA ^ SyncB_clkA[2];assign TaskDone_clkA = SyncB_clkA[2] ^ SyncB_clkA[1];endmoduleinput clkB;output TaskBusy_clkB, TaskStart_clkB;input TaskDone_clkB;reg FlagToggle_clkA, Busyhold_clkB; reg [2:0] SyncA_clkB, SyncB_clkA;always @(posedge clkA) if(TaskStart_clkA & ~TaskBusy_clkA) FlagToggle_clkA <= ~FlagToggle_clkA;always @(posedge clkB) SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA};assign TaskStart_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);assign TaskBusy_clkB = TaskStart_clkB | Busyhold_clkB;always @(posedge clkB) Busyhold_clkB <= ~TaskDone_clkB & TaskBusy_clkB;always @(posedge clkA) SyncB_clkA <= {SyncB_clkA[1:0], Busyhold_clkB ^ SyncA_clkB[2]};assign TaskBusy_clkA = FlagToggle_clkA ^ SyncB_clkA[2];assign TaskDone_clkA = SyncB_clkA[2] ^ SyncB_clkA[1];endmodule Links To learn what is metastablity and why two flip-flops are used to cross clock domains, follow these links. What Is Metastability? and Interfacing Two Clock Domains from World of ASIC. Crossing the abyss from the EDN magazine. Digital Logic Metastability from interfacebus.com Metastability in electronics from Wikipedia. Synchronization in Digital Logic Circuits from Ryan Donohue. 
That's all folks! Have fun crossing clock domains
ソースアドレス:http://blog.xdnice.com/blog6i75177.html