握手

该文描述了一种在FPGA设计中处理跨时钟域问题的方法,通过信号的两拍或三拍处理来避免亚稳态,并确保数据在接收端的正确同步。在慢时钟域,利用ack信号的上升沿处理count和data,而在快时钟域,使用data_req的后两拍信号来安全地采集data。测试bench验证了设计的正确性。
摘要由CSDN通过智能技术生成

对于接收端(慢时钟)

  1. 每个模块有一个请求req信号和一个应答ack信号。
  2. 对单bit的信号跨时钟域传输打两拍处理,
  3. 若要获得单bit信号的上升沿,打三拍处理,使用后两拍,可以避免亚稳态的产生。
  4. 对于count和data,在一次传输结束后只变化一次,要使用ack的上升沿信号,因为ack可能会持续多个周期。
  5. 对于req信号,当ack有效时,req为0,可以直接使用ack打两拍后的信号,也可以使用上升沿信号。

对于接收端(快时钟)

  1. 对于data_ack,使用打两拍后的data_req信号,在data_req_r[1]信号有效时,data_ack信号有效,
  2. 对于data_r数据存储信号,一次握手只采集一次data信号(安全合理),使用data_req打两拍之后的上升沿信号。
  3. data_r若使用打两拍后的data_req信号,会采集多次data,因为data_req信号会持续多个周期有效。
`timescale 1ns/1ns
module data_driver(
	input clk_a,
	input rst_n,
	input data_ack,
	output reg [3:0]data,
	output reg data_req
	);
	reg [2:0] count;
	reg [2:0] data_ack_r;

	//data_ack_r
	always@(posedge clk_a or negedge rst_n) begin
		if(!rst_n)
			data_ack_r <= 3'b00;
		else
			data_ack_r <= {data_ack_r[1:0], data_ack};
	end

	//count
	always@(posedge clk_a or negedge rst_n) begin
		if(!rst_n)
			count <= 3'd0;
		else if(data_ack_r[1]&(~data_ack_r[2]))				//使用三个寄存器的后两拍产生上升沿,防止亚稳态
			count <= 3'd0;
		else if(data_req)
			count <= count;
		else
			count <= count + 1'b1;
	end

	//data_req
	always@(posedge clk_a or negedge rst_n) begin
		if(!rst_n) 
			data_req <= 1'b0;
		else if(data_ack_r[1])
			data_req <= 1'b0;
		else if(count == 3'd4)
			data_req <= 1'b1;
	end

	//data
	always@(posedge clk_a or negedge rst_n) begin
		if(!rst_n) begin
			data <= 4'd0;
		end
		else if(data_ack_r[1]&(~data_ack_r[2])) begin
			data <= (data == 4'd7) ? 4'd0 : (data + 1'b1);
		end
	end

endmodule




module data_receiver(
	input 		clk_b,
	input 		rst_n,
	input [3:0] data,
	input		data_req,
	output reg	data_ack
);
	reg [3:0] data_r;
	reg [2:0] data_req_r;

	//data_req_r
	always@(posedge clk_b or negedge rst_n) begin
		if(!rst_n)
			data_req_r <= 3'b00;
		else
			data_req_r <= {data_req_r[1:0], data_req};
	end

	//data_ack
	always@(posedge clk_b or negedge rst_n) begin
		if(!rst_n) 
			data_ack <= 1'b0;
		else if(data_req_r[1])
			data_ack <= 1'b1;
		else
			data_ack <= 1'b0;
	end
	
	always@(posedge clk_b or negedge rst_n) begin
		if(!rst_n)
			data_r <= 4'b0;
		else if(data_req_r[1]&(~data_req_r[2])) 			//上升沿 只采入一次数据
			data_r <= data;
	end

endmodule
`timescale 1ns/1ns

module testbench();
	reg 	clk_a,clk_b,rst_n;
	wire 	data_req,data_ack;
  wire [3:0]data;
	
initial begin
	clk_a = 1;
	clk_b = 1;
	rst_n = 0;
#30	
	rst_n = 1;	
 #500 $finish();
end

always #15 clk_a = ~clk_a;
always #10 clk_b = ~clk_b;

data_driver dut_1
( 	.clk_a(clk_a),
	.rst_n(rst_n),
	.data(data),
	.data_ack(data_ack),
	.data_req(data_req)
);
data_receiver dut_2
( 	.clk_b(clk_b),
	.rst_n(rst_n),
	.data(data),
	.data_ack(data_ack),
	.data_req(data_req)
);
endmodule

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值