FIFO简介
- first-in-first-out
- FIFO一般用于不同时钟域之间的数据传输,也常用来实现不同位宽的接口的数据匹配
- fifo从输入时钟 的角度来分,有两种类型:单时钟FIFO(SCFIFO)和双时钟FIFO(DCFIFO).
- FIFO的常见参数:
- FIFO的宽度:FIFO一次独写操作的数据位宽N
- FIFO的深度 :FIFO可以存储多少个宽度为N位的数据
- 空标志:对于双时钟FIFO又分为读空标志rdempty和写空标志wrempty。FIFO已空或将要空时由FIFO的状态电路送出的一个信号, 以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出。
- 满标志:对于双时钟FIFO又分为读满标志rdfull和写满标志wrfull。FIFO已满或将要写满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出。
- 读时钟:读FIFO时所遵循的时钟,在每个时钟的上升沿触发。
- 写时钟:写FIFO时所遵循的时钟,在每个时钟的上升沿触发。
实验任务
- 生成FIFO IP core ,并实现FIFO为空时就开始向FIFO中写入自加数据,直到FIFO写满为止;当FIFO写满时则开始从FIFO中读出数据,直到FIFO读空为止。
硬件接口
软件框图
module ip_fifo(
input sys_clk,
input sys_rst_n
);
wire wrreq;
wire [7:0] data;
wire wrempty;
wire wrfull;
wire wrusedw;
wire rdreq;
wire [7:0] q;
wire rdempty;
wire rdfull;
wire rdusedw;
/****************************************
main code
****************************************/
fifo_rd u_fifo_rd(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.rdreq (rdreq ),
.data (q ),
.rdempty (rdempty ),
.rdfull (rdfull )
);
fifo_wr u_fifo_wr(
//system clock and reset
.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
//user interface
.wrempty(wrempty),
.wrfull(wrfull),
.data(data),
.wrreq(wrreq) // write request
);
fifo fifo_inst (
.wrclk ( sys_clk ),
.wrreq ( wrreq ),
.data ( data ),
.wrempty ( wrempty ),
.wrfull ( wrfull ),
.wrusedw ( wrusedw ),
.rdclk ( sys_clk ),
.rdreq ( rdreq),
.q ( q),
.rdempty ( rdempty ),
.rdfull ( rdfull),
.rdusedw ( rdusedw )
);
endmodule
module fifo_wr(
//system clock and reset
input sys_clk,
input sys_rst_n,
//user interface
input wrempty, // ip core cause
input wrfull, // ip core cause
output reg [7:0] data,
output wrreq // write request
);
//reg define
reg wrreq_t;
reg [1:0] flow_cnt;
/**************************************
** main code
**************************************/
assign wrreq=~wrfull & wrreq_t; //fifo not full and write request
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)begin
wrreq_t<=1'b0;
data<=8'd0;
flow_cnt<=2'd0;
end
else begin
case(flow_cnt)
2'd0: begin
if(wrempty)begin
wrreq_t<=1'b1;
flow_cnt<=flow_cnt+1'b1;
end
else
flow_cnt<=flow_cnt;
end
/
2'd1: begin
if(wrfull)begin
wrreq_t<=1'b0;
data<=8'd0;
flow_cnt<=2'd0;
end
else begin
wrreq_t<=1'b1;
data<=data+1'b1;
end
end
/*************************************/
default : flow_cnt<=2'd0;
endcase
end
end
endmodule
module fifo_rd(
input sys_clk,
input sys_rst_n,
input [7:0] data,
input rdfull,
input rdempty,
output rdreq //
);
//reg define
reg rdreq_t;
reg [7:0] data_fifo;
reg [1:0] flow_cnt ;
assign rdreq=~rdempty & rdreq_t;
//fifo read data
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)begin
rdreq_t<=1'b0;
data_fifo<=8'd0;
end
else begin
case(flow_cnt)
2'd0:begin
if(rdfull)begin
rdreq_t<=1'b1;
flow_cnt<=flow_cnt+1'b1;
end
else
flow_cnt<=flow_cnt;
end
2'd1:begin
if(rdempty)begin
rdreq_t<=1'b0;
data_fifo<=8'd0;
flow_cnt<=2'd0;
end
else begin
rdreq_t<=1'b1;
data_fifo<=data;
end
end
default: flow_cnt<=2'd0;
endcase
end
end
endmodule
例化IP core 详情参见正点原子开拓者开发板手册
仿真结果
实验总结
在实验过程中主要注意写请求和读请求的产生,还有读模块和写模块与IP core的配合关系 以及读写的转换时刻。