Xilinx FIFO IP核的例化和使用(含代码实例)

        使用FPGA进行数据传输处理时,数据缓存是很关键的部分。FIFO作为一种简单的缓存方案,在FPGA开发中具有广泛的应用。

        Xilinx为我们提供的FIFO IP核是一种先进先出(FIFO)内存队列,例化后,开发人员可自定义宽度、深度、状态标志、内存类型和写入/读取端口纵横比。FIFO利用顺序存储和检索的工作方式,可以帮助开发人员实现少量数据缓存、跨时钟处理、位宽转换等功能。

本文分为三部分

  1. IP核例化
  2. IP核调用
  3. IP核端口理解和时序关系
  4. IP核控制(提供实例)

一、IP核例化

step1: 点击vivado左侧列表中的 “IP catalog” 进入IP目录,点击搜索框输入“fifo”,选择“FIFO Generator”。

Xilinx FIFO IP核的例化和使用(含代码实例)_第1张图片

 step 2:  首先对fifo命名,可根据深度和位宽作为命名方式。在“Basic”界面中选择例化的fifo类型,若FIFO外接AXI接口,可在接口选择时选择AXI相关,由于作者无相关需求,且为了使用的普遍性,本文故只介绍常用的Native功能。

在“ Fifo Implementation” 中选择FIFO类型,若FIFO使用同频时钟,则选择common相关;若使用不同时钟,则选择independent相关。

其中“Block RAM”称为块RAM,“Distributed RAM”为分布式RAM,其区别在于Block ram由一定数量固定大小的存储块构成的,使用BRAM资源不占用额外的逻辑资源,并且速度快。分布式RAM利用查找表LUT作为存储器, 既可以实现芯片内部存储,又能提高资源利用率。实现大规模的存储器会占用大量的LUT,可用来实现逻辑的查找表就会减少。故在需要小规模存储器时,使用这种分布式RAM。根据实验跨时钟的需要, 本实验选择"Independent Clocks Block RAM ".

Xilinx FIFO IP核的例化和使用(含代码实例)_第2张图片

 Step 3:  "Native ports" 界面配置, 可在此界面进行读模式选择, 当选择 "Standard FIFO"标准读取操作在读请求的下一个时钟周期输出数据。若选择"First Word Fall Through" ,则在读请求的本时钟周期输出数据。

" write width" 表示写入数据位宽 ;  "write  Depth" 表示写入数据深度, 即FIFO中能写入多少个对应位宽的数据; "Read Width" 表示读数据位宽, " Read Depth" 根据前三个参数计算得出,无需自行填入 。其他参数选择默认配置即可。

Xilinx FIFO IP核的例化和使用(含代码实例)_第3张图片

  Step 4:   若无其他开发要求, "Status Flags"  "Data Counts" 选择默认配置即可,点击"OK", 之后一直保持默认操作点击"OK", 直到弹出"Generate ouput product" , 继续点击"OK" 即可完成FIFO IP核的例化操作。

Xilinx FIFO IP核的例化和使用(含代码实例)_第4张图片

Xilinx FIFO IP核的例化和使用(含代码实例)_第5张图片

Xilinx FIFO IP核的例化和使用(含代码实例)_第6张图片

Xilinx FIFO IP核的例化和使用(含代码实例)_第7张图片

 二、IP核调用

        找到到工程路径下,找到IP的保存路径, 打开 .veo文件, 将文档中提供的例化范例直接拷贝到工程中即可完成 IP核的调用过程。

Xilinx FIFO IP核的例化和使用(含代码实例)_第8张图片

三、IP核端口理解

        下图是官方数据手册中提供的Native型接口的FIFO端口连接图,图中上班部分是基础例化后形成的端口,下半部分为可选功能,本文只做基数部分的叙述,如有其他功能需求,请阅读数据手册继续理解,各端口解释如下表。

Xilinx FIFO IP核的例化和使用(含代码实例)_第9张图片

rst input 复位信号:高有效
写端口   wr_clk input 写入时钟:写入域上的所有信号都与该时钟同步
din[n:0] input 写入数据
wr_en input 写使能:当FIFO未满且读数据有效时信号拉高
    full output FIFO写满标志:当其拉高时,写使能不再有效
读端口   rd_clk input 读时钟: 读出域上的所有信号都与该时钟同步
dout[m:0] output 读出数据
  rd_en input 读使能:当FIFO非空且有数据读出需求时拉高
  empty output FIFO读空标志:当其拉高时,读使能不再有效
valid output 可选信号,标志该IP核入/输出数据有效
ready output 可选信号,当FIFO满或空时拉低

        FIFO在使用时,据读写逻辑输出的wr_en和rd_en信号来确定通道上的有效数据或控制信息何时可用。同时可根据需要,在配置IP核时选择性使用握手信号“valid”和“ready”,Valid_in/out拉高时表示有效数据在该时钟周期内可取或可存;Ready_in/out信号表示何时FIFO可以接收或发送数据。

Xilinx FIFO IP核的例化和使用(含代码实例)_第10张图片

