一、慢速多周期信号
Signal-in为clkA时钟域多周期信号。此时只需要用clkB打两拍即可。
module Signal_CrossDomain(
input rst_p;
input clkA, // we actually don't need clkA in that example, but it is here for completeness as we'll need it in further examples
input SignalIn_clkA,
input clkB,
output SignalOut_clkB
);
// We use a two-stages shift-register to synchronize SignalIn_clkA to the clkB clock domain
reg [1:0] SyncA_clkB;
always @(posedge clkB) begin
if(rst_p == 1'b1)
SyncA_clkB[0] <= 1'b0;
else
SyncA_clkB[0] <= SignalIn_clkA; // notice that we use clkB
end
always @(posedge clkB) begin
if(rst_p == 1'b1)
SyncA_clkB[1] <= 1'b0;
else
SyncA_clkB[1] <= SyncA_clkB[0]; // notice that we use clkB
end
assign SignalOut_clkB = SyncA_clkB[1]; // new signal synchronized to (=ready to be used in) clkB domain
endmodule
二、单周期信号
FlagIn(代码里表示为FlagIn_clkA)此时为clkA时钟域产生的单周期信号。
module Flag_CrossDomain(
input rst_p;
input clkA,
input FlagIn_clkA, // this is a one-clock pulse from the clkA domain
input clkB,
output FlagOut_clkB // from which we generate a one-clock pulse in clkB domain
);
reg FlagToggle_clkA = 1'b0;
reg [2:0] SyncA_clkB = 3'b000;
always @(posedge clkA) bein
if(rst_p == 1'b1)
FlagToggle_clkA <= 1'b0;
else
FlagToggle_clkA <= FlagToggle_clkA ^ FlagIn_clkA; // when flag is asserted, this signal toggles (clkA domain)
end
always @(posedge clkB) begin
if(rst_p == 1'b1)
SyncA_clkB <= 3'b000;
else
SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA}; // now we cross the clock domains
end
assign FlagOut_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]); // and create the clkB flag
如果clkA端需要知道clkB端是否接收到了信号,可以添加一个busy信号
module Flag_CrossDomain(
input rst_p,
input clkA,
input FlagIn_clkA, // this is a one-clock pulse from the clkA domain
output Busy_clkA,
input clkB,
output FlagOut_clkB // from which we generate a one-clock pulse in clkB domain
);
reg FlagToggle_clkA;
reg [2:0] SyncA_clkB;
reg [1:0] SyncB_clkA;
always @(posedge clkA)begin
if(rst_p == 1'b1)
FlagToggle_clkA <= 1'b0;
else
FlagToggle_clkA <= FlagToggle_clkA ^ (FlagIn_clkA & ~Busy_clkA);
end
always @(posedge clkB)begin
if(rst_p == 1'b1)
SyncA_clkB <= 3'b000;
else
SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA};
end
always @(posedge clkA)begin
if(rst_p == 1'b1)
SyncB_clkA <= 2'b00;
else
SyncB_clkA <= {SyncB_clkA[0], SyncA_clkB[2]};
end
assign FlagOut_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);
assign Busy_clkA = FlagToggle_clkA ^ SyncB_clkA[1];
endmodule
三、Task
如果clkA时钟域中有一个任务需要在clkB时钟域完成,可以遵循以下设计
module TaskAck_CrossDomain(
input clkA,
input TaskStart_clkA,
output TaskBusy_clkA, TaskDone_clkA,
input clkB,
output TaskStart_clkB, TaskBusy_clkB,
input TaskDone_clkB
);
reg FlagToggle_clkA, FlagToggle_clkB, Busyhold_clkB;
reg [2:0] SyncA_clkB, SyncB_clkA;
always @(posedge clkA) FlagToggle_clkA <= FlagToggle_clkA ^ (TaskStart_clkA & ~TaskBusy_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 clkB) if(TaskBusy_clkB & TaskDone_clkB) FlagToggle_clkB <= FlagToggle_clkA;
always @(posedge clkA) SyncB_clkA <= {SyncB_clkA[1:0], FlagToggle_clkB};
assign TaskBusy_clkA = FlagToggle_clkA ^ SyncB_clkA[2];
assign TaskDone_clkA = SyncB_clkA[2] ^ SyncB_clkA[1];
endmodule