在一个FPGA设计中可能会用到多个时钟,每个时钟在FPGA内部形成一个时钟域,如果在一个时钟域中产生的信号需要在另一个时钟域中使用,那么需要特别小心!
到另一个时钟域的信号
假设一个在时钟域CLKA产生的信号需要在时钟域CLKB中使用,那么它需要首先与时钟域CLKB“同步”,也就是说需要一个“同步”设计,它接受来自时钟域CLKA的信号,并产生一个新的信号输出到CLKB。
rst,
clkA,
FlagIn_clkA,
clkB,
FlagOut_clkB
);
// 时钟域 clkB 的信号input clkB;
input rst;
input clkA;
input FlagIn_clkA;
input clkB;
output FlagOut_clkB;
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
得到的仿真结果如下:
这种方法来实现不同时钟域之间信号传递会存在一些问题,如当输出信号的两个脉冲之间的clkb需要满足有两个上升沿,负责会出现问题,如下图所示:
这样我们可以在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 signals
input clkA;
input TaskStart_clkA;
output TaskBusy_clkA, TaskDone_clkA;
// clkB domain signals
input 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
input 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
input 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