FIFO复习总结
一.具体思路
首先介绍一下FIFO,于我而言,FIFO的作用主要有两个,一个是用于数据的缓存,另一个则是用于跨时钟域的数据传输,比如我要做一个摄像头的实验,摄像头采集到的数据我们要传给DDR3存储器,再从DDR3存储器读出输出到LCD屏幕上进行显示,那么摄像头的时钟频率和DDR3读写的频率完全是天差地别,如果这时候我们将数据塞进去,就可能会造成传非所收的状态,这个时候就需要FIFO来进行一个调整平衡。
那么FIFO介绍完了,重点还是要考虑如何去理解和完成这一实验。
首先我们要考虑的事情是要将这一实验以几个部分,模块来完成。不必多说,首先最必不可少的也就是FIFO IP核部分,由它来进行具体的、细节的数据操作,除此之外,我们打算再设置一个FIFO的读模块(fifo_rd)和写模块(fifo_wr),这两个模块来进行FIFO的读写设定,最后我们再用一个顶层模块(ip_fifo)来将读模块、写模块和FIFO IP核装进去,这就是大致思路。那么接下来我们一部分一部分的粘贴代码进行解释分析(本部分代码采用正点原子例程代码)
FIFO写模块(fifo_wr):
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
);
首先看端口部分,系统时钟和复位不多赘述,那么我们先看到的是almost_empty和almost_full两个端口,即将空和将满端口,由于FIFO秉持着“不读空,不写满”的原则,因此我们在空、满信号的前一拍提前设置了两个信号,就是将空和将满,这样可以有效的避免数据的溢出和丢失。
其次则是输出的使能和数据,大家可以这样想象,作为写FIFO,我们需要注入需要写入的数据,再输出需要写入的数据,但是由于本次实验的写数据是我们自己造的,因此我们不需要输入数据,只有输出的8位位宽的数据。至于使能则更不难想象,是作为一个开关式的存在控制着读写的操作。
reg almost_empty_d0;
reg almost_empty_syn;
reg [3:0] dly_cnt;
reg [1:0] state;
almost_empty_d0和almost_empty_syn则是almost_empty分别延迟一拍和两拍后的信号,那么不难理解,almost_empty_d0 就相当于empty信号,而almost_empty_syn则相当于比空信号晚一拍,即那时候已经是空的了,没有多余的数据存在了。
接着设置了延迟计数器,用于读写切换时的延迟作用,延迟十拍。
state则是用于状态的转移,简单来说,不同状态,不同操作。
always@(posedge clk)begin
if(!rst_n)begin
almost_empty_d0 <= 1'b0;
almost_empty_syn <= 1'b0;
end
else begin
almost_empty_d0 <= almost_empty;
almost_empty_syn <= almost_empty_d0;
end
end
这一部分进行了打拍的处理。
always@(posedge clk)begin
if(!rst_n)begin
fifo_wr_en <= 1'b0;
fifo_wr_data <= 8'd0;
state <= 2'd0;
dly_cnt <= 4'd0;
end
else begin
case(state)
2'd0:begin
if(almost_empty_syn)begin