当前位置:   article > 正文

跨时钟域信号处理方法&异步FIFO_异步fifo跨时钟域处理

异步fifo跨时钟域处理

跨时钟域

全同步设计:1个时钟
全异步设计:没有时钟(存在少)
全局异步,局部同步设计:不可避免,单一时钟不能满足设计需求

多时钟域设计不可避免问题:亚稳态,同步失败
同步化:同步器;保持寄存器和握手(效率不高);异步FIFO设计

两级寄存器
一级寄存概率的平方,虽然两级并不能完全消除亚稳态危害,但是提高了可靠性,减少其发生概率
分类:电平同步器,边沿检测同步器,脉冲同步器
电平同步器(打两拍)
在这里插入图片描述
从Clock1到Clock2的跨时钟,触发器之间无组合逻辑,电平同步一般只适用于频率一样,相位上没有同步,但是两者频率不一样,就不能使用。如果是慢时钟到快时钟域,会出现数据重复采样。

边沿检测同步器(慢到快)
在这里插入图片描述
将慢时钟域的脉冲同步到快时钟域,快时钟采集慢数据,会出现数据重复,将数据变化转为一个脉冲,并进行门运算,去除重复数据

脉冲同步器(快到慢)
在这里插入图片描述
慢到快只需要考虑亚稳态问题,快到慢要考虑采样速率,保证数据不丢失,这个问题称为信号宽度问题。一般安全的宽度是快时钟域的信号宽度必须是慢时钟域周期的1.5倍以上,也就是持续三个时钟沿以上。整个设计包括脉冲电平检测、双触发器同步、边沿检测三部分。

多bit信号跨时钟域传输
在这里插入图片描述
b_load和b_en各自经过同步器延时之后,产生不同步的问题,解决方案将两路合成一路,再经过同步器,分成两路信号控制置位和使能端

总线信号的跨时钟域
正确方法:保持寄存器加握手信号;异步FIFO设计在这里插入图片描述
异步FIFO:读时钟和写时钟为独立时钟,思想:隔离时钟域,匹配读写速度

异步FIFO介绍
FIFO(First In First out)先进先出,它是一种存储器结构,能读写数据,所以有双口RAM作为存储数据的单元,在不同时钟域传输数据,使用异步FIFO来作为传输的缓冲区,既可以保证异步时钟数据传输的时序要求变得宽松,也提高传输效率。

FIFO写满和读空标志的产生
读写指针比较产生,同步FIFO直接把读写指针比较或者运算产生,而异步FIFO由于读写指针不同时钟域,比较前指针必须同步化,由于二进制的指针会出现多位同时跳变,直接由同步器进行同步化会有问题
在这里插入图片描述
判断存储器(RAM)写入写出的状态,需要有写满判断(wfull信号),和读空判断(empty信号),如何得到写满和读空信号?通过比较读写地址(告诉我们数据数据位置)、指针(四个信号 waddr,wptr,raddr,rptr)来判断此刻FIFO的写满和读空。
判断中涉及到w2r和r2w时钟域问题(2级寄存器同步)

对于异步FIFO,读写为不同时钟,如果直接采样,就会有亚稳态问题,比如写地址从00111改变01000的时候,读时钟恰好采样,除了最高位,其他4为有可能出现亚稳态,也有可能同步到错误的地址,这就是需要引入格雷码的原因。

设定地址指针位数时需要+1位,如16个数组需要4位,地址指针位数为5,
当最高位和次高位相同,其余位相同则认为是读空;
当最高位和次高位不同,其余位相同则认为是写满;

在这里插入图片描述
下面是用Verilog HDL设计深度为256(存储器可以写入256个数据),位宽为16(每个数据的宽度为16)的FIFO

