多比特跨时钟域之握手及DMUX

一、握手toggle

握手又称结绳法,适用场景为数据有效信号在数据信号前一个周期或数据有效信号在数据的第一个周期,且在握手期间,数据需要保持不变,直到源时钟域收到了解绳的有效信号。

源码如下:

module toggle(
    input wire clka,
    input wire clkb,
    input wire rst_n,
    input wire a_en,
    input wire [7:0] data_a_in,

    output reg [7:0] data_b_out,
    output wire b_en,
    output wire ack_a
    );

    reg a_en_d1;
    reg a_en_d2;
    wire a_en_neg;
    
    reg a_req;

    reg req_d1;
    reg req_d2;
    
    reg ack_d1;
    reg ack_d2;

    wire ack_pos;

    always@(posedge clka or negedge rst_n)begin
        if(!rst_n)begin
            a_en_d1 <= 1'b0;
            a_en_d2 <= 1'b0;
        end
        else begin
            a_en_d1 <= a_en;
            a_en_d2 <= a_en_d1;
        end
    end

    assign a_en_neg = a_en_d2 && (~a_en_d1);

    always@(posedge clka or negedge rst_n)begin
        if(!rst_n)
            a_req <= 1'b0;
        else if(a_en_neg)
            a_req <= 1'b1;
        else if(ack_pos)
            a_req <= 1'b0;
    end

    always@(posedge clkb or negedge rst_n)begin
        if(!rst_n)begin
            req_d1 <= 1'b0;
            req_d2 <= 1'b0;
        end
        else begin
            req_d1 <= a_req;
            req_d2 <= req_d1;
        end
    end

    always@(posedge clka or negedge rst_n)begin
        if(!rst_n)begin
            ack_d1 <= 1'b0;
            ack_d2 <= 1'b0;
        end
        else begin
            ack_d1 <= req_d2;
            ack_d2 <= ack_d1;
        end
    end

    assign b_en = (~req_d2) && (req_d1);
    
    assign ack_pos = (~ack_d2) && ack_d1;

    assign ack_a = ack_d2;

    always@(posedge clkb or negedge rst_n)begin
        if(!rst_n)
            data_b_out <= 8'd0;
        else if(b_en)
            data_b_out <= data_a_in;
    end


endmodule

testbench如下:

`timescale 1ns/1ns
module toggle_tb();
    reg clka;
    reg clkb;
    reg rst_n;
    reg a_en;
    reg [7:0] data_a_in;

    wire [7:0] data_b_out;
    wire b_en;
    wire ack_a;

    always #5 clka = ~clka;
    always #10 clkb = ~clkb;

    initial begin
        rst_n = 1'b0;
        clka = 1'b0;
        clkb = 1'b0;
        #11;
        rst_n = 1'b1;
        #10000;
        $finish;
    end

    reg ack_a_d1;

    always@(posedge clka or negedge rst_n)begin
        if(!rst_n)begin
            a_en <= 1'b1;
            ack_a_d1 <= 1'b0;
        end
        else begin
            ack_a_d1 <= ack_a;
            a_en <= (~ack_a_d1) && ack_a;
        end
    end

    always@(posedge clka or negedge rst_n)begin
        if(!rst_n)
            data_a_in <= 8'd0;
        else if(a_en)
            data_a_in <= {$random}%256;
    end

    toggle toggle_inst(
        .clka       (clka),
        .clkb       (clkb),
        .rst_n      (rst_n),
        .a_en       (a_en),
        .data_a_in  (data_a_in),
        .data_b_out (data_b_out),
        .b_en       (b_en),
        .ack_a      (ack_a)
    );

    initial begin
        $fsdbDumpfile("tb.fsdb");
        $fsdbDumpvars;
    end


endmodule

仿真结果如下:

其中G1中为源时钟域信号,G2为目的时钟域信号

二,DMUX

 原理图如下:

DMUX适用于慢时钟域向快时钟域传递(因为两级同步器),且数据有效信号在数据信号的前一个周期或者数据有效信号在数据信号的第一个周期。数据信号要保证在有效信号同步期间保持不变。

源代码如下:

module dmux(
    input wire clka,
    input wire clkb,
    input wire a_en,
    input wire rst_n,
    input wire [7:0] data_in,

    output reg [7:0] data_out
);
    
    reg a_en_d1;
    reg a_en_d2;

    always@(posedge clkb or negedge rst_n)begin
        if(!rst_n)begin
            a_en_d1 <= 1'b0;
            a_en_d2 <= 1'b0;
        end
        else begin
            a_en_d1 <= a_en;
            a_en_d2 <= a_en_d1;
        end
    end

    always@(posedge clkb or negedge rst_n)begin
        if(!rst_n)
            data_out <= 8'd0;
        else if(a_en_d2)
            data_out <= data_in;
    end

endmodule

testbench如下:

`timescale 1ns/1ns;
module dmux_tb();
    reg clka;
    reg clkb;
    reg rst_n;
    reg a_en;
    reg [7:0] data_in;

    wire [7:0] data_out;

    always #10 clka = ~clka;
    always #5 clkb = ~clkb;

    initial begin
        clka = 1'b0;
        clkb = 1'b0;
        rst_n = 1'b0;
        a_en = 1'b0;
        data_in = 8'd0;
        #11;
        rst_n = 1'b1;
        @(posedge clka)
        a_en = 1'b1;
        data_in = {$random} %256;
        @(posedge clka)
        a_en = 1'b0;
        #33;
        @(posedge clka)
        a_en = 1'b1;
        @(posedge clka)
        a_en = 1'b0;
        data_in = ($random)%256;
        #100;
        $finish;
    end

    dmux dmux_inst(
    .clka       (clka),
    .clkb       (clkb),
    .rst_n      (rst_n),
    .a_en       (a_en),
    .data_in    (data_in),
    .data_out   (data_out)
    );

    initial begin
        $fsdbDumpfile("tb.fsdb");
        $fsdbDumpvars;
    end

endmodule

仿真结果如下:

可以清晰看到两种情况。

 

 

  • 5
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值