一、FIFO:
即First-in-first-out,用于缓存数据的模块,对于同步FIFO数据写入FIFO的时钟和数据读出FIFO的时钟是同步的(synchronous)。
常用的对外接口:clk、rst_n、wr_en、rd_en、buf_in、buf_out、buf_full、buf_empty
FIFO深度:FIFO有多少个存储单元,一般读写指针位宽$clog2(FIFO_DEPTH);
FIFO宽度:一个存储单元写数据位宽是多少;
空满信号的产生一般有两种方式:
1、用一个计数器对读写数据的个数计数,为0就表示空,等于FIFO深度时就表示满;
2、利用读写指针,多定义一位读写位宽,最高位表示FIFO是否已经读写完成一圈;
wr_ptr:表示当前位置还未写
rd_ptr:表示当前位置还未读
FIFO设计代码:
module sync_fifo#(
parameter BUF_WIDTH = 8, //数据位宽
parameter BUF_DEPTH = 8, //数据个数,FIFO深度
parameter PTR_WIDTH = 3 //地址宽度为3
)(
input clk ,
input rst_n ,
input wr_en ,
input rd_en ,
input [7:0] buf_in , //data input to be pushed to buffer
output reg [7:0] buf_out , // port to output the data using pop
output buf_full , // buffer full indication
output buf_empty // buffer empty indication
);
//reg [PTR_WIDTH:0] fifo_cnt;
//reg [PTR_WIDTH-1:0] wr_ptr;
//reg [PTR_WIDTH-1:0] rd_ptr;
reg [PTR_WIDTH:0] wr_ptr;
reg [PTR_WIDTH:0] rd_ptr;
reg [BUF_WIDTH-1:0] buf_mem[0:BUF_DEPTH-1];
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
wr_ptr <= {(PTR_WIDTH+1){1'b0}};
else if(wr_en && ~buf_full)
wr_ptr <= wr_ptr + 1'b1;
end
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
rd_ptr <= {(PTR_WIDTH+1){1'b0}};
else if(rd_en && ~buf_empty)
rd_ptr <= rd_ptr + 1'b1;
end
/*always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
fifo_cnt <= {(PTR_WIDTH+1){1'b0}};
else if((wr_en && ~buf_full) && (rd_en && ~buf_empty))
fifo_cnt <= fifo_cnt;
else if(wr_en && ~buf_full)
fifo_cnt <= fifo_cnt + 1'b1;
else if(rd_en && ~buf_empty)
fifo_cnt <= fifo_cnt - 1'b1;
end*/
//assign buf_empty = (fifo_cnt == 0);
//assign buf_full = (fifo_cnt == BUF_DEPTH);
assign buf_full = (wr_ptr[3] != rd_ptr[3])&&(wr_ptr[2:0] == rd_ptr[2:0]);
assign buf_empty = (wr_ptr == rd_ptr);
integer i;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
for(i=0;i<=BUF_DEPTH-1;i=i+1)
buf_mem[i] <= {(BUF_WIDTH){1'b0}};
else if(wr_en && ~buf_full)
buf_mem[wr_ptr[2:0]] <= buf_in;
end
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
buf_out <= {(BUF_WIDTH){1'b0}};
else if(rd_en && ~buf_empty)
buf_out <= buf_mem[rd_ptr[2:0]];
end
endmodule
二、FIFO最小深度计算:(重点)
说明:
- burst length:只有在突发数据传输过程中讨论FIFO深度才是有意义的,也就是说我们一次传递一包数据完成后再去传递下一包数据,我们把一段时间内传递的数据个数称为burst length。若FIFO无止境的写数据,那FIFO深度只有无穷大才能满足。
- 要确定FIFO的深度,关键在于计算出在突发读写这段时间内有多少个数据没有被读走,即FIFO的最小深度就等于没有被读走的数据个数。
分几种情况:写读时钟为fa,fb,分fa>fb,fa<fb,fa==fb
举例:
假设:fa>fb
写数据时钟频率fa=80MHz
读数据时钟频率f,=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内能够读走的数据个数= 300ons/80ns = 37.5
所以在300ons内还没有被读走的数据个数= 120-37.5 =82.5
因此FIFO的最小深度为83
假设:fa<fb
写数据时钟频率fa=40MHz
读数据时钟频率f=50MHz
突发长度= number of data to be transferred = 120
每隔1个cycle写一次
每隔3个cycle读一次
那么:
每隔1个cycle写一次,意味着2个cycle才写一个数据
每隔3个cycle读一次,意味着4个cycle才读一个数据
写一个数据所需要的时间=2*1/4OMHz = 50ns
突发传输中,写完所有数据所需要的时间= 120*50ns = 6000ns
读一个数据所需要的时间=4*1/50MHz = 80ns
所以写完所有的突发传输数据需要花费6000ns
在6000ns内能够读走的数据个数编辑ns/B0ns = 75
所以在6000ns内还没有被读走的数据个数=120-75= 45
因此FIFO的最小深度为45
另一种情况:没有给出突发长度时,采用背靠背方式传递数据,就是指连续写两次数据,假设中可以得出每100个周期就有40个数据写入FIFO,每10个周期可以有8个数据读出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
公式:
- Burst_length :最大突发长度, 注意: 指在突发时间段, 写时钟 写入的数据长度
- rd_rate:指一个周期读取的数据字节(byte),1字节 = 8 bit
一个8bit宽的FIFO,输入时钟为100MHz,输出时钟为95MHz,设一个package为4Kbit, 且两个package之间的发送间距足够大。问FIFO的最小深度。
异步FIFO,读写频率不同,读写位宽相同。发送一次Burst突发数据量为4000bit。
发送Burst的时间 T=4000/100MHz。
接收方接受的数据量 T*95MHz = 4000 * 95 / 100 bit
FIFO需要缓存的数据量 4000 - 4000 * 95 / 100 = 200bit
FIFO_Depth >= 200bit/8bit = 25。
那么FIFO的深度至少要大于等于25才行。