异步FIFO

关于异步FIFO的关键技术,有两个,一个是格雷码减小亚稳态,另一个是指针信号跨异步时钟域的传递。我在自己写异步FIFO的时候也很疑惑,地址指针在同步化的时候,肯定会产生至少两个周期的延迟,如果是从快时钟域到慢时钟域,快时域的地址指针并不能都被慢时域的时钟捕获,同步后的指针比起实际的指针延迟会更大。如果以此来产生fifo_empty和fifo_full 信号会非常不准器。
查找资料和仿真后发现,数字电路的世界真的很神奇,还有很多的东西需要去学习。非常巧妙,FIFO中的一个潜在的条件是write_ptr总是大于或者等于read_ptr;分为两种情况,写快读慢和写慢读快。
1.在写时钟大于读时钟时,产生fifo_empty信号,需要将write_ptr同步到读时钟域,写指针会有延时,可能比实际的写地址要小,如果不满足fifo_empty的产生条件,没问题。如果满足fifo_empty的触发条件,说明此时同步后的write_ptr == read_ptr,即实际的write_ptr >= read_ptr,最坏的情况就是write_ptr > read_ptr,像这种FIFO非空而产生空标志信号的情况称为“虚空”,但是也并不影响FIFO的功能。
2.在写时钟大于读时钟时,产生fifo_full信号,需要将read_ptr同步到写时钟域,读指针会有延时,可能比实际的读地址要小,如果不满足fifo_full的产生条件,没问题。如果满足fifo_full的触发条件,说明此时同步后的read_ptr == write_ptr - fifo_depth,即实际的read_ptr >= read_ptr - fifo_depth,最坏的情况就是read_ptr > read_ptr - fifo_depth,像这种FIFO非满而产生满标志信号的情况称为“虚满”,但是也并不影响FIFO的功能。
写慢读快的情况也同上,并没有大的差异,不再分析。

关于格雷码减小亚稳态,如果读写时钟差距过大,从快时钟域同步到慢时钟域的信号,时钟捕获的相邻两个数据变化并不是只有一个bit位的改变,可能导致格雷码失去原来的意义,嗯,目前的理解是这样。
————————————————
版权声明:本文为优快云博主「alangaixiaoxiao」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/alangaixiaoxiao/article/details/81432144

module fifo
	( 	input				wclk , 
							rclk , 
							w_en ,
							r_en ,
							rst_n,		
		input		[Wsize-1:0]	wdata,
		output				fifo_full ,
							fifo_empty,
		output		[Wsize-1:0]	rdata
	);
parameter Wsize=8,Dsize=32;

wire fifo_empty_vail,fifo_full_vail;
//定义变量
reg  fifo_empty,fifo_full;
 reg [Wsize-1:0] mem [Dsize-1:0];
wire [Dsize-1:0] w_addr,r_addr;
 reg [Dsize:0] w_bin,r_bin;
wire [Dsize:0] r_bin_next,w_bin_next;
 reg [Dsize:0] r_gray,w_gray;
 wire [Dsize:0] r_gray_next,w_gray_next;
 reg [Dsize:0] w_2_r_gray1,w_2_r_gray2,r_2_w_gray1,r_2_w_gray2;

 //定义双端口RAM
 assign rdata = mem[r_addr];
 always@(posedge wclk)
   if (w_en && !fifo_full) mem[w_addr] <= wdata;
	
 
//产生读地址r_addr,同时把二进制转化为格雷码
always@(posedge rclk or negedge rst_n)
 if (!rst_n) {r_bin,r_gray} <= 0;
 else
   {r_bin,r_gray} <= {r_bin_next,r_gray_next};
	
	
assign r_addr = r_bin[Dsize-1:0];
assign r_bin_next = r_bin + (r_en && !fifo_empty);
assign r_gray_next = r_bin ^ (r_bin >> 1);
 
