FIFO
2023-12-31 23:28:36
一、简介
????????FIFO(First In, First Out)是一种数据结构和算法原则,最早进入的元素最先被处理或者移除。这种原则通常应用于队列(Queue)的管理,其中新元素被添加到队列的尾部,而从队列中取出元素则是从队列的头部开始。FIFO 常用于处理按照时间顺序到达或产生的数据。
二、分类
(一)同步FIFO(SCFIFO)
- 同步 FIFO 是在时钟信号的控制下进行读写操作的。
- 数据的写入和读取都与系统的时钟信号同步。即读写是同一个时钟
- 在同步 FIFO 中,写入和读取的时机是由时钟信号精确控制的,这有助于避免时序问题。
(二)异步FIFO(DCFIFO)
- 异步 FIFO 不依赖于时钟信号进行数据读写。
- 数据的读取和写入不受系统的时钟信号同步。读写时钟独立
- 异步 FIFO 通常包含更多的控制电路,以确保在异步情况下也能正确地进行数据传输。
? (三)异步混合位宽 FIFO(DCFIFO_MIXED_WIDTHS)
- 异步混合位宽 FIFO 是一种具有不同数据宽度的输入和输出的 FIFO。
- 这种 FIFO 允许异步读写,并且输入和输出端口的数据宽度可以不同。
- 异步混合位宽 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 IP核的使用
(一)参数设置
(二)写FIFO
????????由于是在时序逻辑中对写使能信号进行赋值,因此会延迟一个时钟周期,即在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
(三)读FIFO
? ? ? ? 同理,为防止读空后继续读,加一个读使能中间信号。
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
(二)波形图
写:
读:
###本文参考正点原子视频,如有侵权,请联系删除。
文章来源:https://blog.csdn.net/m0_58427556/article/details/135291069
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!