IC设计基础系列之CDC篇5:跨时钟域信号处理 (发起请求信号和回传确定信号,有状态图,有代码)

来源:互联网 发布:软件安装权限 编辑:程序博客网 时间:2024/06/05 17:30

来自:http://blog.csdn.net/skyplain1984/article/details/54782968


一、慢速多周期信号

Signal-in为clkA时钟域多周期信号。此时只需要用clkB打两拍即可。
[plain] view plain copy print?
  1. module Signal_CrossDomain(  
  2.     input rst_p;  
  3.     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  
  4.     input SignalIn_clkA,  
  5.     input clkB,  
  6.     output SignalOut_clkB  
  7. );  
  8.   
  9. // We use a two-stages shift-register to synchronize SignalIn_clkA to the clkB clock domain  
  10. reg [1:0] SyncA_clkB;  
  11.   
  12. always @(posedge clkB) begin  
  13.     if(rst_p == 1'b1)  
  14.         SyncA_clkB[0] <= 1'b0;  
  15.     else  
  16.         SyncA_clkB[0] <= SignalIn_clkA;   // notice that we use clkB  
  17. end  
  18.   
  19. always @(posedge clkB) begin  
  20.     if(rst_p == 1'b1)  
  21.         SyncA_clkB[1] <= 1'b0;  
  22.     else  
  23.         SyncA_clkB[1] <= SyncA_clkB[0];   // notice that we use clkB  
  24. end  
  25.   
  26. assign SignalOut_clkB = SyncA_clkB[1];  // new signal synchronized to (=ready to be used in) clkB domain  
  27.   
  28. endmodule  



二、单周期信号


FlagIn(代码里表示为FlagIn_clkA)此时为clkA时钟域产生的单周期信号。
[plain] view plain copy print?
  1. module Flag_CrossDomain(  
  2.     input rst_p;  
  3.     input clkA,  
  4.     input FlagIn_clkA,   // this is a one-clock pulse from the clkA domain  
  5.     input clkB,  
  6.     output FlagOut_clkB   // from which we generate a one-clock pulse in clkB domain  
  7. );  
  8.   
  9. reg FlagToggle_clkA = 1'b0;  
  10. reg [2:0] SyncA_clkB = 3'b000;  
  11.   
  12. always @(posedge clkA) bein  
  13.     if(rst_p == 1'b1)  
  14.         FlagToggle_clkA <= 1'b0;  
  15.     else  
  16.         FlagToggle_clkA <= FlagToggle_clkA ^ FlagIn_clkA;  // when flag is asserted, this signal toggles (clkA domain)  
  17. end  
  18.   
  19. always @(posedge clkB) begin  
  20.     if(rst_p == 1'b1)  
  21.         SyncA_clkB <= 3'b000;  
  22.     else  
  23.         SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA};  // now we cross the clock domains  
  24. end  
  25.   
  26. assign FlagOut_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);  // and create the clkB flag  

如果clkA端需要知道clkB端是否接收到了信号,可以添加一个busy信号

[plain] view plain copy print?
  1. module Flag_CrossDomain(  
  2.     input rst_p,  
  3.     input clkA,  
  4.     input FlagIn_clkA,   // this is a one-clock pulse from the clkA domain  
  5.     output Busy_clkA,  
  6.     input clkB,  
  7.     output FlagOut_clkB   // from which we generate a one-clock pulse in clkB domain  
  8. );  
  9.   
  10. reg FlagToggle_clkA;  
  11. reg [2:0] SyncA_clkB;  
  12. reg [1:0] SyncB_clkA;  
  13.   
  14. always @(posedge clkA)begin  
  15.     if(rst_p == 1'b1)  
  16.         FlagToggle_clkA <= 1'b0;  
  17.     else   
  18.         FlagToggle_clkA <= FlagToggle_clkA ^ (FlagIn_clkA & ~Busy_clkA);  
  19. end  
  20.   
  21. always @(posedge clkB)begin  
  22.     if(rst_p == 1'b1)  
  23.         SyncA_clkB <= 3'b000;  
  24.     else  
  25.         SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA};  
  26. end  
  27.   
  28. always @(posedge clkA)begin  
  29.     if(rst_p == 1'b1)  
  30.         SyncB_clkA <= 2'b00;  
  31.     else  
  32.         SyncB_clkA <= {SyncB_clkA[0], SyncA_clkB[2]};  
  33. end  
  34.   
  35. assign FlagOut_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);  
  36. assign Busy_clkA = FlagToggle_clkA ^ SyncB_clkA[1];  
  37.   
  38. endmodule  

三、Task

如果clkA时钟域中有一个任务需要在clkB时钟域完成,可以遵循以下设计

[plain] view plain copy print?
  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  


阅读全文
0 0
原创粉丝点击