????????FIFO(First In, First Out)是一种数据结构和算法原则,最早进入的元素最先被处理或者移除。这种原则通常应用于队列(Queue)的管理,其中新元素被添加到队列的尾部,而从队列中取出元素则是从队列的头部开始。FIFO 常用于处理按照时间顺序到达或产生的数据。
? ? ? ? 读信号wrreq和写信号rdreq都是高电平有效。full是满信号,当被拉高后表示FIFO被写满了,此时绝对不能往FIFO中再写入数据。almost_full,当输入的数据量大于设定的数值时,此信号被拉高。empty是空信号,被拉高时表示FIFO已经被读空了,此时绝不能再往外读出数据。almost_empty,当读出的数据量大于设定的数值时,此信号被拉高。usedw用于表示当前FIFO中缓存了多少个数据。
????????使用Quartus II 生成 FIFO IP 核,并实现当 FIFO 为空时,开始向 FIFO 中写入数据,直到 FIFO 写满为止;当 FIFO 写满后则开始从 FIFO中读出数据,直到 FIFO 读空为止,以此类推,循环往复。
????????其中使用PLL IP核来产生两个不同的时钟,编写读写FIFO模块,然后使用FIFO IP核来连接。
????????由于是在时序逻辑中对写使能信号进行赋值,因此会延迟一个时钟周期,即在FIFO写满后的下一个时钟周期,系统才会采集到满信号,因此会多写进一个数据。为避免这种情况,可以使用一个中间写使能信号。
module wr(
input clk ,
input rst_n ,
input wr_empty ,//写空信号
input wr_full ,//写满信号
output reg [7:0] wr_data,
output wr_en //写使能信号
);
reg wr_en_temp;
assign wr_en =wr_en_temp & (~wr_full);
//产生写数据
always @(posedge clk or negedge rst_n)begin
if (!rst_n)
wr_data <= 8'b0;
else if(wr_en)
wr_data <= wr_data +1'b1;
else
wr_data <= wr_data;
end
//写使能信号
always @(posedge clk or negedge rst_n)begin
if (!rst_n)
wr_en_temp <= 1'b0;
else if(wr_empty)
wr_en_temp <= 1'b1;//为空时才往里写信号
else if (wr_full)
wr_en_temp <= 1'b0;//写满后不往里写信号
end
endmodule
? ? ? ? 同理,为防止读空后继续读,加一个读使能中间信号。
module rd(
input clk,
input rst_n,
input rd_empty,
input rd_full,
input [7:0] rd_data,
output rd_en
);
reg rd_en_tmp;
assign rd_en = rd_en_tmp & (~ rd_empty);
always @(posedge clk or negedge rst_n)begin
if (!rst_n)
rd_en_tmp <= 1'b0;
else if (rd_full)
rd_en_tmp <= 1'b1;
else
rd_en_tmp <=1'b0;
end
endmodule
module ip_fifo(
input clk,
input rst_n
);
//连线
wire locked ;
wire clk_50 ;
wire clk_25 ;
wire [7:0]rd_usedw ; //读侧FIFO中的数据量
wire [7:0]wr_usedw ; //写侧FIFO中的数据量
wire wr_empty ;
wire wr_full ;
wire [7:0]wr_data ;
wire wr_en ;
wire rd_empty ;
wire rd_full ;
wire [7:0]rd_data ;
wire rd_en ;
//例化锁相环PLL
ip_pll ip_pll_inst (
.areset ( ~rst_n ),//注意要取反
.inclk0 ( clk ),
.c0 ( clk_50 ),
.c1 ( c1k_25 ),
.locked ( locked)
);
//例化FIFO
async_fifo async_fifo_inst (
.aclr ( ~clk ) ,//注意取反
.data ( wr_data ) ,
.rdclk ( clk_25 ) ,
.rdreq ( rd_en ) ,
.wrclk ( clk_50 ) ,
.wrreq ( wr_en ) ,
.q ( rd_data ) ,
.rdempty ( rd_empty ) ,
.rdfull ( rd_full ) ,
.rdusedw ( rd_usedw ) ,
.wrempty ( wr_empty ) ,
.wrfull ( wr_full ) ,
.wrusedw ( wr_usedw)
);
//例化写模块
wr wr_inst(
.clk (clk_50),
.rst_n (rst_n),
.wr_empty (wrempty),
.wr_full (wr_full),
.wr_data (wr_data),
.wr_en (wr_en),
);
//例化读模块
rd rd_inst(
.clk (c1k_25),
.rst_n (rst_n),
.rd_empty (rd_empty),
.rd_full (rd_full),
.rd_data (rd_data),
.rd_en (rd_en)
);
endmodule
`timescale 1ns/1ns
module ip_fifo_tb() ;
parameter SYS_PERIOD = 20; //定义系统时钟周期
reg clk ;
reg rst_n ;
always #(SYS_PERIOD/2) clk <= ~clk ;
initial begin
clk <= 1'b0 ;
rst_n <= 1'b0 ;
#(SYS_PERIOD+1)
rst_n <= 1'b1 ;
end
//例化ip_pll模块
ip_pll u_ip_pll(
.sys_clk (clk),
.sys_rst_n (rst_n),
);
endmodule
读:
###本文参考正点原子视频,如有侵权,请联系删除。