赞
踩
常用的多bit信号的跨时钟域处理方法有两种:
①使用异步FIFO进行数据同步。
②采用握手方式进行数据同步。
当存在两个异步时钟域并且二者之间需要进行数据包传输时,双端口异步FIFO最为合适。
FIFO有两个端口,一个端口写入输入数据,另一个端口读出数据。两个端口工作在相互独立的时钟域内,通过各自的指针(地址)来读写数据。由于每个端口工作在相互独立的时钟域内,因此读写操作可以独立实现并且不会出现任何差错。当FIFO变满时,应停止写操作,直到FIFO中出现空闲空间。同样,当FIFO为空时,应停止读操作,直到有新的数据被写入FIFO中。
异步FIFO的具体代码可以参见我的另一篇文章:
异步FIFO代码
FIFO可用于在不同的时钟域之间进行数据包的传输,但是在一些应用中,需要在不同时钟域之间进行少量数据的传输。FIFO占用的硬件资源较大,此时可以考虑使用握手同步机制。
以下是握手同步机制的工作步骤:
●用后缀_t表示数据发送端,用后缀_r表示数据接收端。发送端时钟用tclk表示,接收端时钟用rclk表示;
●当需要发送的数据准备好后,发送端将t_rdy信号置为有效;
●在t_rdy有效期间,t_data必须保持稳定;
●接收端在rclk时钟域内采用双同步器同步t_rdy控制信号,并把同步后的信号命名为t_rdy_rclk;
●接收端在发现t_rdy_rclk信号有效时,t_data已经安全地进入了rclk时钟域内,使用rclk对其进行采样,可以得到t_data_rclk。由于数据已经在rclk域进行了正确采样,所以此后在rclk域使用该数据是安全的;
●接收端将r_ack信号置为1;
●发送端通过双同步器在tclk时钟域内同步r_ack信号,同步后的信号命名为r_ack_tclk;
●以上所有步骤被称为“半握手”。这是因为发送端在输出下一个数据之前,不会等到r_ack_tclk被置为0;
●半握手机制工作速度快,但是使用半握手机制时需要谨慎,一旦使用不当,会导致操作错误;
●从低频时钟域向高频时钟域传输数据时,半握手机制较为适用,这是由于接收端可以更快地完成操作。然而,如果从高频时钟域向低频时钟域传输数据,则需要采用全握手机制;
●当r_ack_tclk为高电平时,发送端将t_rdy置为0;
●当t_rdy_rclk为低电平时,接收端将r_ack置为0;
●当发送端发现r_ack_tclk为低电平后,全握手过程结束,发送端可以发送新的数据;
●显然,全握手过程耗时较长,数据传输速率较慢。然而,全握手机制稳定可靠,可以在两个任意频率的时钟域内安全地进行数据传输。
下图所示为全握手机制工作波形图:
下面是一段采用全握手机制的同步桥代码,代码中采用的信号命名方式与以上讲述中略有不同,但整体思路与以上讲述的一致,可以直接例化此同步桥进行跨时钟域的数据同步:
module sync_bridge( input clk_t , input clk_r , input rst_n , input data_vld, //表示发送端数据有效(已经准备好) input [31:0] data_t , output reg [31:0] data_r ); reg req, req_syn1, req_syn2; reg ack, ack_syn1, ack_syn2; always @(posedge clk_t, negedge rst_n) begin if(rst_n == 1'b0) begin req <= #1 1'b0; end else if(ack_syn2 == 1'b1) begin req <= #1 1'b0; end else if(ack_syn2 == 1'b0 && data_vld == 1'b1) begin req <= #1 1'b1; end end always @(posedge clk_t, negedge rst_n) begin if(rst_n == 1'b0) begin ack_syn1 <= #1 1'b0; ack_syn2 <= #1 1'b0; end else begin ack_syn1 <= #1 ack; ack_syn2 <= #1 ack_syn1; end end always @(posedge clk_r, negedge rst_n) begin if(rst_n == 1'b0) begin req_syn1 <= #1 1'b0; req_syn2 <= #1 1'b0; end else begin req_syn1 <= #1 req; req_syn2 <= #1 req_syn1; end end always @(posedge clk_r, negedge rst_n) begin if(rst_n == 1'b0) begin ack <= #1 1'b0; end else if(req_syn2 == 1'b1) begin ack <= #1 1'b1; end else if(req_syn2 == 1'b0) begin ack <= #1 1'b0; end end always @(posedge clk_r, negedge rst_n) begin if(rst_n == 1'b0) begin data_r <= #1 32'h0; end else if(req_syn2 == 1'b1) begin data_r <= #1 data_t; end end endmodule
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。