zoukankan      html  css  js  c++  java
  • 跨时钟域的设计

    参考自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
  • 相关阅读:
    面板数据及其基本模型
    markdwon编辑公式入门
    向纳什大神致敬
    我和我的祖国观后感
    少年的你观后感
    特征选择学习笔记1(综述)
    时间序列学习笔记1
    《绿皮书》观后感
    《美丽心灵》观后感
    pycharm跨目录调用文件
  • 原文地址:https://www.cnblogs.com/hiramlee0534/p/3817052.html
Copyright © 2011-2022 走看看