• 跨时钟域的设计


    参考自fpga4fun.com

    part 1.跨时钟域的信号

    如果时钟域B需要使用来自时钟域A的信号,那么需要对这个信号进行同步。

    image

    如果输入信号比起时钟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

    image

    part 2 跨时钟的Flag

    当信号是一个短脉冲时

    image

       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.

    1. Gray code: If the data bus is a monotonic counter (i.e. only incrementing or decrementing), we can convert it to a gray code, which has the ability to cross clock domains (under certain timing conditions).
    2. Data freeze: If the data bus is non-monotonic, use a flag to signal the other domain to capture the value (while it is frozen in the source clock domain).
    3. Data burst: If the data bus has many consecutive values that need to cross the clock domain, use an FIFO, where you push values from the source clock domain, and read back values from the other domain.

    That's all folks!

    OPTIMISM, PASSION & HARDWORK
  • 相关阅读:
    静态类型的 NSUserDefaults
    [转]iOS 10.2 XCode 8.2 证书申请 远程推送 打包上架
    [转-备忘]iOS11.0后APP的图标和启动图
    [转-备忘] iOS navigationBar
    测试管理_关于测试管理职位的招聘面试题
    [性能测试]关于在线用户线大于10万用户的测试
    [稳定性测试]性能测试之稳定性测试培训
    [LoadRunner]LR11安装或破解时报错的解决方法
    [windows]win10家庭版切换到管理员账户
    [缺陷管理]缺陷处理机制
  • 原文地址:https://www.cnblogs.com/hiramlee0534/p/3817052.html
Copyright © 2020-2023  润新知