跨时钟域之握手机制

  • 全握手机制概述

    在不同的时钟域之间进行数据传输时,可以考虑使用握手同步机制。握手同步机制分为半握手和全握手。当从低频时钟域向高频时钟域传输数据时,半握手机制比较适用,这是由于接收端可以更快的完成操作。但是从高频时钟向低频时钟传输数据时,则需要全握手机制。

  • 握手同步机制的步骤如下

    (1)在高频时钟域下,将一个需要发送的数据准备好,将req信号设置为有效。在低频时钟域下,接收端同步该req信号,同步后的信号命名为req_r0、req_r1;

   (2)在低速时钟域下,通过边沿检测的方式来检测信号req_r0、req_r1的上升沿pos_req_r0、pos_req_r1,在信号pos_req_r0的上升沿有效时对数据进行采样,并在信号pos_req_r1有效时生成响应信号ack;

   (3)在高速时钟域下,同步该响应信号ack,同步后的信号为 ack_r0、ack_r1,通过边沿检测的方式得到ack信号的上升沿pos_ack_r0,在信号pos_ack_r0为高电平的时候将req信号拉低。

   (4)在低速时钟域下,检测到req同步后的信号req_r0为低电平时,拉低响应信号ack。

  • 个人理解

  1、发送方准备好数据之后,通过req信号通知下接收方;
  2、接收方在req信号有效时,接收数据;
  3、接收方在接收到数据之后,返还一个ack信号给发送方,告诉它接收方已经接收到数据了;
  4、发送方收到响应信号ack有效之后,将req信号拉低,说明数据已经传输结束了;
  5、接收方在收到req信号拉低之后,也将ack信号给拉低;

  • 程序编写
  1 module hand_shake(
  2     input                                clka                ,    //    fast clock
  3     input                                clkb                ,    //    slow clock
  4     
  5     input                                rst_n                ,
  6     
  7     input                                data_vld            ,    //    持续一个时钟周期
  8     input            [7:0]                data_in                ,
  9     
 10     output reg        [7:0]                data_out
 11 );
 12 
 13 //========================================================================\
 14 // =========== Define Parameter and Internal signals =========== 
 15 //========================================================================/
 16 
 17 reg                                        data_vld_r0            ;
 18 reg                                        data_vld_r1            ;
 19 
 20 wire                                    neg_data_vld        ;
 21 
 22 reg                                        req                    ;
 23 reg                                        ack                    ;
 24 
 25 reg                                        ack_rx_r0            ;
 26 reg                                        ack_rx_r1            ;
 27 
 28 wire                                    pos_ack_rx            ;
 29 
 30 reg                                        req_r0                ;
 31 reg                                        req_r1                ;
 32 reg                                        req_r2                ;
 33 
 34 wire                                    pos_req_r0            ;
 35 wire                                    pos_req_r1            ;
 36 
 37 //=============================================================================
 38 //****************************     Main Code    *******************************
 39 //=============================================================================
 40 
 41 always @(posedge clka or negedge rst_n) begin
 42     if(!rst_n) begin
 43         data_vld_r0 <= 1'b0;
 44         data_vld_r1 <= 1'b0;
 45     end
 46     else begin
 47         data_vld_r0 <= data_vld;
 48         data_vld_r1 <= data_vld_r0;
 49     end
 50 end
 51 
 52 assign    neg_data_vld    =    (data_vld_r1 == 1'b1) && (data_vld_r0 == 1'b0);
 53 
 54 always @(posedge clka or negedge rst_n) begin    //    将ack信号同步到clka时钟下
 55     if(!rst_n) begin
 56         ack_rx_r0 <= 1'b0;
 57         ack_rx_r1 <= 1'b0;
 58     end
 59     else begin
 60         ack_rx_r0 <= ack;
 61         ack_rx_r1 <= ack_rx_r0;
 62     end
 63 end
 64 
 65 assign pos_ack_rx = (ack_rx_r1 == 1'b0) && (ack_rx_r0 == 1'b1);
 66 
 67 always @(posedge clka or negedge rst_n) begin    //    请求信号设计
 68     if(!rst_n)
 69         req <= 1'b0;
 70     else if(neg_data_vld == 1'b1)
 71         req <= 1'b1;
 72     else if(pos_ack_rx == 1'b1)
 73         req <= 1'b0;
 74     else
 75         req <= req;
 76 end
 77 
 78 // ================ 接收数据部分设计 ==============================
 79 
 80 always @(posedge clkb or negedge rst_n) begin    //    在时钟域clkb下同步req信号
 81     if(!rst_n) begin
 82         req_r0 <= 1'b0;
 83         req_r1 <= 1'b0;
 84         req_r2 <= 1'b0;
 85     end
 86     else begin
 87         req_r0 <= req;
 88         req_r1 <= req_r0;
 89         req_r2 <= req_r1;
 90     end
 91 end
 92 
 93 assign    pos_req_r0    =    (req_r1 == 1'b0) && (req_r0 == 1'b1);
 94 assign    pos_req_r1  =    (req_r2 == 1'b0) && (req_r1 == 1'b1);
 95 
 96 always @(posedge clkb or negedge rst_n) begin    //    在同步过来的req信号为高电平时对数据进行采样
 97     if(!rst_n)
 98         data_out <= 8'd0;
 99     else if(pos_req_r0 == 1'b1)
100         data_out <= data_in;
101     else
102         data_out <= data_out;
103 end
104 
105 always @(posedge clkb or negedge rst_n) begin    //    响应信号ack的设计
106     if(!rst_n)
107         ack <= 1'b0;
108     else if(pos_req_r1 == 1'b1)
109         ack <= 1'b1;
110     else if(req_r0 == 1'b0)
111         ack <= 1'b0;
112     else
113         ack <= ack;
114 end
115 
116 endmodule
View Code
  • 仿真验证
 1 `timescale 1ns/1ps
 2 
 3 module handshake_tb;
 4     reg                                clka                ;    //    fast clock
 5     reg                                clkb                ;    //    slow clock
 6     
 7     reg                                rst_n                ;
 8     
 9     reg                                data_vld            ;    //    持续一个时钟周期
10     reg            [7:0]                data_in                ;
11     
12     wire        [7:0]                data_out            ;
13     
14     reg            [3:0]                cnt                    ;
15 
16 hand_shake hand_shake_inst(
17     .clka        ( clka                 ),
18     .clkb        ( clkb                ),
19     .rst_n        ( rst_n                ),
20     .data_vld    ( data_vld            ),
21     .data_in    ( data_in            ),
22     .data_out    ( data_out            )
23 );
24 
25 initial
26     begin
27         $dumpfile("wave.vcd");
28         $dumpvars(0,handshake_tb);
29     end
30     
31 initial
32     clka = 1'b0;
33     always #4 clka = ~clka;
34     
35 initial
36     clkb = 1'b0;
37     always #10 clkb = ~clkb;
38     
39 initial
40     begin
41         #1;
42         rst_n = 1'b0;
43         #51;
44         rst_n = 1'b1;
45     end
46     
47 always @(posedge clka or negedge rst_n) begin
48     if(!rst_n)
49         cnt <= 4'd0;
50     else
51         cnt <= cnt + 1'b1;
52 end
53 
54 always @(posedge clka or negedge rst_n) begin
55     if(!rst_n)
56         data_vld <= 1'b0;
57     else if(&cnt == 1'b1)
58         data_vld <= 1'b1;
59     else
60         data_vld <= 1'b0;
61 end
62 
63 always @(posedge clka or negedge rst_n) begin
64     if(!rst_n)
65         data_in <= 8'd0;
66     else if(&cnt == 1'b1)
67         data_in <= data_in + 1'b1;
68     else
69         data_in <= data_in;
70 end
71 
72 endmodule
View Code

 

 

 

  •  参考

   [1] https://blog.csdn.net/qq_39814612/article/details/105795252

   [2] https://reborn.blog.csdn.net/article/details/112726447?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-14.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-14.control

  [3] https://blog.csdn.net/weixin_37603007/article/details/82805966?utm_term=%E6%8F%A1%E6%89%8B%E6%9C%BA%E5%88%B6%E7%9A%84%E6%95%B0%E6%8D%AE%E5%90%8C%E6%AD%A5&utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~all~sobaiduweb~default-4-82805966&spm=3001.4430

 

 

 

 

      

 

posted @ 2021-09-02 10:10  青河  阅读(568)  评论(0)    收藏  举报