今天尝试使用了Quartus Ⅱ 15.1 的FIFO的IP核。
———————————————————————————————————————
简单介绍一下FIFO。FIFO(First Input First Output),很容易理解,就是先进先出,和数据结构里的队列一样。举一个通俗的例子,在超市买东西,结账的时候,大家都在排队,先排队的人先结账走人,不在这里逗留(这点和RAM不同)。所以FIFO通常是作为数据缓冲结构,一般用于不同时钟域之间的数据传输,比如FIFO一端是采样速率比较慢的接口,另一端是采样速率比较块的接口。也可以用于输入数据和输出数据位宽不同的情况。Ip核的参数配置网上有很多,大家也可以看下《HELLO FPGA》里的详细介绍。
FIFO IP核主要用于同步或异步时钟域先入先出数据流的缓存。
FIFO是没有读写地址的,根据读写使能和上升沿触发的时钟进行写入和读出。而且数据不再FIFO里逗留,读出既从“结完账走人了”。所以它有写满和读空的标志位,我们可以利用两个标志位写读写逻辑使能,这一点比利用双口RAM做缓冲会简单方便很多。
简单的贴下代码,使用SignalTap仿真。
module fifo(
clk,rst_n,
RomAddr,rddata,RomData,rden,full,empty,clk_10M
);
input clk;
input rst_n;
output [7:0] RomData;
output reg [4:0] RomAddr;
output [7:0] rddata;
output reg rden;
output full;
output empty;
output clk_10M;
always @ (posedge clk or negedge rst_n)
if(!rst_n)
rden <= 'd0;
else if(full)
rden <= 1'b1;
else if(empty)
rden <= 1'b0;
else
rden <= rden;
Dif_Fifo Dif_Fifo_inst (
.data(RomData),
.rdclk(clk),
.rdreq(rden),
.wrclk(clk_10M),
.wrreq(~rden),
.q(rddata),
.rdempty(empty),
.wrfull(full)
);
/*
FIFO FIFO_inst (
.clock(clk),
.data(RomData),
.rdreq(rden),
.wrreq(wren),
.empty(empty),
.full(full),
.q(rddata),
.usedw(usedw)
);
*/
/*****************10M去读rom*****************/
//reg [4:0] RomAddr;
always @ (posedge clk_10M or negedge rst_n)
if(!rst_n)
RomAddr <= 'd0;
else if(RomAddr >= 5'd31)
RomAddr <= 'd0;
else
RomAddr <= RomAddr + 1'b1;
//wire [7:0] RomData;
Rom_Test Rom_Test_inst (
.address(RomAddr),
.clock(clk_10M),
.q(RomData)
);
/*****PLL分频产生10M的时钟*****/
//wire clk_10M;
Ip_Core_PLL Ip_Core_PLL_inst (
.refclk(clk), // refclk.clk
.rst(!rst_n), // reset.reset
.outclk_0(clk_10M), // outclk0.clk
.locked() // locked.export
);
endmodule
仿真: