跨时钟域处理:MUX/DMUX处理多比特数据跨时钟域

MUX 同步器这种方式,要求被同步的数据,跟随一个使能信号,如下图类型:

跨时钟域处理:MUX/DMUX处理多比特数据跨时钟域

这在特定的场景下是不难实现的,下面具体讲它的实现方式。

一、实现原理

想要将 data bus 从 clkA 转到 clkB(不论谁的频率快慢都一样),我们通过 data bus 的 valid 信号(属于 clkA),也就是图中的 data enable A,将 data enable A 使用 two flip-flop synchronizer 跨到 clkB,也就是 data enable B,并且使用 data enable B 当作最右边 DFF 的 flip-flop enable 信号(在图中使用 mux 来示意),由于 data enable A 的时序等同于 data bus,跨到 data enable B 时也就保证了 data bus 穿过 DFF 的信号已经稳定,即可拿来锁入最后一级 DFF,最后一级的 DFF 的 Q 即是 data bus 存在于 clk B domain 的稳定信号。

跨时钟域处理:MUX/DMUX处理多比特数据跨时钟域

我们将中间信号标注一下,以便于波形图分析使用:

跨时钟域处理:MUX/DMUX处理多比特数据跨时钟域

如上图,我们假设时钟 A 是慢时钟,我们的数据仅持续一个时钟即可被同步到 B 时钟域。根据电路,得到的波形图如下:

跨时钟域处理:MUX/DMUX处理多比特数据跨时钟域

根据电路框图,我们使用 Verilog 语言进行描述,然后仿真,看其效果:

module mux_synchronizer(

    input   wire        clka            ,
    input   wire        clkb            ,
    input   wire        rst             ,
    input   wire [3:0]  data_bus        ,
    input   wire        data_enable_a   ,
    output  reg         data_bus_b

    );

    reg             reg_data_enable_a       ;
    reg             data_enable_b_mid       ;
    reg             data_enable_b           ;
    reg     [3:0]   reg1_data_bus_a         ;

    wire    [3:0]   data_bus_mux            ;

    //时钟域 a 下同步本地数据及其有效标志信号,改善时序
    always@(posedge clka or posedge rst) begin
        if(rst) begin
            reg_data_enable_a <= 1'b0           ;
            reg1_data_bus_a   <= 4'd0           ;      
        end
        else begin
            reg_data_enable_a <= data_enable_a  ;
            reg1_data_bus_a   <= data_bus       ;
        end
    end

    //将数据有效标志信号同步到 b 时钟域,两级同步器
    always@(posedge clkb or posedge rst) begin
        if(rst) begin
            data_enable_b_mid <= 1'b0   ;
            data_enable_b <= 1'b0;
        end
        else begin
            data_enable_b_mid <= reg_data_enable_a;
            data_enable_b <= data_enable_b_mid;
        end
    end

    //写法 1:
    assign data_bus_mux = data_enable_b ? reg1_data_bus_a : data_bus_b;

    always@(posedge clkb or posedge rst) begin
        if(rst) begin
            data_bus_b <= 4'b0;
        end
        else begin
            data_bus_b <= data_bus_mux;
        end
    end

    // //写法 2:
    // always@(posedge clkb or posedge rst) begin
    //     if(rst) begin
    //         data_bus_b <= 4'b0;
    //     end
    //     else if(data_enable_b) begin
    //         data_bus_b <= reg1_data_bus_a;
    //     end
    //     else begin
    //         data_bus_b <= data_bus_b;
    //     end
    // end

endmodule

注意到,我们的注释处,有写法 2,这种描述,和电路图中的 MUX 写法是一致的。

其实 MUX 充当的作用就是触发器的一个使能信号,如果有带有使能的触发器,那就直接使用无疑了。 而 Xilinx 的 FPGA 中,就有这样的触发器呀,如下为上述电路的 RTL 图:

跨时钟域处理:MUX/DMUX处理多比特数据跨时钟域