四、IP核使用

      Independent Clocks Block RAM IP核的简单使用代码和仿真运行结果如下, 需要可自取。文章包含了以下三个文件:

fifo_test_top.v:工程的top,用于例化IP,生成读逻辑;

fifo_data_in.v:用于构造仿真输入数据,生成写逻辑;

fifo_test_tb.v:仿真文件,用于生成时钟和复位。

module fifo_test_top(

input   wire                   clk_a ,   //74.25M
input   wire                   clk_b ,   //148.5M
input   wire                   rst   ,
output  wire   [15:0]          o_data,
output  reg                    o_vld
    );
    
wire  [31:0]   fifo_wdata;
wire           fifo_wvld ;
wire           full      ;
wire           empty     ;  
wire           wr_en     ;
wire           rd_en     ;
wire  [15:0]   fifo_rdata;

fifo_data_in u_fifo_data_in(
.clk(clk_a),
.rst(rst),
.o_data(fifo_wdata),
.o_data_vld(fifo_wvld)
);

assign wr_en = fifo_wvld & (~full) ;
assign rd_en = (~empty) ;

always @(posedge clk_b) begin
    if(rst)
        o_vld <= 1'b0;
    else
        o_vld <= rd_en;
end

assign o_data = fifo_rdata;

fifo_32_4096_16 u_fifo_32_4096_16 (
  .rst(rst),                  // input wire rst
  .wr_clk(clk_a),             // input wire wr_clk
  .rd_clk(clk_b),             // input wire rd_clk
  .din(fifo_wdata),           // input wire [31 : 0] din
  .wr_en(wr_en),              // input wire wr_en
  .rd_en(rd_en),              // input wire rd_en
  .dout(fifo_rdata),          // output wire [15 : 0] dout
  .full(full),                // output wire full
  .empty(empty)               // output wire empty
 // .wr_rst_busy(wr_rst_busy),  // output wire wr_rst_busy
//  .rd_rst_busy(rd_rst_busy)  // output wire rd_rst_busy
);
    

endmodule
module fifo_data_in(

input  wire           clk,
input  wire           rst,
output reg   [31:0]   o_data,
output reg            o_data_vld
    );

reg  [15:0]          data_cnt_l;
wire [15:0]          data_cnt_u;
parameter   VLD_CNT = 16'd1125;

always @(posedge clk) begin
    if(rst)
        data_cnt_l <= 16'd0;
    else if(data_cnt_l == 1125)
        data_cnt_l <= 16'd0;
    else 
        data_cnt_l <= data_cnt_l + 11'd1;
end
assign data_cnt_u = VLD_CNT - data_cnt_l ;

always @(posedge clk) begin
    if(rst)
        o_data  <= 32'd0;
    else if ((data_cnt_l < 1080) && (data_cnt_l >= 0))
        o_data <= {data_cnt_u,data_cnt_l};
    else
        o_data <= 32'd0;
end

always @(posedge clk) begin
    if(rst)
        o_data_vld  <= 32'd0;
    else if ((data_cnt_l < 1080) && (data_cnt_l >= 0))
        o_data_vld <= 1'b1;
    else
        o_data_vld <= 32'd0;
end

endmodule
module fifo_test_tb();

reg                clk_a;   //74.25M
reg                clk_b;   //148.5M
reg                rst;
wire [15:0]       o_data;
wire              o_vld;

parameter   CLK_74_25 = 6.734;
parameter   CLK_148_5 = 3.367;

initial begin   //74.25M
    clk_a = 0;
    forever begin
    # CLK_74_25 clk_a = 0;
    # CLK_74_25 clk_a = 1;
    end
end

initial begin   //148.5
    clk_b = 0;
    forever begin
    # CLK_148_5 clk_b = 0;
    # CLK_148_5 clk_b = 1;
    end
end

initial begin
rst = 1;
#1000 rst = 0;
end

fifo_test_top fifo_test_top_tb(
.clk_a (clk_a),   //74.25M
.clk_b (clk_b),   //148.5M
.rst   (rst) ,
.o_data(o_data),
.o_vld (o_vld)
    );
endmodule

Xilinx FIFO IP核的例化和使用(含代码实例)_第11张图片

         若拷贝了以上程序仍然无法调试成功, 可下载"保姆" 调试包, 包含了以上提到的三个.v文件和例化后的FIFO IP文件夹,以及 FIFO的官方使用手册--pg057-fifo-generator.pdf。

https://download.csdn.net/download/qq_37203760/86762497

说明: "保姆" 调试包中的程序与文章中完全一样,所以还是希望大家能参照文章自主调试,加油!

"保姆" 调试包使用方法:

1. 点击“Add Sources”-"Add or create design sources"将fifo_data_in.v、fifo_test_top.v和fifo_32_4096_16.xci导入已建好的工程中。
2. 点击“Add Sources”-"Add or create simulation sources" 将fifo_test_tb.v导入工程中。
3. 运行simulation

你可能感兴趣的:(FPGA基础学习,fpga开发)