国内免费云主机,网站图片大小优化,长春建站网站模板,供电局招聘2023社招1.简介 FIFO( First Input First Output)简单说就是指先进先出。FIFO存储器是一个先入先出的双口缓冲器#xff0c;即第一个进入其内的数据第一个被移出#xff0c;其中一个口是存储器的输入口#xff0c;另一个口是存储器的输出口。 对于单片FIFO来说#xff0c;主要有两种…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.主要参数 宽度WIDTHFIFO每个地址的数据位宽W深度DEEPTHFIFO可以存储多少个W位的数据满full标志FIFO已满或将满时会输出一个对写操作的反压信号以阻止被继续写入数据而溢出空empty标志FIFO已空或将空时会输出一个对读操作的反压信号以避免被继续读出无效数据读/写时钟读/写操作所遵循的时钟每个时钟沿触发。根据FIFO工作的时钟域分为同步/异步FIFO。同步FIFO是指读时钟和写时钟为同一个时钟在时钟沿来临时同时发生读写。异步FIFO读写时钟不一致读写相互独立。 读写指针即读写地址当前读/写操作完成后指针自动加一指向下一个地址连续递增。 写指针总是指向下一个将要被写入的地址复位时指向编号0的地址读指针总是指向下一个将要被读出的数据地址复位时也指向编号0的地址且此时数据无效2.工作原理
2.1.空满标志
2.1.1.读空信号rd_empty 一般情况下当读写指针相等时表明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使其变为n1 bits该extra bit用来指示读/写指针是否连续递增并越过了FIFO的最后一个地址若越过则该MSB加1其他位清零。例如深度为8的fifo需要采用13bits的地址位宽MSB作为指针折回标志低3bits作为地址。 那么判断机制读指针读出FIFO最后一个有效数据后即会停止递增为 ①如果两个指针的MSB不同就说明写指针比读指针多折回一次此时若除开MSB以外的地址位相等则表示FIFO已满 ②如果两个指针的MSB相同就说明读写指针的折回次数相同若其他地址位相等则表示读写指针完全相等FIFO已空。 方案二设置数据计数器设置一个data_counter当写使能有效时数据计数器加1每读出一个数据时该计数器又减1。如此当data_counter0时FIFO为空data_counterFIFO深度时表明已满。 缺点计数器会占用额外资源当FIFO较大时可能会降低FIFO的读写速度。
2.2.2.异步fifo空满判断
判断步骤如下①地址指针采用二进制binaryextra bit ②二进制指针转gray码后跨时钟域同步做比较 当读写指针采用二进制表示且读写操作属于异步时钟时读写指针做比较前需要先将其中一个指针同步到另一个指针的时钟域后再操作直接同步这样容易产生亚稳态问题。 可以使用一个二进制转gray码的转换电路将地址转换为对应的gray码后再同步到另一个时钟域进行对比产生空满指示如左下图 例如13bits的二进制地址完全转换为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)beginif(!rst_n)begindata_cnt {ADDR_WIDTH{1b0}};endelse if(wen ren !full !empty)begindata_cnt data_cnt;endelse if(wen !full)begindata_cnt data_cnt 1b1;endelse if(ren !empty)begindata_cnt data_cnt - 1b1;end
endassign full (data_cnt FIFO_DEPTH);
assign empty (data_cnt 0);
3.2.异步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 interfaceinput 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) beginif(!rst_n_wr_i)begin{wr_ptr_ext, wr_ptr} {(PTR_WIDTH1){1b0}};fifo[wr_ptr] { (DATA_WIDTH){1b0}};endelse if(wr_en_i !wr_full_o)begin{wr_ptr_ext, wr_ptr} {wr_ptr_ext, wr_ptr} 1b1;fifo[wr_ptr] wr_data_i;end
endalways (posedge clk_rd_i or negedge rst_n_rd_i) beginif(!rst_n_rd_i)begin{rd_ptr_ext, rd_ptr} {(PTR_WIDTH1){1b0}};rd_data_o { (DATA_WIDTH){1b0}};endelse if(rd_en_i !rd_empty_o)begin{rd_ptr_ext, rd_ptr} {rd_ptr_ext, rd_ptr} 1b1;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) beginif(!rst_n_rd_i) beginrd_ptr_gray_d1 {(PTR_WIDTH1){1b0}};rd_ptr_gray_d2 {(PTR_WIDTH1){1b0}};endelse beginrd_ptr_gray_d1 rd_ptr_gray;rd_ptr_gray_d2 rd_ptr_gray_d1;end
endalways (posedge clk_rd_i or negedge rst_n_rd_i) beginif(!rst_n_rd_i) beginwr_ptr_gray_d1 {(PTR_WIDTH1){1b0}};wr_ptr_gray_d2 {(PTR_WIDTH1){1b0}};endelse beginwr_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]}) ? 1b1 : 1b0;
assign rd_empty_o (rd_ptr_graywr_ptr_gray_d2) ? 1b1 : 1b0;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。 场景1idle cycles in both write andor read 假设
写数据时钟频率fa80MHz读数据时钟频率fb50MHz突发长度 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 假设
写数据时钟频率fa40MHz读数据时钟频率fb≥40MHz突发长度 number of data to be transferred 120在突发传输过程中数据都是连续读写的
由于读数据比写数据要快因此FIFO只起到跨时钟域的作用FIFO的最小深度为1即可。 场景3Data rates are givenread and write random 在工程设计中还存在一种情形只给出数据在一段时间内的读写速率怎么读写完全随机这种情况需要考虑最坏的一种情况避免数据丢失。在最坏的情形中读写的速率应该相差最大也就是说需要找出最大的写速率和最小的读速率。
假设
写数据时钟频率fa80MHz读数据时钟频率fb50MHz在写时钟周期内每100个周期就有40个数据写入FIFO在读时钟周期内每10个周期可以有8个数据读出FIFO
那么
首先没有给出数据的突发长度从假设中可以得出每100个周期就有40个数据写入FIFO因为数据是随机写入FIFO的需要考虑做坏的情形即写速率最大的情形只有如下图背靠背的情形才是写速率最高的情形burst length为80。注意这里需要验证一下是否有解即写入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。 方案二采用脉冲同步读写信号参考深度为1的异步FIFO设计。 方案三采用握手机制去跨时钟不属于FIFO类型。
4.3.2.FIFO的深度为其他任意数 无论FIFO的深度为奇数或偶数都需要对地址指针扩展1bit来作为标志位这样产生的地址指针循环一定为偶数再利用格雷码的环回对称性采用“掐头去尾地址偏移”的方法。 地址同步后不能采用原来2的整数次幂的gray判断空满机制来做判断此时可以将格雷码再转回二进制后再做空满判断。 参考任意深度异步FIFO设计。
5.读写位宽不一致问题 对于异步fifo由于地址不能跳变fifo的位宽可以选择输入输出位宽的最小公倍数会有一定的保守性。 参考FPGA之FIFO详解读写位宽不同。