FIFO是英文First In First Out 的缩写,是一种先进先出的数据缓存器,他与普通存储器的区别是没有外部读写地址线,这样使用起来非常简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。
FIFO的一些重要参数
1、FIFO的宽度:也就是英文资料里常看到的THE WIDTH,它指的是FIFO一次读写操作的数据位,就像MCU有8位和16位,ARM 32位等等。
2、FIFO的深度:THE DEEPTH,它指的是FIFO可以存储多少个N位的数据(如果宽度为N)。如一个8位的FIFO,若深度为8,它可以存储8个8位的数据,深度为12 ,就可以存储12个8位的数据。
3、满标志:FIFO已满或将要满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出(overflow)。
4、空标志:FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出(underflow)。
5、读指针:指向下一个读出地址。读完后自动加1。
6、写指针:指向下一个要写入的地址的,写完自动加1。
对于FIFO,读写指针都指向一个内存的初始位置,每进行一次读写操作,相应的指针就递增一次,指向下一个内存位置。当指针移动到了内存的最后一个位置时,它又重新跳回初始位置。在FIFO非满或非空的情况下,这个过程将随着读写控制信号的变化一直进行下去。如果FIFO处于空的状态,下一个读动作将会导致向下溢(underflow),一个无效的数据被读人;同样,对于一个满了的FIFO,进行写动作将会导致向上溢出(overflow),一个有用的数据被新写入的数据覆盖。这两种情况都属于误动作,因此需要设置满和空两个信号,对满信号置位表示FIFO处于满状态,对满信号复位表示FIFO非满,还有空间可以写入数据;对空信号置位表示FIFO处于空状态,对空信号复位表示FIFO非空,还有有效的数据可以读出。
/**************************************
* Module: fifo
* Date:2014-08-10
* Author: hemmingway@163.com
*
* Description: FIFO存储器设计
***************************************/
module fifo(clk,rstp,din,writep,readp,dout,emptyp,fullp
);
input clk;
input rstp; // 复位信号
input[15:0] din;
input readp;
input writep;
output[15:0] dout;
output emptyp;
output fullp;
parameter DEPTH = 2,MAX_COUNT=2'b11; //定义地址最大值reg emptyp;
reg fullp;
reg[15:0] dout;
reg[(DEPTH-1):0] tail;
reg[(DEPTH-1):0] head;
reg[(DEPTH-1):0] count;
reg[15:0] fifomem[0:MAX_COUNT]; // 定义fifo存储器,4个16位的存储器// dout被赋给tail指针指向的数值
always @(posedge clk) beginif(rstp==1) begindout <= 16'h0000; // 复位信号有效置0endelse begindout <= fifomem[tail]; //将fifomem中第tail个单元给doutend
end// 写入数据
always @(posedge clk) beginif(rstp==1'b0 && writep == 1'b1 && fullp == 1'b0) beginfifomem[head]<=din; // 写入end
end// head指针递增
always @(posedge clk) beginif(rstp==1'b1) beginhead<=2'b00;endelse beginif(writep==1'b1 && fullp==1'b0) beginhead<=head+1;endend
end//tail指针递增
always @(posedge clk) beginif(rstp==1'b1) begintail<=2'b00;endelse beginif(readp==1'b1 && emptyp==1'b0) begintail<=tail+1;endend
end// 计数器
always @(posedge clk) beginif (rstp == 1'b1) begincount <= 2'b00;endelse begincase ({readp, writep})2'b00: count <= count;2'b01: if (count != MAX_COUNT) count <= count + 1; //为写状态时计数器进行加法计数2'b10: if (count != 2'b00)count <= count - 1; //为读状态计数器进行减法计数2'b11:count <= count;endcaseend
end// empty指针
always @(count) beginif (count == 2'b00)emptyp <= 1'b1; //count为0时emptyp赋为1elseemptyp <= 1'b0;
end// fullp指针
always @(count) beginif (count == MAX_COUNT)fullp <= 1'b1; //计数到最大时fullp赋为1elsefullp <= 1'b0;
endendmodule
/**************************************
* Module: test_fifo
* Date:2014-08-10
* Author: hemmingway@163.com
*
* Description: FIFO测试程序
***************************************/
module test_fifo;reg clk;
reg rstp;
reg [15:0] din;
reg readp;
reg writep;
wire [15:0] dout;
wire emptyp;
wire fullp;reg [15:0] value;
fifo U1 (.clk(clk),.rstp(rstp),.din(din),.readp(readp),.writep(writep),.dout(dout),.emptyp(emptyp),.fullp(fullp));// 读任务
task read_word;
begin@(negedge clk);readp = 1;@(posedge clk) #5;readp = 0;
end
endtask// 写任务
task write_word;
input [15:0] value;
begin@(negedge clk);din = value;writep = 1;@(posedge clk);#5;din = 16'hzzzz;writep = 0;
end
endtaskinitial beginclk = 0;forever begin#10 clk = 1;#10 clk = 0;end
endinitial begin//test1;test2; //调用测试模块2
endtask test1;
begindin = 16'hzzzz;writep = 0;readp = 0;rstp = 1;#50 rstp = 0;#50;write_word (16'h1111);write_word (16'h2222);write_word (16‘h3333); //写入3个数据read_word;read_word; //读两个write_word (16‘h4444); //在写一个数据repeat (6) beginread_word;
endwrite_word (16'h0001);write_word (16'h0002);write_word (16'h0003);write_word (16'h0004);write_word (16'h0005);write_word (16'h0006);write_word (16'h0007);write_word (16'h0008);
repeat (6) beginread_word;end
end
endtasktask test2;
reg [15:0] writer_counter;
beginwriter_counter = 16'h0001;din = 16'hzzzz;writep = 0;readp = 0;rstp = 1;#50 rstp = 0;#50;fork//写数据beginrepeat (500) begin@(negedge clk);if (fullp == 1'b0) beginwrite_word (writer_counter);#5;writer_counter = writer_counter + 1;end#50;endend//读数据beginforever begin@(negedge clk);if (emptyp == 1'b0) beginread_word;end #50;endendjoin
end
endtaskendmodule