module asyn_fifo
	#(
		parameter data_width = 16,
		parameter data_depth = 8,
		parameter ram_depth  = 256
	)
	(
	input							rst_n,
	
	input               			wr_clk,
	input               			wr_en,
	input      [data_width-1:0]     data_in,
	output              			full,
	
	input               			rd_clk,
	input               			rd_en,
	input  reg [data_width-1:0]     data_out,
	output              			empty
	);
	
	reg  [data_depth-1:0] wr_adr;
	reg  [data_depth-1:0] rd_adr;
	
	reg  [data_depth:0] wr_adr_ptr;
	reg  [data_depth:0] rd_adr_ptr;
	
	wire  [data_depth:0] wr_adr_gray;
	reg  [data_depth:0] wr_adr_gray1;
	reg  [data_depth:0] wr_adr_gray2;
	wire  [data_depth:0] rd_adr_gray;
	reg  [data_depth:0] rd_adr_gray1;
	reg  [data_depth:0] rd_adr_gray2;
	
	//dual port ram -write and read
	assign wr_adr = wr_adr_ptr[data_depth-1:0];
	assign rd_adr = rd_adr_ptr[data_depth-1:0];
	
	integer i;
	reg [data_width-1:0] ram_fifo [ram_depth-1:0];
	
	always@(posedge wr_clk or negedge rst_n)begin
		if(!rst_n)begin
			for(i=0;i<ram_depth;i++)
				ram_fifo[i] <= 'd0;//全部清零
		end
		else if(wr_en && (~full))
			ram_fifo[wr_adr] <= data_in;
		else
			ram_fifo[wr_adr] <= ram_fifo[wr_adr];
	end
	
	always@(posedge rd_clk or negedge rst_n)begin
		if(!rst_n)
			data_out <= 'd0;
		end
		else if(rd_en && (~empty))
			data_out <= ram_fifo[rd_adr];
		else
			data_out <= 'd0;
	end
	
	//wr_adr_ptr ++ and rd_adr_ptr ++
	always@(posedge wr_clk or negedge rst_n)begin
		if(!rst_n)
			wr_adr_ptr <= 'd0;
		else if(wr_en && (~full))
			wr_adr_ptr <= wr_adr_ptr + 1'b1;
		else
			wr_adr_ptr <= wr_adr_ptr;
	end
	
	always@(posedge rd_clk or negedge rst_n)begin
		if(!rst_n)
			rd_adr_ptr <= 'd0;
		end
		else if(rd_en && (~empty))
			rd_adr_ptr <= rd_adr_ptr + 1'b1 ;
		else
			rd_adr_ptr <= rd_adr_ptr;
	end
	
	//binary to gray
	assign wr_adr_gray = (wr_adr_ptr >> 1) ^ wr_adr_ptr;
	assign rd_adr_gray = (rd_adr_ptr >> 1) ^ rd_adr_ptr;
	
	//gray cdc compare
	always@(posedge wr_clk or negedge rst_n)begin
		if(!rst_n)begin
			wr_adr_gray1 <= 'd0;
			wr_adr_gray2 <= 'd0;
		end
		else begin 
			wr_adr_gray1 <= wr_adr_gray;
			wr_adr_gray2 <= wr_adr_gray1;
		end
	end
	
	always@(posedge rd_clk or negedge rst_n)begin
		if(!rst_n)begin
			rd_adr_gray1 <= 'd0;
			rd_adr_gray2 <= 'd0;
		end
		else begin 
			rd_adr_gray1 <= rd_adr_gray;
			rd_adr_gray2 <= rd_adr_gray1;
		end
	end
	
	assign empty = (rd_adr_gray == wr_adr_gray2)?1'b1:1'b0;
	assign full=(wr_adr_gray[data_depth:data_depth-1] !=rd_adr_gray2[data_depth:data_depth-1])&&(wr_adr_gray[data_depth:data_depth-2:0] ==rd_adr_gray2[data_depth-2:0]);

endmodule	
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112

测试代码如下

'timescale 1us/1us

module asyn_fifo_tb;
	reg						rst_n;
	
	reg                     wr_clk;
	reg						wr_en;
	reg        [15:0]       data_in;
	wire					full;
	
	reg						rd_clk;
	reg						rd_en;
	wire       [15:0]       data_out;
	wire					empty;
	
	asyn_fifo asyn_fifo_inst
	(
		.rst_n    (rst_n),
		
		.wr_clk   (wr_clk),
		.wr_en    (wr_en),
		.data_in  (data_in),
		.full     (full),
		
		.rd_clk   (rd_clk),
		.rd_en    (rd_en),
		data_out  (data_out),
		.empty    (empty)
	);

	initial wr_clk = 0;
	always#10 wr_clk=~wr_clk;
	
	initial rd_clk = 0;
	always#30 rd_clk=~rd_clk;
	
	always@(posedge wr_clk or negedge rst_n)begin
		if(!rst_n)
			data_in <= '0d0;
		else if(wr_en)
			data_in <=data_in + 1'b1;
		else 
			data_in <= data_in;
	end
	
	initial begin
		rst_n = 0;
		wr_en = 0;
		rd_en = 0;
		#200;
		rst_n = 1;
		wr_en = 1;
		#20000;
		wr_en = 0;
		rd_en = 1;
		#20000;
		rd_en = 0;
		$stop;
	end
	
endmodule
		
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62

仿真测试结果如下图所示
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/206641
推荐阅读
相关标签
  

闽ICP备14008679号