//产生写地址
always@(posedge wclk or negedge rst_n)
 if (!rst_n) {w_bin,w_gray} <= 0;
 else
   {w_bin,w_gray} <= {w_bin_next,w_gray_next};

assign w_addr = w_bin[Dsize-1:0];
assign w_bin_next = w_bin + (w_en && !fifo_empty);
assign w_gray_next = w_bin ^ (w_bin >> 1);

//同步写地址到读时钟域,两个触发器同步
always@(posedge rclk or negedge rst_n)
begin
  if(!rst_n)
    {w_2_r_gray2,w_2_r_gray1} <= 0;
	 else
	 {w_2_r_gray2,w_2_r_gray1} <= {w_2_r_gray1,w_gray};

end

//同步读地址到写时钟域,两个触发器同步
always@(posedge rclk or negedge rst_n)
begin
  if(!rst_n)
    {r_2_w_gray2,r_2_w_gray1} <= 0;
	 else·
	 {r_2_w_gray2,r_2_w_gray1} <= {r_2_w_gray1,r_gray};

end

//产生读空信号
assign fifo_empty_vail = (w_2_r_gray2 == r_gray_next);
always@(posedge rclk or negedge rst_n)
begin
 if(!rst_n) 
   fifo_empty <= 1'b0;
	else
	fifo_empty <= fifo_empty_vail;
	
end
//产生写满信号
//assign r_2_w_gray2_reg = { ~ r_2_w_gray2 [Dsize:Dsize-1] , r_2_w_gray2 [Dsize-2:0]};

assign fifo_full_vail = (({ ~  r_2_w_gray2 [Dsize:Dsize-1] , r_2_w_gray2 [Dsize-2:0]}) == w_gray_next)?1:0;

always@(posedge wclk or negedge rst_n)
begin
 if(!rst_n) 
   fifo_full <= 1'b0;
	else
	fifo_full <= fifo_full_vail;
	
end


