参考自fpga4fun.com
part 1.跨时钟域的信号
如果时钟域B需要使用来自时钟域A的信号,那么需要对这个信号进行同步。
如果输入信号比起时钟B来讲变化较慢,可以使用两个触发器来完成
1: module Signal_CrossDomain(
2: 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
3: input SignalIn_clkA,
4: input clkB,
5: output SignalOut_clkB
6: );
7:
8: // We use a two-stages shift-register to synchronize SignalIn_clkA to the clkB clock domain
9: reg [1:0] SyncA_clkB;
10: always @(posedge clkB) SyncA_clkB[0] <= SignalIn_clkA; // notice that we use clkB
11: always @(posedge clkB) SyncA_clkB[1] <= SyncA_clkB[0]; // notice that we use clkB
12:
13: assign SignalOut_clkB = SyncA_clkB[1]; // new signal synchronized to (=ready to be used in) clkB domain
14: endmodule
part 2 跨时钟的Flag
当信号是一个短脉冲时
1: module Flag_CrossDomain(
2: input clkA,
3: input FlagIn_clkA,
4: input clkB,
5: output FlagOut_clkB
6: );
7:
8: // this changes level when the FlagIn_clkA is seen in clkA
9: reg FlagToggle_clkA;
10: always @(posedge clkA) FlagToggle_clkA <= FlagToggle_clkA ^ FlagIn_clkA;
11:
12: // which can then be sync-ed to clkB
13: reg [2:0] SyncA_clkB;
14: always @(posedge clkB) SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA};
15:
16: // and recreate the flag in clkB
17: assign FlagOut_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);
18: endmodule
1: module FlagAck_CrossDomain(
2: input clkA,
3: input FlagIn_clkA,
4: output Busy_clkA,
5: input clkB,
6: output FlagOut_clkB
7: );
8:
9: reg FlagToggle_clkA;
10: always @(posedge clkA) FlagToggle_clkA <= FlagToggle_clkA ^ (FlagIn_clkA & ~Busy_clkA);
11:
12: reg [2:0] SyncA_clkB;
13: always @(posedge clkB) SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA};
14:
15: reg [1:0] SyncB_clkA;
16: always @(posedge clkA) SyncB_clkA <= {SyncB_clkA[0], SyncA_clkB[2]};
17:
18: assign FlagOut_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);
19: assign Busy_clkA = FlagToggle_clkA ^ SyncB_clkA[1];
20: endmodule
part3 task
1: module TaskAck_CrossDomain(
2: input clkA,
3: input TaskStart_clkA,
4: output TaskBusy_clkA, TaskDone_clkA,
5:
6: input clkB,
7: output TaskStart_clkB, TaskBusy_clkB,
8: input TaskDone_clkB
9: );
10:
11: reg FlagToggle_clkA, FlagToggle_clkB, Busyhold_clkB;
12: reg [2:0] SyncA_clkB, SyncB_clkA;
13:
14: always @(posedge clkA) FlagToggle_clkA <= FlagToggle_clkA ^ (TaskStart_clkA & ~TaskBusy_clkA);
15:
16: always @(posedge clkB) SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA};
17: assign TaskStart_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);
18: assign TaskBusy_clkB = TaskStart_clkB | Busyhold_clkB;
19: always @(posedge clkB) Busyhold_clkB <= ~TaskDone_clkB & TaskBusy_clkB;
20: always @(posedge clkB) if(TaskBusy_clkB & TaskDone_clkB) FlagToggle_clkB <= FlagToggle_clkA;
21:
22: always @(posedge clkA) SyncB_clkA <= {SyncB_clkA[1:0], FlagToggle_clkB};
23: assign TaskBusy_clkA = FlagToggle_clkA ^ SyncB_clkA[2];
24: assign TaskDone_clkA = SyncB_clkA[2] ^ SyncB_clkA[1];
25: endmodule
To move a data bus (2 bits wide or more) from one clock domain to another, we have several techniques to our disposal.
Here are a few ideas.
That's all folks!