综合后的原理图:

跨时钟域处理:MUX/DMUX处理多比特数据跨时钟域

实现后的原理图:

跨时钟域处理:MUX/DMUX处理多比特数据跨时钟域

下面对其功能进行仿真。

二、功能仿真

首先我们仿真从慢时钟到快时钟的情况,仿真平台如下:

module sim_mux_synchronizer(

    );

    reg             clka            ;
    reg             clkb            ;
    reg             rst             ;
    reg     [3:0]   data_bus        ;
    reg             data_enable_a   ;
    wire    [3:0]   data_bus_b      ;

    initial begin
        clka = 1'b0;
        forever begin
            #5 clka = ~clka;
        end
    end

    initial begin
        clkb = 1'b0;
        forever begin
            #2 clkb = ~clkb;
        end
    end

    initial begin
        rst = 1'b1;
        data_bus = 4'b0;
        data_enable_a = 1'b0;
        #15
        rst = 1'b0;

        #20
        @(posedge clka) begin
           data_bus = #0.5 4'b1101;
           data_enable_a = #0.5 1'b1;
        end
        @(posedge clka) begin
            data_bus =  #0.5 4'b0;
            data_enable_a = #0.5 1'b0;
        end

    end

    mux_synchronizer u_mux_synchronizer(
        .clka           ( clka           ),
        .clkb           ( clkb           ),
        .rst            ( rst            ),
        .data_bus       ( data_bus       ),
        .data_enable_a  ( data_enable_a  ),
        .data_bus_b     ( data_bus_b     )
    );

endmodule

由此得到仿真波形:

跨时钟域处理:MUX/DMUX处理多比特数据跨时钟域

可见,实现了我们想要的功能。

下面提一个问题:如果是从快时钟跨时钟域到慢时钟域呢?我们不妨简单仿真一下:

假设数据在快时钟域内持续时间大概是慢时钟域的三个时钟那么长,如下稍微修改即可得到仿真平台:

module sim_mux_synchronizer(

    );

    reg             clka            ;
    reg             clkb            ;
    reg             rst             ;
    reg     [3:0]   data_bus        ;
    reg             data_enable_a   ;
    wire    [3:0]   data_bus_b      ;

    initial begin
        clka = 1'b0;
        forever begin
            #2 clka = ~clka;
        end
    end

    initial begin
        clkb = 1'b0;
        forever begin
            #5 clkb = ~clkb;
        end
    end

    initial begin
        rst = 1'b1;
        data_bus = 4'b0;
        data_enable_a = 1'b0;
        #15
        rst = 1'b0;

        #20
        @(posedge clka) begin
           data_bus = #0.5 4'b1101;
           data_enable_a = #0.5 1'b1;
        end
        repeat(7) begin
            @(posedge clka);
        end
        @(posedge clka) begin
            data_bus =  #0.5 4'b0;
            data_enable_a = #0.5 1'b0;
        end

    end

    mux_synchronizer u_mux_synchronizer(
        .clka           ( clka           ),
        .clkb           ( clkb           ),
        .rst            ( rst            ),
        .data_bus       ( data_bus       ),
        .data_enable_a  ( data_enable_a  ),
        .data_bus_b     ( data_bus_b     )
    );

endmodule

得到仿真图:

跨时钟域处理:MUX/DMUX处理多比特数据跨时钟域

可见也是没问题的。但是这个方法也有局限性,如果是快时钟到慢时钟,且快时钟的数据使能脉冲很短,那么慢时钟那两个 DFF 都可能采不到快时钟的数据使能脉冲。

三、参考资料

扫码关注尚为网微信公众号

尚为网微信公众号
每天学习电路设计嵌入式系统的专业知识,关注一波,没准就用上了。

原创文章,作者:sunev,如若转载,请注明出处:https://www.sunev.cn/embedded/1276.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022年9月6日
下一篇 2022年9月12日

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注