FIFO的工作原理及其设计

这篇具有很好参考价值的文章主要介绍了FIFO的工作原理及其设计。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.简介

        FIFO( First Input First Output)简单说就是指先进先出。FIFO存储器是一个先入先出的双口缓冲器,即第一个进入其内的数据第一个被移出,其中一个口是存储器的输入口,另一个口是存储器的输出口。

        对于单片FIFO来说,主要有两种结构:触发导向结构和零导向传输结构。触发导向传输结构的FIFO是由寄存器阵列构成的,零导向传输结构的FIFO是由具有读和写地址指针的双口RAM构成。

        FIFO与普通RAM存储器的区别是没有外部读写地址线(指针),使用方便,但缺点是只能顺序写入数据和读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。

1.1.功能

        FIFO存储器是系统的缓冲环节,主要有几方面的功能:

                1)对连续的数据流进行缓存,防止在进机和存储操作时丢失数据;

                2)数据集中起来进行进栈和存储,可避免频繁的总线操作,减轻CPU的负担;

                3)允许系统进行DMA操作,提高数据的传输速度。这是至关重要的一点,如果不采用DMA操作,数据传输将达不到传输要求,而且大大增加CPU的负担,无法同时完成数据的存储工作。

1.2.用途

1.2.1.跨时钟域多bit数据传输

        解决一个系统多个时钟所带来的问题:异步时钟之间的接口电路。异步FIFO是解决这个问题的一种便捷简单的方案,使用异步FIFO可以在两个不同时钟系统之间快速方便地传输实时数据。

1.2.2.达到数据匹配问题(读写位宽不一致)

        对于不同宽度的数据接口也可以使用FIFO,例如单片机的8位输出而DSP可能是16位输入,在单片机与DSP连接时就可以使用FIFO来达到数据匹配的目的。

1.3.主要参数

  • 宽度(WIDTH):FIFO每个地址的数据位宽(W);
  • 深度(DEEPTH):FIFO可以存储多少个W位的数据;
  • 满(full)标志:FIFO已满或将满时,会输出一个对写操作的反压信号,以阻止被继续写入数据而溢出;
  • 空(empty)标志:FIFO已空或将空时,会输出一个对读操作的反压信号,以避免被继续读出无效数据;
  • 读/写时钟:读/写操作所遵循的时钟,每个时钟沿触发。

        根据FIFO工作的时钟域分为同步/异步FIFO。同步FIFO是指读时钟和写时钟为同一个时钟在时钟沿来临时同时发生读写。异步FIFO读写时钟不一致,读写相互独立。

        读写指针即读写地址,当前读/写操作完成后,指针自动加一指向下一个地址(连续递增)。

  • 写指针:总是指向下一个将要被写入的地址,复位时指向编号0的地址;
  • 读指针:总是指向下一个将要被读出的数据地址,复位时也指向编号0的地址且此时数据无效;

2.工作原理

2.1.空满标志

2.1.1.读空信号(rd_empty)

        一般情况下当读写指针相等时,表明FIFO已空,这种情况发生在复位操作时或当读指针读出FIFO中最后一个有效数据时(即读指针追赶上写指针),此时读空信号有效,如下左图:

fifo工作原理,IC逻辑,fifo深度,同步fifo,异步fifofifo工作原理,IC逻辑,fifo深度,同步fifo,异步fifo

2.1.2.写满信号(wr_full)

        当读写指针再次相等时,即写指针转了一圈又折回来(wrapped around)从起始低位追上了读指针(写比读快),此时表明FIFO已满,如上右图:

2.2.空满判断机制