endmodule
### 异步FIFO的工作原理 异步FIFO(First In First Out)是一种用于在不同时钟域之间传输数据的缓冲结构。其核心原理是通过两个独立的时钟域分别控制数据的写入和读取操作,从而实现数据的异步传输。在异步FIFO中,写入操作由写时钟控制,而读取操作由读时钟控制。这种设计允许数据在不同时钟频率和相位的情况下进行传输,适用于多时钟域系统中的数据同步问题[^3]。 #### 1. **空满标志的判断** 由于异步FIFO的读指针和写指针处于不同的时钟域,直接进行比较会导致跨时钟域的问题。因此,需要对读指针和写指针进行同步处理后再进行比较,以消除亚稳态的影响。通常采用多级寄存器(如两级D触发器)对指针进行同步处理,同时将指针转换为格雷码(Gray Code)以减少同步过程中可能出现的错误[^5]。 #### 2. **指针的表示** 在同步FIFO中,FIFO的空满状态通常通过写地址减去读地址来判断。然而,在异步FIFO中,由于读写指针处于不同的时钟域,这种直接相减的方式不再适用。因此,需要采用额外的同步机制来确保读写指针的比较是可靠的[^2]。 #### 3. **复位机制** 异步FIFO支持在读写过程中发生复位操作。例如,在写过程中发生写复位时,写数据和FIFO满标志位会被清空;在读过程中发生读复位时,读数据和FIFO空标志位会被清空。这种机制确保了FIFO在复位后仍能继续正常工作[^1]。 --- ### 异步FIFO的实现方法 #### 1. **Verilog实现** 异步FIFO的实现通常包括以下几个关键模块: - **写控制模块**:负责将数据写入FIFO,并更新写指针。 - **读控制模块**:负责从FIFO中读取数据,并更新读指针。 - **空满标志生成模块**:通过比较同步后的读写指针,生成FIFO的空满标志。 - **同步模块**:对读写指针进行同步处理,以消除跨时钟域的亚稳态问题。 以下是一个简单的异步FIFO的Verilog代码框架: ```verilog module async_fifo #( parameter DATA_WIDTH = 8, parameter ADDR_WIDTH = 4 ) ( input wr_clk, input wr_rst_n, input rd_clk, input rd_rst_n, input wr_en, input [DATA_WIDTH-1:0] din, output reg [DATA_WIDTH-1:0] dout, output full, output empty ); // FIFO存储器 reg [DATA_WIDTH-1:0] fifo_mem [0:(1<<ADDR_WIDTH)-1]; // 写指针和读指针 reg [ADDR_WIDTH:0] wr_ptr; reg [ADDR_WIDTH:0] rd_ptr; // 同步后的指针 wire [ADDR_WIDTH:0] sync_wr_ptr; wire [ADDR_WIDTH:0] sync_rd_ptr; // 同步逻辑 sync_block_wr sync_wr ( .clk(wr_clk), .rst_n(wr_rst_n), .data_in(rd_ptr), .data_out(sync_rd_ptr) ); sync_block_rd sync_rd ( .clk(rd_clk), .rst_n(rd_rst_n), .data_in(wr_ptr), .data_out(sync_wr_ptr) ); // 空满标志生成逻辑 assign full = (wr_ptr == {~sync_rd_ptr[ADDR_WIDTH:ADDR_WIDTH-1], sync_rd_ptr[ADDR_WIDTH-2:0]} && wr_ptr[ADDR_WIDTH] != sync_rd_ptr[ADDR_WIDTH]); assign empty = (wr_ptr == sync_rd_ptr); // 写操作 always @(posedge wr_clk or negedge wr_rst_n) begin if (!wr_rst_n) begin wr_ptr <= 0; end else if (wr_en && !full) begin fifo_mem[wr_ptr[ADDR_WIDTH-1:0]] <= din; wr_ptr <= wr_ptr + 1; end end // 读操作 always @(posedge rd_clk or negedge rd_rst_n) begin if (!rd_rst_n) begin rd_ptr <= 0; dout <= 0; end else begin if (!empty) begin dout <= fifo_mem[rd_ptr[ADDR_WIDTH-1:0]]; rd_ptr <= rd_ptr + 1; end end end endmodule // 同步模块 module sync_block_wr ( input clk, input rst_n, input [ADDR_WIDTH:0] data_in, output reg [ADDR_WIDTH:0] data_out ); always @(posedge clk or negedge rst_n) begin if (!rst_n) begin data_out <= 0; end else begin data_out <= data_in; end end endmodule ``` #### 2. **同步处理** 为了消除亚稳态,异步FIFO通常采用多级寄存器对跨时钟域信号进行同步处理。例如,在读时钟域中对写指针进行同步,或在写时钟域中对读指针进行同步。这种同步机制可以有效减少由于时钟异步导致的不稳定状态。 --- ### 异步FIFO的应用场景 异步FIFO广泛应用于需要在不同时钟域之间传输数据的场景,主要包括以下几个方面: 1. **多时钟域系统**:在现代集成电路设计中,系统通常包含多个时钟域。异步FIFO可以作为不同时钟域之间的数据缓冲,确保数据的可靠传输[^3]。 2. **数据流处理**:在数据流处理系统中,异步FIFO可以用于缓存数据,以应对数据速率不匹配的问题。例如,在高速ADC(模数转换器)和低速处理器之间的数据传输中,异步FIFO可以有效缓解数据速率差异[^1]。 3. **通信接口**:在通信系统中,异步FIFO常用于串行通信接口(如UART、SPI等)中,用于缓冲发送和接收的数据,避免数据丢失或溢出。 4. **图像处理**:在图像处理系统中,异步FIFO可以用于缓冲图像数据,以应对不同模块之间的处理速度差异。例如,在图像采集和图像处理模块之间,异步FIFO可以确保数据的连续传输[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值