【FPGA】 Vivado FIFO IP核使用教程

目录

一、FIFO简介

二、FIFO的应用

三、Vivado FIFO创建

四、FIFO IP核实例化

五、对实例化顶层文件仿真

一、FIFO简介

       FIFO 的英文全称是 First In First Out ,即先进先出 FPGA 使用的 FIFO 一般指的是对数据的存储具有先进先出特性的一个缓存器,常被用于数据的缓存或者高速异步数据的交互,也即所谓的跨时钟域信号传递。它与 FPGA 内部的 RAM ROM 的区别是没有外部读写地址线,采取顺序写入数据,顺序读出数据的方式,使用起来简单方便,由此带来的缺点就是不能像 RAM 和 ROM 那样可以由地址线决定读取或写入某个指定的地址。        FIFO 从输入时钟的角度来分,有两种类型: 单时钟 FIFO和双时钟 FIFO;单时钟 FIFO 具有一个独立的时钟端口 clock,因此,所有的输入输出信号都同步于 clock 信号。双时钟 FIFO 结构中,写端口 和读端口分别有独立的时钟,所有与写相关的信号都是同步于写时钟 wr_clk,所有与读相关 的信号都是同步于读时钟 rd_clk。

二、FIFO的应用

1. 单时钟 FIFO 常用于同步时钟的数据缓存; 2. 双时钟 FIFO 常用于跨时钟域的数据信号的传递,例如时钟域 A 下的数据 data1 传递 给异步时钟域 B ,当 data1 为连续变化信号时,如果直接传递给时钟域 B 则可能会 导致收到的数据不是发送的数据的情况,即在采集过程中会出现包括亚稳态(数据采样失真)问题在内的一系列问题,使用双时钟 FIFO 能够将不同时钟域中的数据同步到所需的时钟域中

三、Vivado FIFO创建

1、新建工程后进入以下界面,点击IP Catalog,在右侧界面搜索fifo,找到FIFO Cenerator打开。

2、在FIFO IP核配置界面,Component Name中可以更改命名,Fifo Impiementation中可以选择单时钟(Common Clock Block RAM)和双时钟(Independent Clocks Block RAM),这里我选择双时钟。

 

3、模式选择有标准模式和FWFT模式,标准模式中读取的数据滞后读信号一个时钟周期;FWFT模式中读信号有效时,读取的数据也立即有效。这里我选择标准模式,设置读写数据位宽为16,数据深度为512,根据需要自行设置。

 4、读写计数界面,Write Data Count表示FIFO已经写入多少数据,Read Data Count表示FIFO中有多少数据可以读。点击“OK”,完成异步FIFO 配置。

四、FIFO IP核实例化

1、Sources里的fifo_ip.veo文件中是IP的例化模板。我们只需要将文件中内容复制粘贴到我们verilog程序中,对IP进行实例化。。

 2、我们在创建一个顶层设计文件来实例化这个FIFO IP, 编写pll_test.v代码如下。

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/03/31 14:59:11
// Design Name: 
// Module Name: fifo_test
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//module fifo_test(input wr_clk ,//写 FIFO 时钟input rd_clk ,//读 FIFO 时钟input rst_n ,//复位input [7:0] wr_din ,//写入 FIFO 的数据input wr_en ,//写使能input rd_en ,//读使能output reg [7:0] rd_dout,//从 FIFO 读出的数据output reg rd_out_vld    //从 FIFO 读出的数据有效指示信号);//信号定义wire [7:0] wr_data ;wire [7:0] q ;wire wr_req ;wire rd_req ;wire rd_empty ;wire wr_full ;wire [7:0] wrusedw ;wire [7:0] rdusedw ;//FIFO 例化fifo_ip your_instance_name (.wr_clk       (wr_clk     ),   // input wire wr_clk.rd_clk       (rd_clk     ),   // input wire rd_clk.din          (wr_data    ),   // input wire [15 : 0] din.wr_en        (wr_req     ),   // input wire wr_en.rd_en        (rd_req     ),   // input wire rd_en.dout         (q          ),   // output wire [15 : 0] dout.full         (wr_full    ),   // output wire full.empty        (rd_empty   ),   // output wire empty.rd_data_count(rdusedw    ),   // output wire [8 : 0] rd_data_count.wr_data_count(wrusedw    )    // output wire [8 : 0] wr_data_count
);assign wr_data = wr_din;//输入的数据assign wr_req = (wr_full  == 1'b0)?wr_en:1'b0;//非满才写assign rd_req = (rd_empty == 1'b0)?rd_en:1'b0;//非空才读always @(posedge rd_clk or negedge rst_n)beginif(!rst_n)beginrd_dout <= 0;endelse beginrd_dout <= q;endendalways @(posedge rd_clk or negedge rst_n)beginif(!rst_n)beginrd_out_vld <= 1'b0;endelse beginrd_out_vld <= rd_req;endendendmodule

五、对实例化顶层文件仿真

1、我们在创建一个仿真激励文件来仿真这个fifo_test顶层文件, 编写fifo_test_tb.v代码如下。

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2023/03/31 15:11:44
// Design Name: 
// Module Name: fifo_test_tb
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//module fifo_test_tb();
//时钟和复位reg     wr_clk      ;reg     rd_clk      ;reg     rst_n       ;
//输入信号reg [7:0]    wr_din;reg          wr_en ;reg          rd_en ;
//输出信号wire        rd_out_vld  ;wire [7:0]  rd_dout     ;//参数定义parameter   WR_CYCLE    = 20;//写时钟周期,单位为 ns,parameter   RD_CYCLE    = 30;//读时钟周期,单位为 ns,parameter    RST_TIME   = 3 ;//复位时间,此时表示复位 3 个时钟周期的时间。
//待测试的模块例化fifo_test u_fifo_test(.wr_clk         (wr_clk  ),//时钟.rd_clk         (rd_clk  ),.rst_n          (rst_n   ),//复位.wr_din         (wr_din  ),//写入 FIFO 的数据.wr_en          (wr_en   ),//写使能.rd_en          (rd_en   ),//读使能
//输出信号定义.rd_dout        (rd_dout ),//从 FIFO 读出的数据.rd_out_vld     (rd_out_vld )//从 FIFO 读出的数据有效指示信号
);integer i = 0;
//生成本地时钟 50Minitial wr_clk = 0;always #(WR_CYCLE/2) wr_clk=~wr_clk;initial rd_clk = 0;always #(RD_CYCLE/2) rd_clk=~rd_clk;//产生复位信号initial beginrst_n = 1;#2;rst_n = 0;#(WR_CYCLE*RST_TIME);rst_n = 1;end//输入信号赋值initial begin#1;//赋初值wr_din = 0;wr_en = 0;#(100*WR_CYCLE);//开始赋值for(i=0;i<500;i=i+1)beginwr_din = {$random};wr_en  = {$random};#(1*WR_CYCLE);end#(100*WR_CYCLE);endinitial begin#1;//赋初值rd_en = 0;#(120*RD_CYCLE);//开始赋值for(i=0;i<500;i=i+1)beginrd_en = {$random};#(1*RD_CYCLE);end#(100*RD_CYCLE);$stop;endendmodule

2、仿真结果如下,输出rd_dout[7:0]的结果和输入wr_din[7:0]一致。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部