• FPGA设计中的跨时钟域问题


    转自:http://blog.163.com/sunhuifxd@126/blog/static/55859443201010131042581

    跨时钟域问题

    在一个FPGA设计中可能会用到多个时钟,每个时钟在FPGA内部形成一个时钟域,如果在一个时钟域中产生的信号需要在另一个时钟域中使用,那么需要特别小心!

    到另一个时钟域的信号

    假设一个在时钟域CLKA产生的信号需要在时钟域CLKB中使用,那么它需要首先与时钟域CLKB“同步”,也就是说需要一个“同步”设计,它接受来自时钟域CLKA的信号,并产生一个新的信号输出到CLKB。

    FPGA设计中的跨时钟域问题(转) - huihui - 辉辉的博客
    在第一个设计中,我们假设信号的改变相对于时钟域CLKA和CLKB的时钟都是很慢的,典型的做法是使用两个触发器来将信号同步到时钟域CLKB。(具体原因参考随后我翻译的blog)
    module signal_crossdomain(
            clka,
            signalin,
            clkb,
            signalout
            );
    input clka;
    input signalin;
    input clkb;
    output signalout;
    //信号的跨时钟域传递,使用两个移位寄存器来进行“同步”
    reg [1:0] synca_clkb;
    always @(posedge clkb) synca_clkb[0] <= signalin;   //注意使用的是clkb
    always @(posedge clkb) synca_clkb[1] <= synca_clkb[0];  //注意我们使用的是clkb
    assign signalout = synca_clkb[1];
    endmodule
    由于这两个触发器的使用,会使得信号有一定的延迟,例如下图就是使用两个触发器同步时代波形图:
    FPGA设计中的跨时钟域问题(转) - huihui - 辉辉的博客
    到另一个时钟域的标志(FLAG)
    好了,假设需要跨时钟域传递的信号是一个宽度仅为1个时钟周期的脉冲(称为标志信号FLAG),那么前面的设计可能就不会正常工作了,因为这个FLAG很可能被CLKB错过或者延长(变成多个FLAG),具体是由CLKB的速度决定的。
    我们仍然使用一个同步器,但是它是为FLAG信号设计的
    FPGA设计中的跨时钟域问题(转) - huihui - 辉辉的博客
     设计的技巧是先把FLAG信号转换为电平信号,然后再使用两个触发器来同步。
    module Flag_CrossDomain(
            rst,
            clkA, 
            FlagIn_clkA, 
            clkB, 
            FlagOut_clkB
            );
    // 时钟域 clkA 的信号:clkA, FlagIn_clkA;  
    // 时钟域 clkB 的信号input clkB;     
    input rst;
    input clkA;
    input FlagIn_clkA;
    input clkB;
    output FlagOut_clkB;
    reg FlagToggle_clkA;
    reg [2:0] SyncA_clkB;
    always @(posedge clkA or negedge rst)
    begin
            if(!rst) begin
                    FlagToggle_clkA <= 1'b0;
            end
            else if(FlagIn_clkA) begin
                    FlagToggle_clkA <= ~FlagToggle_clkA;  // 当FLAG来到时,改变电平状态
            end
    end
    doalways @(posedge clkB or negedge rst)
    begin
            if(!rst) begin
                    SyncA_clkB <= 3'd0;
            end
            else begin
                    SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA};   // 与clk B同步
            end
    end
    assign FlagOut_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);  // 重生FLAG信号
    endmodule
    得到的仿真结果如下:

    FPGA设计中的跨时钟域问题(转) - huihui - 辉辉的博客

    这种方法来实现不同时钟域之间信号传递会存在一些问题,如当输出信号的两个脉冲之间的clkb需要满足有两个上升沿,负责会出现问题,如下图所示:

    FPGA设计中的跨时钟域问题(转) - huihui - 辉辉的博客

    这样我们可以在clkA域中设置一个busy信号来指示clkB域正在处理信号,这时候clkA域中再输入信号是无效的:

    FPGA设计中的跨时钟域问题(转) - huihui - 辉辉的博客

     

    module FlagAck_CrossDomain(      clkA, FlagIn_clkA, Busy_clkA,       clkB, FlagOut_clkB);  // clkA domain signals  
    input clkA, FlagIn_clkA;  
    output Busy_clkA;  // clkB domain signals  
    input clkB;  
    output FlagOut_clkB;  
    reg FlagToggle_clkA;  
    reg [2:0] SyncA_clkB;  
    reg [1:0] SyncB_clkA; 
    always @(posedge clkA) 
    if(FlagIn_clkA & ~Busy_clkA) 
    FlagToggle_clkA <= ~FlagToggle_clkA;  
    always @(posedge clkB) 
    SyncA_clkB <= {SyncA_clkB[1:0], FlagToggle_clkA};  
    always @(posedge clkA) 
    SyncB_clkA <= {SyncB_clkA[0], SyncA_clkB[1]};  
    assign FlagOut_clkB = (SyncA_clkB[2] ^ SyncA_clkB[1]);  
    assign Busy_clkA = FlagToggle_clkA ^ SyncB_clkA[1];  
    endmodule

    也可以在clkB中也添加一个完成信号

    FPGA设计中的跨时钟域问题(转) - huihui - 辉辉的博客

    module TaskAck_CrossDomain(
        clkA, TaskStart_clkA, TaskBusy_clkA, TaskDone_clkA, 
        clkB, TaskStart_clkB, TaskBusy_clkB, TaskDone_clkB);
    // clkA domain signals
    input clkA;
    input TaskStart_clkA;
    output TaskBusy_clkA, TaskDone_clkA;
    // clkB domain signals
    input clkB;
    output TaskBusy_clkB, TaskStart_clkB;
    input TaskDone_clkB;
    reg FlagToggle_clkA, Busyhold_clkB; reg [2:0] SyncA_clkB, SyncB_clkA;
    always @(posedge clkA) if(TaskStart_clkA & ~TaskBusy_clkA) FlagToggle_clkA <= ~FlagToggle_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 clkA) SyncB_clkA <= {SyncB_clkA[1:0], Busyhold_clkB ^ SyncA_clkB[2]};
    assign TaskBusy_clkA = FlagToggle_clkA ^ SyncB_clkA[2];
    assign TaskDone_clkA = SyncB_clkA[2] ^ SyncB_clkA[1];
    endmodule
    input
     clkB;
    output TaskBusy_clkB, TaskStart_clkB;
    input TaskDone_clkB;
    reg FlagToggle_clkA, Busyhold_clkB; reg [2:0] SyncA_clkB, SyncB_clkA;
    always @(posedge clkA) if(TaskStart_clkA & ~TaskBusy_clkA) FlagToggle_clkA <= ~FlagToggle_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 clkA) SyncB_clkA <= {SyncB_clkA[1:0], Busyhold_clkB ^ SyncA_clkB[2]};
    assign TaskBusy_clkA = FlagToggle_clkA ^ SyncB_clkA[2];
    assign TaskDone_clkA = SyncB_clkA[2] ^ SyncB_clkA[1];
    endmodule
    input
     clkB;
    output TaskBusy_clkB, TaskStart_clkB;
    input TaskDone_clkB;
    reg FlagToggle_clkA, Busyhold_clkB; reg [2:0] SyncA_clkB, SyncB_clkA;
    always @(posedge clkA) if(TaskStart_clkA & ~TaskBusy_clkA) FlagToggle_clkA <= ~FlagToggle_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 clkA) SyncB_clkA <= {SyncB_clkA[1:0], Busyhold_clkB ^ SyncA_clkB[2]};
    assign TaskBusy_clkA = FlagToggle_clkA ^ SyncB_clkA[2];
    assign TaskDone_clkA = SyncB_clkA[2] ^ SyncB_clkA[1];
    endmodule
    Links
    To learn what is metastablity and why two flip-flops are used to cross clock domains, follow these links. 
    What Is Metastability? and Interfacing Two Clock Domains from World of ASIC. 
    Crossing the abyss from the EDN magazine. 
    Digital Logic Metastability from interfacebus.com 
    Metastability in electronics from Wikipedia. 
    Synchronization in Digital Logic Circuits from Ryan Donohue. 

    That's all folks!
    Have fun crossing clock domains

     源地址:http://blog.xdnice.com/blog6i75177.html

    03/

  • 相关阅读:
    C++ 对象没有显式初始化
    NFA与DFA
    VS DLL 复制本地
    TFS 图标意思
    C++ 析构方法
    C++ 异常
    【转】二叉树的非递归遍历
    【转】Dijkstra算法(单源最短路径)
    Dijkstra最短路径算法
    python __name__
  • 原文地址:https://www.cnblogs.com/youngforever/p/3104708.html
Copyright © 2020-2023  润新知