2.2.1.同步fifo空满判断

  • 方案一:extra bit

                深度为的FIFO其地址位宽为n,若数据位宽为W则该FIFO的容量为N*W bits。

                现在在指针添加1个extra bit即地址的MSB,使其变为n+1 bits,该extra bit用来指示读/写指针是否连续递增并越过了FIFO的最后一个地址,若越过则该MSB加1,其他位清零。例如深度为8的fifo,需要采用1+3bits的地址位宽,MSB作为指针折回标志,低3bits作为地址。

                那么判断机制读指针读出FIFO最后一个有效数据后即会停止递增)为:

                ①如果两个指针的MSB不同,就说明写指针比读指针多折回一次,此时若除开MSB以外的地址位相等,则表示FIFO已满;

                ②如果两个指针的MSB相同,就说明读写指针的折回次数相同,若其他地址位相等,则表示读写指针完全相等,FIFO已空。

  • 方案二:设置数据计数器

                设置一个data_counter,当写使能有效时数据计数器加1,每读出一个数据时该计数器又减1。如此,当data_counter=0时FIFO为空,data_counter=FIFO深度时表明已满。

                缺点:计数器会占用额外资源,当FIFO较大时,可能会降低FIFO的读写速度。

2.2.2.异步fifo空满判断

  • 判断步骤如下:

                ①地址指针采用二进制(binary)+extra bit

                ②二进制指针转gray码后跨时钟域同步做比较

        当读写指针采用二进制表示且读写操作属于异步时钟时,读写指针做比较前需要先将其中一个指针同步到另一个指针的时钟域后再操作,直接同步这样容易产生亚稳态问题。

        可以使用一个二进制转gray码的转换电路,将地址转换为对应的gray码后再同步到另一个时钟域,进行对比产生空满指示,如左下图:

fifo工作原理,IC逻辑,fifo深度,同步fifo,异步fifofifo工作原理,IC逻辑,fifo深度,同步fifo,异步fifo

                例如1+3bits的二进制地址完全转换为gray后如右上图所示,此时空满标志不能按照原来二进制的方法来判断,gary码指针的空满判断标准如下:

                空标志:gray码地址完全相等(包括MSB)。

                满标志:高两位(MSB+次高位)不同,其余各位相同。

                PS:二进制与格雷码互相转换 。

  • 补充:

                ①同步方向产生保守的空满机制:

                        读指针同步到写时钟域:经过一定的同步时间后,此时同步后(写时钟域的)读指针小于或等于真实的(读时钟域)的读指针,而写指针是即时且真实的,空满判断机制可产生保守的“假写满”(正确且安全设计)和错误的“读空”。

                        反之同理,总结:写时钟域产生正确的“假写满”,读时钟域产生正确的“假读空”

                ②由于读写异步快时钟域同步慢时钟域指针可能会漏采,不会影响空满判断逻辑:

                        举例读慢写快:写指针同步到读时钟域发生漏采,即读时钟域采样到的写指针小于真实的(写时钟域的)写指针,此时不会导致“读空判断逻辑”错误,也是保守且正确的。反之亦然。

3.FIFO代码设计示例

3.1.同步FIFO代码

        同步FIFO由于没有跨时钟的操作,所以只需要使用二进制即可,不用格雷码操作。根据上面的分析,有两种方法进行表示full/empty状态,代码如下:

//1、generate full/empty signal by addr
assign full = (waddr_ptr == {~raddr_ptr[ADDR_WIDTH-1],
                              radde_ptr[ADDR_WIDTH-2:0]});
