FIFO是First in first out 的缩写,是一种先进先出的数据缓存器,它与普通存储器的区别是没有外部读写地址线。这样使用起来就非常简单,但缺点是只能顺序写入数据,顺序读出数据,其数据地址由内部读写指针自动加1完成,不能像普通的存储器那样由地址线决定读取或写入某个具体的存储单元。
FIFO 一般用于不同时钟域之间的数据传输,比如一端为串行输入的图像数据,另一端为处理器以并行方式读取的图像数据,由于两端读写速率不一致,需要先行将串行数据进行串并转换缓存写入FIFO中,达到一定的条件,MCU在一次性将所有缓存数据读走(直到FIFO的状态变成空为止)。
FIFO的宽度:它指的是FIFO一次读写操作的数据位,专用FIFO芯片的宽度是固定的,也有可选择的,如果用FPGA自己实现一个FIFO,其数据位,也就是宽度可以自己定义。
FIFO的深度,它指的是FIFO可以存储多少个N位的数据。如1个8位的FIFO,深度是16,那就是可以存储16个8位的数据;深度为1024,就可以存储1024个8位的数据。
满标志:输出信号,FIFO已经满的时候,由FIFO的状态电路送出一个信号,以阻止继续向FIFO中写数据照成溢出。
空标志:输出信号,FIFO已空的时候,由FIFO的状态电路送出一个信号,以阻止继续从FIFO中读出数据而造成无效数据的读出。
读使能:输入信号,读出数据时的使能信号
读时钟:输入信号,读数据时所需要的时钟信号,在每个有效时钟沿来临时如果读使能信号有效则读数据。
读出数据:输出信号,读操作时反映在输出端口上的有效数据。
写使能:输入信号,写入数据时的使能信号
写时钟:写入数据所需要的时钟
写入数据:输入信号,待写入数据,写操作时将端口上的数据写入FIFO。
读指针:指向下一个要读出的数据的存储单元的地址,读完后自动加1
写指针:指向下一个要写入数据的存储单元的地址,写完后自动加1
读写指针其实就是读写的地址,只不过这个地址不是任意选择,而是连续的。
根据FIFO工作的时钟域,可以将FIFO分为同步FIFO和异步FIFO。同步FIFO是指读时钟和写时钟为同一个时钟,异步FIFO是指读写时钟不一致,是相互独立的。
module fifo_serial(
clk,
wen,
rst,
full,
empty,
data_in,
data_out
);
input clk; // 外部输入时钟
input wen; // 外部输入写使能,低有效
input ren; // 外部输入读使能,低有效
input rst; // 外部输入复位信号,低有效
input [7:0]data_in; // 外部输入待写入数据
output full;
output empty;
output [7:0] data_out; // 外部读出的数据
reg [9:0] waddr;
reg [9:0] raddr;
reg [10:0] count;
// FIFO中有效数据个数,如果为0则FIFO为空状态;如果为1024,则FIFO为满状态;
wire wen_wire;
wire ren_wire;
// 在写使能并且没有满的情况下,写指针加1;如果已经满了,则写指针不变
always@(posedge clk or negedge rst)
if(rst==1'b0)
waddr <= 10'd0;
else if(wen == 1'b0 && full != 1'b1)
waddr <= waddr + 1'b1;
else
waddr <= waddr;
// 在读使能并没有空的情况下,读指针加1;如果已经满了,则读指针不变
always@(posedge clk or negedge rst)
if(rst == 1'b0)
raddr <= 10'd0;
else if(ren == 1'b0 && empty != 1'b1)
raddr <= raddr + 1'b1;
else
raddr <= raddr;
// 从上面这段代码产生FIFO内有效数据计数器
always@(posedge clk or negedge rst)
if(rst == 1'b0)
count <= 11'd0;
else begin
case({wen, ren})
2'b00:
begin
count <= count;
end
2'b01:
begin
if(full == 1'b0)
count <= count + 1;
else
count <= count;
end
2'b10:
begin
if(empty == 1'b0)
count <= count + 1;
else
count <= count;
end
default:
begin
count <= count;
end
endcase
end
// FIFO 中有效数据个数,如果为0则FIFO为空状态
assign empty=(count==11'd0)?1'b1:1'b0;
// FIFO 中有效数据个数,如果为1024则FIFO为满状态
assign full = (count==11'd1024)?1'b1:1'b0;
// 在写使能有效并且已经满的情况下,不产生对双端口RAM的写操作
assign wen_wire = (full == 1'b1)? 1'b1:wen;
// 在读使能有效并且已经空的情况下,不产生对双端口RAM的读操作
assign ren_wire = (empty == 1'b1)?1'b1:ren;
// 下面为例化的双端口RAM
dpram1k u1(
.WD(data_in),
.RD(data_out),
.WEN(wen_wire),
.REN(ren_wire),
.WADDR(waddr),
.RADDR(raddr),
.RWCLK(clk),
.RESET(rst)
);