跨时钟域握手信号的实现(Verilog)

方法

使用握手信号是在两个不同域之间传输数据的有效方式,如下图所示:
在这里插入图片描述
使用握手信号xack和yreq,系统X发给系统Y,下面是使用握手信号传输数据的例子:
1)发送器系统X将数据放到数据总线上并发出xreq请求信号,表示有效数据已经发送到接收器系统Y的数据总线上
2)把xreq信号同步到接收器的时钟域yclk上。
3)接收器在识别xreq同步信号yreq2后,锁存数据总线上的信号
4)接收器发出确认信号yack,表示其已经接受了数据
5)接收器发出的yack信号同步到发送时钟xclk上
6)发送器在识别同步的ack信号后,将下一个数据放到数据总线上
握手信号的时序图如下所示:
在这里插入图片描述

握手信号的要求

数据应该在发送时钟域内稳定至少两个时钟上升沿,请求信号xreq的宽度应该超过两个上升沿时钟,否则从高速时钟的低速时钟域传递可能无法捕捉到该信号。缺点是是延迟太大(相比于FIFO)。

硬件实现

数据发送系统

模块框图如下
在这里插入图片描述

module tx_data(
    input   wire            tx_clk      ,
    input   wire            xack2       ,
    input   wire            rst_n       ,
    input   wire            en          ,

    output  reg             xreq        ,
    output  wire    [7:0]   t_data  
);

    reg     [3:0]       data1   ;
    reg     [3:0]       data2   ;

    //在yack2有效时data1和data2更新
    always @(posedge tx_clk or negedge rst_n) begin
        if(!rst_n) begin
            data1 <= 4'd1;
            data2 <= 4'd1;
        end
        else if(xack2) begin
            data1 <= data1 + 4'd1;
            data2 <= data2 + 4'd2;
        end
        else begin
            data1 <= data1;
            data2 <= data2;
        end
    end       

    //xreq信号
    always @(posedge tx_clk or negedge rst_n) begin
        if(!rst_n) begin
            xreq <= 1'b0;
        end
        else if(en) begin
            xreq <= 1'b1;
        end
        else if(xack2) begin
            xreq <= 1'b1;
        end
        else begin
            xreq <= 1'b0;
        end
    end

    assign t_data = {data1, data2};

endmodule

数据接收系统

模块框图如下:
在这里插入图片描述

module rv_data(
    input   wire        rv_clk      ,
    input   wire        rst_n       ,
    input   wire        yreq2       ,
    input   wire [7:0]  r_data      ,

    output  reg         yack        ,
    output  wire [5:0]  result           
);
    /*
        接收到数据的第一周期进行数据计算
        第二周期返回ack信号
    */
    reg             dly1        ;
    reg     [5:0]   result_reg  ;

    always @(posedge rv_clk or negedge rst_n) begin
        if(!rst_n) begin
            yack <= 1'b0;
        end
        else if(dly1) begin
            yack <= 1'b1;
        end
        else begin
            yack <= 1'b0;
        end
    end

    always @(posedge rv_clk or negedge rst_n) begin
        if(!rst_n) begin
            dly1 <= 1'b0;
        end
        else if(yreq2) begin
            dly1 <= 1'b1;
        end
        else begin
            dly1 <= 1'b0;
        end
    end

    always @(posedge rv_clk or negedge rst_n) begin
        if(!rst_n) begin
            result_reg <= 'd0;
        end
        else if(yreq2) begin
            result_reg <= r_data[3:0] + r_data[7:4];
        end
        else begin
            result_reg <= result_reg;
        end
    end

    assign result = dly1 ? result_reg : 6'd0;

endmodule

异步握手实现

模块框图如下:
在这里插入图片描述

module shake_hand_asy(
    input   wire            tx_clk      ,
    input   wire            rv_clk      ,
    input   wire            rst_n       ,
    input   wire            en          ,

    output  wire    [5:0]   result 
);

    wire                xreq    ;
    wire                yack    ;
    wire    [7:0]       data    ;

    reg                 yreq1   ;
    reg                 yreq2   ;
    reg                 xack1   ;
    reg                 xack2   ;

    //xreg的两级同步
    always @(posedge rv_clk or negedge rst_n) begin
        if(!rst_n) begin
            yreq1 <= 1'b0;
            yreq2 <= 1'b0;
        end
        else begin
            yreq1 <= xreq;
            yreq2 <= yreq1;
        end
    end

    //yack的两级同步
    always @(posedge tx_clk or rst_n) begin
        if(!rst_n) begin
            xack1 <= 1'b0;
            xack2 <= 1'b0;
        end
        else begin
            xack1 <= yack;
            xack2 <= xack1;
        end
    end

    tx_data u_tx_data(
    . tx_clk    (tx_clk)    ,
    . xack2     (xack2)     ,
    . rst_n     (rst_n)     ,
    . en        (en)        ,

    . xreq      (xreq)      ,
    . t_data    (data)
);

    rv_data u_rv_data(
     .rv_clk     (rv_clk)    ,
     .rst_n      (rst_n)     ,
     .yreq2      (yreq2)     ,
     .r_data     (data)      ,

     .yack       (yack)      ,
     .result     (result)      
);

endmodule

波形仿真

testbench代码如下:


`timescale  1ns/1ns

module tb_shake_hand_asy();

    reg         tx_clk      ;
    reg         rv_clk      ;
    reg         rst_n       ;
    reg         en          ;

    wire [5:0]  result      ;

    initial begin
        tx_clk = 1'b0;
        rv_clk = 1'b0;
        rst_n = 1'b0;
        en = 1'b0;
        #30
        rst_n = 1'b1;
        @(posedge tx_clk);
        en = 1'b1;          //启动
        @(posedge tx_clk);
        en = 1'b0;
    end

    always #15 tx_clk = ~tx_clk;
    always #10 rv_clk = ~rv_clk;

    shake_hand_asy u_shake_hand_asy(
    . tx_clk    (tx_clk)  ,
    . rv_clk    (rv_clk)  ,
    . rst_n     (rst_n)  ,
    . en        (en)  ,

    . result    (result)
);

endmodule

波形如下所示:
在这里插入图片描述
可知仿真正确。

总结

自己基础还很薄弱,继续加油!!!!

  • 5
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值