FPGA的FIFO部分的知识点
看的小梅哥的新视频,FIFO这边讲的不太清楚,换正点原子的fifo听一下。
后面的以太网和HDMI有空也看一下正点原子的,主要是想快速看zynq的知识,而且现在学的很多都是模仿抄代码,真正自己来还是得工程中实际应用的时候才会使用学习
FIFO,先入先出,像队列。常用于数据的缓存,因为数据的读写带宽,也就是读写速度不同步,可以通过异步FIFO解决
同步FIFO就是读写同时钟,异步FIFO就是时钟独立,跨时钟处理。
FIFO计算公式(计算在最恶劣的情况下,在突发读写这段时间内,有多少数据没被读取)
FIFO的最小深度D可以通过一下公式计算:
a.读比写快
D=BW-BR=BW(1-FR/FW)
其中BW和BR分别为写入和读取的burst长度,FW和FR分别为写时钟和读时钟的频率。
b.读写同速或者读比写快
fifo只起跨时钟域传输数据的作用,深度设置成最小即可。
举个例子:
AD采样率为50MHZ,fpga的读取速度为40MHZ,需要5万个采样数据完整的送入FPGA,在AD和FPGA之间的FIFO缓存的最大深度?
突发读写数据量:50000个
写数据时钟: 50MHZ
读数据时钟: 40MHZ
FIFO深度最小为:50000(1-40/50)=10000
不同位宽的异步FIFO深度计算,一般输入位宽和输出的位宽是整数倍关系。
这边FIFO的结构,黑色的都是必要的,蓝色的可选(读时钟在同步FIFO里面就没有了,可选),灰色的是可选( )
这是时钟IP核生成的端口。
//----------- Begin Cut here for INSTANTIATION Template ---// INST_TAG
fifo_test your_instance_name (
.rst(rst), // input wire rst
.wr_clk(wr_clk), // input wire wr_clk
.rd_clk(rd_clk), // input wire rd_clk
.din(din), // input wire [7 : 0] din
.wr_en(wr_en), // input wire wr_en
.rd_en(rd_en), // input wire rd_en
.dout(dout), // output wire [7 : 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
.wr_rst_busy(wr_rst_busy), // output wire wr_rst_busy
.rd_rst_busy(rd_rst_busy) // output wire rd_rst_busy
);
从原子哥那里漂的顶层模块和例化的框图
任务是,先写满,再读出来
那么其中除了根据满和空的状态,控制读写信号使能。由时钟IP产生两个时钟分别给读写时钟,异步读写FIFO
fifo_wr
module fifo_write(
wr_clk,
reset_n,
//FIFO
empty, //输入空信号!!!这是读时钟域的信号,异步信号需要打拍。
almost_full, //将满信号
wr_rst_busy, //写复位忙信号
fifo_wr_en,
fifo_wr_data
);
input wr_clk;
input reset_n;
input empty;
input almost_full;
input wr_rst_busy;
output reg fifo_wr_en;
output reg [7:0] fifo_wr_data;
reg empty_d0;
reg empty_d1;
//打两拍,延时2周期
//因为实际上的空信号是读时序的时候FIFO才能输出来的,所以这边跟写时序是异步信号
always @(posedge wr_clk or negedge reset_n)
if(!reset_n) begin
empty_d0 <= 0;
empty_d1 <= 0;
end
else begin
empty_d0 <= empty;
empty_d1 <= empty_d0;
end
always @(posedge wr_clk or negedge reset_n)
if(!reset_n)
fifo_wr_en <= 0;
else if(!wr_rst_busy) begin
if(empty_d1)
fifo_wr_en <= 1'b1;
else if(almost_full)
fifo_wr_en <= 1'b0;
end
//对fifo_wr_data赋值 0~254
always @(posedge wr_clk or negedge reset_n)
if(!reset_n)
fifo_wr_data <= 0;
else if(fifo_wr_en && fifo_wr_data < 8'd254)
fifo_wr_data <= fifo_wr_data + 8'd1;
else
fifo_wr_data <= 0;
endmodule
fifo_rd
module fifo_read(
rd_clk,
reset_n,
fifo_rd_data,
almost_empty,
full,
rd_rst_busy,
fifo_rd_en
);
input rd_clk;
input reset_n;
input [7:0] fifo_rd_data;
input almost_empty;
input full;
input rd_rst_busy;
output reg fifo_rd_en;
reg full_d0;
reg full_d1;
always @(posedge rd_clk or negedge reset_n)
if(!reset_n) begin
full_d0 <= 0;
full_d1 <= 0;
end
else begin
full_d0 <= full;
full_d1 <= full_d0;
end
always @(posedge rd_clk or negedge reset_n)
if(!reset_n)
fifo_rd_en <= 1'b0;
else if(!rd_rst_busy) begin
if(full_d1)
fifo_rd_en <= 1'b1;
else if(almost_empty)
fifo_rd_en <= 1'b0;
end
endmodule
ip_fifo顶层例化
module ip_fifo(
clk,
reset_n
);
input clk;
input reset_n;
wire clk_50m;
wire clk_100m;
wire locked;
wire rst_n;
assign rst_n = reset_n & locked;
wire empty;
wire almost_full ;
wire wr_rst_busy ;
wire fifo_wr_en ;
wire [7:0] fifo_wr_data ;
wire [7:0] fifo_rd_data ;
wire almost_empty ;
wire full ;
wire rd_rst_busy ;
wire fifo_rd_en ;
wire [7:0] rd_data_count;
wire [7:0] wr_data_count;
clk_wiz_0 instance_name
(
// Clock out ports
.clk_out1(clk_50m), // output clk_out1
.clk_out2(clk_100m), // output clk_out2
// Status and control signals
.locked(locked), // output locked
// Clock in ports
.clk_in1(clk)
); // input clk_in1
fifo_write fifo_wirte_inst(
.wr_clk(clk_50m),
.reset_n(rst_n),
//FIFO
.empty(empty), //输入
.almost_full(almost_full),
.wr_rst_busy(wr_rst_busy),
.fifo_wr_en(fifo_wr_en),
.fifo_wr_data(fifo_wr_data)
);
fifo_read fifo_read_inst(
.rd_clk(clk_100m),
.reset_n(rst_n),
.fifo_rd_data(fifo_rd_data),
.almost_empty(almost_empty),
.full(full),
.rd_rst_busy(rd_rst_busy),
.fifo_rd_en(fifo_rd_en)
);
//FIFO的复位高电平有效
fifo_test your_instance_name (
.rst(~rst_n), // input wire rst
.wr_clk(clk_50m), // input wire wr_clk
.rd_clk(clk_100m), // input wire rd_clk
.din(fifo_wr_data), // input wire [7 : 0] din
.wr_en(fifo_wr_en), // input wire wr_en
.rd_en(fifo_rd_en), // input wire rd_en
.dout(fifo_rd_data), // output wire [7 : 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
.wr_rst_busy(wr_rst_busy), // output wire wr_rst_busy
.rd_rst_busy(rd_rst_busy) // output wire rd_rst_busy
);
endmodule
FIFO的高电平复位,例化的时候取反。
本文来自博客园,作者:祈愿树下,转载请注明原文链接:https://www.cnblogs.com/cjl520/p/18070725