assign empty = (waddr_ptr == raddr_ptr);
//2、generate full/empty signal by conuter
always @(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		data_cnt <= {ADDR_WIDTH{1'b0}};
	end
	else if(wen && ren && !full && !empty)begin
		data_cnt <= data_cnt;
	end
	else if(wen && !full)begin
		data_cnt <= data_cnt + 1'b1;
	end
	else if(ren && !empty)begin
		data_cnt <= data_cnt - 1'b1;
	end
end

assign full = (data_cnt == FIFO_DEPTH);
assign empty = (data_cnt == 0);

3.2.异步FIFO代码

        由于存在读写时钟不同步的问题,采用的解决方法是:加两级寄存器同步 + 格雷码(目的都是消除亚稳态),代码示例如下: 

fifo工作原理,IC逻辑,fifo深度,同步fifo,异步fifo

`timescale 1ns/1ps
module async_fifo #(
	parameter	DATA_WIDTH	= 32,
	parameter	DATA_DEPTH	=  8,
	parameter	PTR_WIDTH	= $clog2(DATA_DEPTH)
)(
	//write interface	
	input  wire					 clk_wr_i,
	input  wire					 rst_n_wr_i,	
	input  wire					 wr_en_i,
	input  wire [DATA_WIDTH-1:0] wr_data_i ,
	output wire					 wr_full_o,
	
	//read interface
	input  wire					 clk_rd_i,
	input  wire					 rst_n_rd_i,
	input  wire					 rd_en_i,
	output reg  [DATA_WIDTH-1:0] rd_data_o,
	output wire					 rd_empty_o
);
	reg  [DATA_WIDTH-1:0]	fifo[DATA_DEPTH-1:0];

    reg                     wr_ptr_ext;
	reg	 [ PTR_WIDTH-1:0]	wr_ptr;
	wire [ PTR_WIDTH  :0]	wr_ptr_gray;
	reg	 [ PTR_WIDTH  :0]	wr_ptr_gray_d1;
	reg	 [ PTR_WIDTH  :0]	wr_ptr_gray_d2;

	reg                     rd_ptr_ext;
	reg  [ PTR_WIDTH-1:0]	rd_ptr;
	wire [ PTR_WIDTH  :0]	rd_ptr_gray;
	reg	 [ PTR_WIDTH  :0]	rd_ptr_gray_d1;
	reg  [ PTR_WIDTH  :0]	rd_ptr_gray_d2;
	
//------------- ptr++ and data inout--------------
always @(posedge clk_wr_i or negedge rst_n_wr_i) begin
	if(!rst_n_wr_i)begin
		{wr_ptr_ext, wr_ptr} <= {(PTR_WIDTH+1){1'b0}};
        fifo[wr_ptr]         <= { (DATA_WIDTH){1'b0}};
    end
	else if(wr_en_i && !wr_full_o)begin
		{wr_ptr_ext, wr_ptr} <= {wr_ptr_ext, wr_ptr} + 1'b1;
        fifo[wr_ptr]         <= wr_data_i;
    end
end

always @(posedge clk_rd_i or negedge rst_n_rd_i) begin
	if(!rst_n_rd_i)begin
		{rd_ptr_ext, rd_ptr} <= {(PTR_WIDTH+1){1'b0}};
		rd_data_o            <= { (DATA_WIDTH){1'b0}};
    end
	else if(rd_en_i && !rd_empty_o)begin
		{rd_ptr_ext, rd_ptr} <= {rd_ptr_ext, rd_ptr} + 1'b1;
		rd_data_o            <= fifo[rd_ptr];
    end
end
	
//--------- binary to gray ---------
assign rd_ptr_gray = {rd_ptr_ext, rd_ptr} ^ ({rd_ptr_ext, rd_ptr}>>1);
assign wr_ptr_gray = {wr_ptr_ext, wr_ptr} ^ ({wr_ptr_ext, wr_ptr}>>1);

//--------- pointer sync -----------
always @(posedge clk_wr_i or negedge rst_n_wr_i) begin
	if(!rst_n_rd_i) begin
		rd_ptr_gray_d1 <= {(PTR_WIDTH+1){1'b0}};
		rd_ptr_gray_d2 <= {(PTR_WIDTH+1){1'b0}};
	end
	else begin
		rd_ptr_gray_d1 <= rd_ptr_gray;
		rd_ptr_gray_d2 <= rd_ptr_gray_d1;
	end
end

always @(posedge clk_rd_i or negedge rst_n_rd_i) begin
	if(!rst_n_rd_i) begin
		wr_ptr_gray_d1 <= {(PTR_WIDTH+1){1'b0}};
		wr_ptr_gray_d2 <= {(PTR_WIDTH+1){1'b0}};
	end
	else begin
		wr_ptr_gray_d1 <= wr_ptr_gray;
		wr_ptr_gray_d2 <= wr_ptr_gray_d1;
	end
end

//------------ full_o and empty_o ------------------
assign wr_full_o  = (wr_ptr_gray=={~rd_ptr_gray_d2[PTR_WIDTH:PTR_WIDTH-1],
                     rd_ptr_gray_d2[PTR_WIDTH-2:0]}) ? 1'b1 : 1'b0;
assign rd_empty_o = (rd_ptr_gray==wr_ptr_gray_d2) ? 1'b1 : 1'b0;

endmodule

4.FIFO的深度计算

4.1.概念

        突发(burst)传输:In telecommunication, a burst transmission or data burst is the broadcast of a relatively high-bandwidth transmission over a short period。某个短时间内相对高带宽的数据传输。

        假如模块A不间断地往FIFO中写数据,模块B同样不间断地从FIFO中读数据,不同的是模块A写数据的时钟频率要大于模块B读数据的时钟频率,那么在一段时间内总是有一些数据没来得及被读走,如果系统一直在工作,那么那些没有被读走的数据会越累积越多,那么FIFO的深度需要是无穷大的,因此只有在突发数据传输过程中讨论FIFO深度才是有意义的。一次传递一包数据完成后再去传递下一包数据,一段时间内传递的数据个数称为burst length

        FIFO的最小深度与burst rate, burst size, read and write frequency等因素有关。要确定FIFO的深度,关键在于计算出在突发读写这段时间内有多少个数据没有被读走,即FIFO的最小深度就等于没有被读走的数据个数。

4.2.深度计算示例

        假定模块A向FIFO写数据的时钟频率为fa,模块B从FIFO读数据的时钟频率为fb。

场景1:idle cycles in both write and(or) read

假设:

  • 写数据时钟频率fa=80MHz,读数据时钟频率fb=50MHz;
  • 突发长度= number of data to be transferred = 120;
  • 每隔1个cycle写一次,每隔3个cycle读一次。

那么:

  • 每隔1个cycle写一次,意味着2个cycle才写一个数据;每隔3个cycle读一次,意味着4个cycle才读一个数据。
  • 写一个数据所需要的时间 = 2*1/80MHz = 25ns。突发传输中,写完所有数据所需要的时间 = 120*25ns = 3000ns。
  • 读一个数据所需要的时间 = 4*1/50MHz = 80ns。在3000ns内能够读走的数据个数 = 3000ns/80ns = 37.5。
  • 所以在3000ns内还没有被读走的数据个数 = 120-37.5 = 82.5,因此FIFO的最小深度为83。

场景2fa ≤ fb with no idle cycles in both write and read

假设:

  • 写数据时钟频率fa=40MHz,读数据时钟频率fb≥40MHz
  • 突发长度= number of data to be transferred = 120
  • 在突发传输过程中,数据都是连续读写的

由于读数据比写数据要快,因此FIFO只起到跨时钟域的作用,FIFO的最小深度为1即可。

场景3:Data rates are given,read and write random

        在工程设计中还存在一种情形,只给出数据在一段时间内的读写速率,怎么读写完全随机,这种情况需要考虑最坏的一种情况避免数据丢失。在最坏的情形中,读写的速率应该相差最大,也就是说需要找出最大的写速率和最小的读速率。

假设:

  • 写数据时钟频率fa=80MHz,读数据时钟频率fb=50MHz
  • 在写时钟周期内,每100个周期就有40个数据写入FIFO
  • 在读时钟周期内,每10个周期可以有8个数据读出FIFO

那么:

  • 首先没有给出数据的突发长度,从假设中可以得出每100个周期就有40个数据写入FIFO,因为数据是随机写入FIFO的,需要考虑做坏的情形,即写速率最大的情形,只有如下图背靠背的情形才是写速率最高的情形,burst length为80。

fifo工作原理,IC逻辑,fifo深度,同步fifo,异步fifo

  • 注意:这里需要验证一下是否有解即写入burst数据时间必须大于等于读出burst数据时间,不然数据就会越累积越多,使得FIFO的深度必须为无穷大。首先写入80个数据需要的时间 = 1/80MHz*(80*100/40)=2500ns,读出80个数据需要的时间 = 1/50MHz*(80*10/8)=2000ns,由于写入burst数据时间大于对出burst数据时间,因此有解。
  • 下面来计算FIFO最小深度,连续写入80个数据最快所需要时间 = 1/80MHz * 80 = 1000ns。
  • 从FIFO中读出一个数据至少所需时间 = (1/50MHz) * (10/8) = 25ns。那么在1000ns内能够读出的数据 = 1000ns/25ns = 40。
  • 在1000ns内没有读出的数据 = 80 - 40 = 40,因此FIFO的最小深度为40。

         参考FIFO深度计算。

4.3.异步FIFO的深度不为2的正整数次幂

4.3.1.FIFO的深度为1

        方案一:将深度加1变为2,这样地址指针用1bit表示即可,且不用添加extra bit。

fifo工作原理,IC逻辑,fifo深度,同步fifo,异步fifo

         方案二:采用脉冲同步读写信号,参考深度为1的异步FIFO设计。

        方案三:采用握手机制去跨时钟,不属于FIFO类型。

4.3.2.FIFO的深度为其他任意数

        无论FIFO的深度为奇数或偶数,都需要对地址指针扩展1bit来作为标志位,这样产生的地址指针循环一定为偶数,再利用格雷码的环回对称性,采用“掐头去尾+地址偏移”的方法。

        地址同步后不能采用原来2的整数次幂的gray判断空满机制来做判断,此时可以将格雷码再转回二进制后再做空满判断。

        参考任意深度异步FIFO设计。

5.读写位宽不一致问题

        对于异步fifo,由于地址不能跳变,fifo的位宽可以选择输入输出位宽的最小公倍数,会有一定的保守性。

        参考FPGA之FIFO详解,读写位宽不同。

6.异步FIFO中格雷码的约束

6.1.设置读写地址格雷码约束的原因

6.1.1.格雷码各bit位间延时不一样

        格雷码各bit位延时不一致,导致afifo功能异常。

        假设3bit的gray码各比特位延时不一致,比如gray[1]延时比gray[0]多一个采样周期,比如gray[2]延时比gray[1]多一个采样周期,虽然源端格雷码是符合要求的,但是由于格雷码延时不一致,导致采样端采样的格雷码不符合要求(不正确)。

6.1.2.格雷码到同步器的延时过大

        格雷码到同步器的延时越长,流水间隔越大,afifo性能越差。

        假如afifo深度为16,写地址waddr_gray码到同步器的延时为8个周期,加上同步器3个周期,写数据侧写入数据后,至少需要11个read_clk后读数据侧empty信号无效,也就是说至少11个read_clk后读侧才能读数据。而如果写地址waddr_gray码到同步器的延时为1个周期,则写数据侧写入数据后,只需要4个周期,读侧就能读数据了。

6.2.具体约束

        为了保证异步fifo的功能和性能保证,需要在综合约束文件sdc中,约束异步FIFO格雷码的最大延时

        约束如图所示:从格雷码寄存器的时钟端口---->到同步器的输入端口的最大延时。写地址waddr和读地址raddr格雷码同步都需要设置set_max_delay。此处set_max_delay是为了保证源端信号到达目的端被采样时的格雷码唯一bit跳变特性。延时可设置为读写时钟中最快时钟周期的一半,也可以设置成源端时钟的一半,或者设置成源端时钟的倍数且bit间的skew明显小于一个源端时钟周期

fifo工作原理,IC逻辑,fifo深度,同步fifo,异步fifo文章来源地址https://www.toymoban.com/news/detail-823889.html

到了这里,关于FIFO的工作原理及其设计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Verilog】同步FIFO原理及verilog实现(参数化)

            旨在学习理解,项目中还是用成熟IP靠谱~ 目录 一、FIFO原理 二、同步FIFO设计 2.1 位宽和深度 2.2 空、满标志 2.3 FIFO计数 2.4 ram模型 2.5 读/写操作 三、​​​​​​​verilog代码 四、仿真验证 后记 FIFO( First Input First Output)是指先进先出。模型如下:           F

    2024年02月05日
    浏览(34)
  • FIFO的Verilog设计(三)——最小深度计算

    FIFO的设计可参考 FIFO的Verilog设计(一)——同步FIFO FPGA的Verilog设计(二)——异步FIFO 参考文献 [1]FIFO最小深度计算   在实际使用FIFO时,需要考虑FIFO的深度如何设置,如果深度设置不当,可能会出现资源浪费或者数据丢失等情况。下面将简要介绍FIFO的最小深度如何计算。

    2024年02月04日
    浏览(92)
  • 跨时钟域方法(同步器、异步FIFO、边沿检测器、脉冲同步器、同步FIFO)

    目录 1、跨时钟域方法的原因 2、跨时钟处理的两种思路 3、跨时钟域分类——单比特信号跨时钟 3.1.1慢时钟———快时钟。(满足三边沿准则,有效事件可以被安全采样) 3.1.2慢时钟———快时钟。(不满足三边沿准则,有效事件可以被安全采样) 3.2.1有效事件传输背景下确

    2024年02月12日
    浏览(48)
  • FIFO专题之单口RAM实现FIFO(同步)

    使用单口RAM实现FIFO,其实很简单,其中的重点就是区分出读写, 读写如果同时启动,你肯定会思考单口RAM肯定会出问题,毕竟单口RAM只有一个口,肯定不能实现同时读写,那么怎么解决这个问题呢。 有两种办法: 第一种办法就是采用两个单口RAM,这样就可以了,两个单口

    2024年02月02日
    浏览(42)
  • 手撕代码——同步FIFO

      查看Xilinx官方FIFO IP核,其主要的信号有时钟信号、写端口信号、读端口信号,其中,写端口信号包括写满信号full、写使能信号wr_en、写数据输入din、几乎满信号almost_full;读端口信号包括读空信号empty、读使能信号rd_en、读数据输出dout、几乎空信号almost_empty。几乎满信号

    2024年02月06日
    浏览(44)
  • FIFO(三)——FIFO高级原理

      由于FIFO会占用芯片面积,选择容量合适的FIFO显得非常重要。特别是当有多个FIFO时,这种需求更加突出。FIFO过大将导致面积浪费,过小将导致FIFO上溢,造成数据丢失。因此需要根据实际需求合理选择位宽和深度。   同步FIFO的深度可以是任何一个正数,取值可能为8、

    2024年02月16日
    浏览(35)
  • 【Verilog】用双口RAM实现同步FIFO

    端口说明如下表。 双口RAM端口说明: 同步FIFO端口说明: 输入描述: input clk , input rst_n , input winc , input rinc , input [WIDTH-1:0] wdata 输出描述: output reg wfull , output reg rempty , output wire [WIDTH-1:0] rdata 双口RAM和代码框架: 同步FIFO,就是我们学习其他经典计算机语言(如C语言)的数据结

    2024年02月07日
    浏览(39)
  • 同步FIFO的verilog实现(2)——高位扩展法

            在之前的文章中,我们介绍了同步FIFO的verilog的一种实现方法:计数法。其核心在于:在同步FIFO中,我们可以很容易的使用计数来判断FIFO中还剩下多少可读的数据,从而可以判断空、满。         关于计数法实现同步FIFO的详细内容,请参考:同步FIFO的verilog实现(

    2024年02月09日
    浏览(37)
  • 用移位寄存器实现同步FIFO,带空满判断

            如图所示,同步FIFO带有push信号和pop信号,push代表往队列里面压入一个数据,pop代表往队列外面排出一个数据。         同步FIFO的空满判断用一个计数器来判断,收到push信号计数器加1,收到pop信号时计数器减1,考虑同时push和pop的情况计数器不变,当计数器为

    2024年02月14日
    浏览(57)
  • 【FIFO】异步 FIFO 设计

    目录   写在前面 简介 传递多个异步信号 同步 FIFO 指针 异步FIFO指针 二进制 FIFO 指针注意事项 FIFO测试问题 格雷码计数器 ‑ 样式 #1 格雷码模式 格雷码计数器基础 额外的格雷码计数器注意事项 格雷码计数器 ‑ 样式 #2 处理满空情况 产生空标志 产生满标志 不同的时钟速度

    2024年02月02日
    浏览(62)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包