FIFO的基本知识与设计实现

最近在学习FPGA的FIFO,现在将最近的FIFO学习情况做一个小结:
首先从几个问题来引入FIFO的概念吧
1) FIFO是什么?
答:FIFO的英文是First in First out,也就是先进先出,即先进入FIFO的数据也最先被读出,一般作为数据传输的缓冲器。他与普通的RAM和ROM的区别在于FIFO不用给定读写的地址,在进行读写操作的过程当中是顺序进行的,不需要给定地址线。
2) FIFO的作用是?
a)FIFO的作用主要是在进行数据传输的过程当中,作为缓冲器对数据进行缓冲。
b)FIFO可以处理跨时钟域的数据交互,主要是异步FIFO,可以处理不同时钟域的数据传输,因为来自不同时钟域的数据传输速率不一样,如果没有FIFO的话,很可能产生接收数据不是传输数据的现象,同时也能避免亚稳态的现象。
3)同步FIFO和异步FIFO的区别是?
FIFO分为同步FIFO和异步FIFO,当配置为同步FIFO的时候,只使用wr_clk,即所有的输入输出的信号都同步于写时钟;当被配置为异步FIFO的时候,写端口和读端口分别由独立的时钟,即wr_clk和rd_clk。
到这里想必大家对FIFO有了一个大致的了解,那么FIFO大致是什么样子的呢?那就请看下图:
在这里插入图片描述

其中左侧Write Agent是写数据侧,右侧为读数据侧,对FIFO操作时要注意各个信号的方向,其中almost_full于almost_empty是FIFO的将满和将空标志,也就是full和empty信号的前一拍,这两个信号的作用是在于避免使FIFO写满和读空,所以这两个信号出现表示不能往FIFO里面写数据了,以及不能从FIFO里面读数据了。
同时要注意almost_full信号是在Write_Agent模块产生的,如果在Read Agent模块使用的话,建议将这个先进行同步处理,也就是我们俗称的打拍处理,同时如果在Write Agent模块中使用almost_empty信号也是这样。
那么说到这儿,我们怎么设计FIFO呢?我们可以调用Vivado当中的IP核,打开IP Catalog搜索FIFO,点击FIFO Generate就可以对FIFO进行配置。
另外附上fifo的设计思路如下:
在这里插入图片描述

大致FIFO的基础知识了解的差不多了,那我们就上代码吧

1) 顶层模块,完成对读FIFO模块、写FIFO模块以及FIFO IP核进行例化
顶层模块代码如下:(该例程是异步FIFO,但是写时钟和读时钟都是采用的同一个时钟)
module FIFO_IP(
input sys_clk ,
input sys_rst_n ,
);
wire fifo_wr_en;
wire fifo_rd_en;
wire [7:0] fifo_din;
wire [7:0] fifo_dout;
wire full;
wire empty;
wire almost_full;
wire almost_empty;
wire [7:0] rd_data_count ;
wire [7:0] wr_data_count ;
//例化FIFO IP核
fifo_generator_0 your_instance_name (
.wr_clk(sys_clk), // input wire wr_clk
.rd_clk(sys_clk), // input wire rd_clk
.din(fifo_din), // input wire [31 : 0] din
.wr_en(fifo_wr_en), // input wire wr_en
.rd_en(fifo_rd_en), // input wire rd_en
.dout(fifo_out), // output wire [31 : 0] dout
.full(full), // output wire full
.almost_full(almost_full), // output wire almost_full
.empty(empty), // output wire empty
.almost_empty(almost_empty), // output wire almost_empty
.rd_data_count(rd_data_count), // output wire [7 : 0] rd_data_count
.wr_data_count(wr_data_count) // output wire [7 : 0] wr_data_count
);

//例化fifo写模块
fifo_wr u_fifo_wr(
.clk (sys_clk ),
.rst_n (sys_rst_n ),
.almost_empty (almost_empty),
.almost_full (almost_full ),
.fifo_wr_data (fifo_wr_data),
.fifo_wr_en (fifo_wr_en )
);

//例化fifo读模块
fifo_rd u_fifo_rd(
.clk (s’y’s_clk ),
.rst_n (sys_rst_n ),
.fifo_rd_en (fifo_rd_en ),
.almost_empty (almost_empty ),
.almost_full (almost_full ),
.fifo_rd_data (fifo_dout )
);

endmodule

读写控制模块如下:
module fifo_wr(
input clk ,
input rst_n ,
input almost_empty ,
input almost_full ,
output reg [7:0] fifo_wr_data ,
output reg fifo_wr_en
);
reg [1:0] state ;
reg almost_empty_d0;//因为empty是读时钟域过来的,所以要做同步处理
reg almost_empty_d1;
reg [3:0] dly_cnt ;//延时计数器
always@(posedge clk )begin//上升沿有效
if(!rst_n) begin //打拍处理
almost_empty_d0 <= 1’b0;
almost_empty_d1 <= 1’b1;
end
else begin
almost_empty_d0 <= almost_empty;
almost_empty_d1 <= almost_empty_d0;
end
end

//像fifo写数据(上升沿写数据的哈,所以没有复位的下降沿)
always@(posedge clk)begin
if(!rst_n)begin
state <= 2’d0;
fifo_wr_en<=1’b0;
fifo_wr_data<=32’d0;
dly_cnt<=4’d0 ;
end
else begin
case(state)
2’d0:begin
if(almost_empty_d1)begin
state<=2’d1;
end
else
state <= state;
end
2’d1:begin
if(dly_cnt == 4’d10)begin
dly_cnt <= 4’d0;
state <= 2’d2;
fifo_wr_en<=1’b1;
end
else
dly_cnt <=dly_cnt ;
end
2’d2:begin
if(almost_empty)begin
state<=2’d0;//回到1状态
fifo_wr_en<=1’b0;
fifo_wr_data<=32’d0;
end
else begin
fifo_wr_en <=1’b1;
fifo_wr_data<=fifo_wr_data+1’b1;
end
end
default:state<=2’d0;
endcase
end
end
endmodule

3) 读数据模块如下:(与写模块很相似)
module fifo_rd(
input clk ,
input rst_n ,
output reg fifo_rd_en ,
input almost_empty ,
input almost_full ,
input [7:0] fifo_rd_data
);

reg almost_full_d0;
reg almost_full_d1;
reg [3:0] dly_cnt;
reg [1:0] state;
always@(posedge clk)begin
if(!rst_n)begin
almost_full_d0<=1’b0;
almost_full_d1<=1’b0;
end
else begin
almost_full_d0 <= almost_full ;
almost_full_d1 <= almost_full_d0 ;
end
end

always@(posedge clk)begin
if(!rst_n)begin
fifo_rd_en<=1’d0;
state <=2’d0;
dly_cnt<=4’d0;
end
else begin
case(state)
2’d0:begin
if(almost_full_d1)
state<=2’d1;
else
state <= state;
end
2’d1:begin
if(dly_cnt==4’d10)begin
dly_cnt<=4’d0;
state<=2’d2;
end
else
dly_cnt<=dly_cnt;
end
2’d2:begin
if(almost_empty)begin
fifo_rd_en <= 1’b0;
state <= 2’d0;
end
else
fifo_rd_en<=1’b1;
end
default:state<=2’d0;
endcase
end
end
endmodule

至此整个FIFO的大致讲解到此结束,如果大家有什么问题可以一起探讨哦,并且一起学习FPGA,后面也会持续更新一些FPGA相关知识

  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值