Vivado fifo IP 完整例程(包括testbench)

38 篇文章 5 订阅
34 篇文章 9 订阅
本文详细介绍了如何使用Verilog实现异步FIFO,包括完整的例程和仿真分析。通过实例展示了FIFO的读写地址生成、空满标志检测,并提供了独立时钟的Block RAM实现。此外,还提供了自编与调用Xilinx IP核的FIFO测试平台,分析了不同模式下的FIFO行为。
摘要由CSDN通过智能技术生成

网上尽管有各种介绍fifo的文章,但大部分没有一个完整的例程来练习,这里给出能够完整演示的fifo例程和仿真分析。工程文件虽然部分基于xilinx的官方例程,但官方例程没有testbench,这部分是自己编写的,并对不同的配置进行了分析,完整的工程文件见
如果没有分数下载,认真看本篇,也能做出来。

第一部分参考以下文章,表示感谢!
调试成功的简单异步FIFO–verilog实现+testbench-布布扣-bubuko.com http://www.bubuko.com/infodetail-2720594.html

实验一 自编fifo主程序

module Asyn_FIFO
#(
     parameter WIDTH = 8,
     parameter DEPTH = 4
 )
(
     input  clk_wr,
     input  clk_rd,
     input  rst_n_rd,
     input  rst_n_wr,
     input  wr_en,
     input  rd_en,
     input  [WIDTH-1:0] data_wr,
     output [WIDTH-1:0] data_rd,
     output reg rd_empty,
     output reg wr_full
);
 
     //defination
     reg  [WIDTH-1 : 0] mem [0 : (1<<DEPTH)-1];        //2^DEPTH numbers
     reg  [DEPTH   : 0] wp, rp;
     reg  [DEPTH   : 0] wr1_rp, wr2_rp, rd1_wp, rd2_wp;
     reg  [DEPTH   : 0] wbin, rbin;
 
 
     wire [DEPTH-1 : 0] waddr, raddr;
     wire [DEPTH   : 0] wbin_next, rbin_next;        //bincode
     wire [DEPTH   : 0] wgray_next, rgray_next;        //graycode
     
     wire rd_empty_val, wr_full_val;
     
     //output
     assign data_rd = mem[raddr];
 
     //input
     always@(posedge clk_wr)
         if(wr_en && !wr_full)
            mem[waddr] <= data_wr;
 
 /*----------generate waddr and raddr-------------------------*/
     //gen raddr and read gray code
     always@(posedge clk_rd or negedge rst_n_rd)
         if(!rst_n_rd)
            {rbin, rp} <= 0;
         else
            {rbin, rp} <= {rbin_next, rgray_next};
 
     assign raddr = rbin[DEPTH-1 : 0];
     assign rbin_next = rbin + (rd_en & ~rd_empty);
     assign rgray_next = rbin_next ^ (rbin_next >> 1);
 
     //gen waddr and write gray code
     always@(posedge clk_wr or negedge rst_n_wr)
         if(!rst_n_wr)
             {wbin, wp} <= 0;
         else
             {wbin, wp} <= {wbin_next, wgray_next};
 
     assign waddr = wbin[DEPTH-1 : 0];
     assign wbin_next = wbin + (wr_en & ~wr_full);
     assign wgray_next = wbin_next ^ (wbin_next >> 1);
 
 /*---------------synchro rp and wp--------------------------*/
     //synchro rp
     always@(posedge clk_wr or negedge rst_n_wr)
         if(!rst_n_wr)
             {wr2_rp, wr1_rp} <= 0;
         else
             {wr2_rp, wr1_rp} <= {wr1_rp, rp}; //delay two clock
 
     //synchro wp
     always@(posedge clk_rd or negedge rst_n_rd)
         if(!rst_n_rd)
             {rd2_wp, rd1_wp} <= 0;
         else
             {rd2_wp, rd1_wp} <= {rd1_wp, wp};
 
 /*---------------empty and full flags--------------------------*/
     //gen rd_empty
     assign rd_empty_val = (rd2_wp == rgray_next);
     always@(posedge clk_rd or negedge rst_n_rd)
         if(!rst_n_rd)
             rd_empty <= 1'b1;
         else
             rd_empty <= rd_empty_val;
 
     //gen wr_full, two high bit do not equal
     assign wr_full_val = ({~wr2_rp[DEPTH : DEPTH-1], wr2_rp[DEPTH-2 : 0]} == wgray_next);
     always@(posedge clk_wr or negedge rst_n_wr)
         if(!rst_n_wr)
             wr_full <= 1'b0;
         else
             wr_full <= wr_full_val;
 
endmodule

tb程序

module Asyn_FIFO_tb;
 
     parameter WIDTH = 8;
 
     reg clk_wr;
     reg clk_rd;
     reg rst_n_rd;
     reg rst_n_wr;
 
     reg  [WIDTH-1:0] data_wr;
     reg  wr_en;
     wire wr_full;
 
     wire [WIDTH-1:0] data_rd;
     reg  rd_en;
     wire rd_empty;
 
 
     Asyn_FIFO fifo_inst(
     .clk_wr(clk_wr), 
     .rst_n_rd(rst_n_rd),
     .rst_n_wr(rst_n_wr),
     .wr_en(wr_en), 
     .data_wr(data_wr), 
     .clk_rd(clk_rd), 
     .rd_en(rd_en), 
     .data_rd(data_rd), 
     .rd_empty(rd_empty), 
     .wr_full(wr_full)
     );
     
     initial begin
         rst_n_rd = 0;
         rst_n_wr = 0;
         clk_wr = 0;
         clk_rd = 0;
         wr_en = 0;
         rd_en = 0;
         
         #20
         rst_n_rd = 1;
         rst_n_wr = 1;
         
         #80
         wr_en = 1;
         rd_en = 0;
         
         #335
         wr_en = 0;
         rd_en = 1;
     end
 
     always #10 clk_wr = ~clk_wr;
     always #20 clk_rd = ~clk_rd;
     
 /*     always @(posedge clk_rd)
         rd_en <= ($random) % 2;
 
     always @(posedge clk_wr)
         wr_en <= ($random) % 2; */
     
     always @(posedge clk_wr)
         data_wr <= ($random) % 256;
     
endmodule

将simulate.runtime时间改为1500ns
在这里插入图片描述

在这里插入图片描述

实验二 调用已IP库fifo, 编写testbench, 参考xilinx下面的官方例程,但自己编写testbench.

从地址下载
https://www.xilinx.com/support/documentation/sw_manuals/xilinx2018_3/ug939-design-files.zip,解压后用vivado打开lab_1实验
在这里插入图片描述
从Flow Navigator, 选择IP Catalog,输入fifo
在这里插入图片描述
在这里插入图片描述

双击FIFO下面的选项
在这里插入图片描述

在这里插入图片描述
Component Name输入char_fifo, Fifo Implementation选Independent Clocks Block RAM.
在这里插入图片描述
注意这里选的是
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
保持Leave Out of context per IP选择, 双击Generate button.
在这里插入图片描述
至此生成fifo IP.

下面制作testbench,

在这里插入图片描述
在这里插入图片描述

拷贝第57至63行到testbench tb_fifo.v例化

char_fifo 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
.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
);

从图上可以看到full信号拉低需要在复位信号410ns以后,重新修改testbench
在这里插入图片描述

`timescale 1ns/1ps


module tb_fifo1;

//***************************************************************************
// Parameter definitions
//***************************************************************************

  parameter         WIDTH        = 8;
  parameter         DEPTH        = 16;

  //inputs 
  reg rst;
  reg wr_clk;
  reg rd_clk;
  reg [7:0] din;
  reg wr_en;
  reg rd_en;

  //outputs 
  wire [7:0] dout;
  wire full;
  wire empty;
  wire [3:0] rd_data_count;
  wire [3:0] wr_data_count; 

  // Instantiate the Unit 
 
char_fifo 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
  .empty(empty),                  // output wire empty
  .rd_data_count(rd_data_count),  // output wire [3 : 0] rd_data_count
  .wr_data_count(wr_data_count)  // output wire [3 : 0] wr_data_count
);

  always #10 wr_clk = ~wr_clk;                
  always #20 rd_clk = ~rd_clk;

  initial begin
      // Initialize Inputs 
      wr_clk = 0;                
      rd_clk = 0;
      rst = 1;
      din = 1'b1;
      wr_en = 0;
      rd_en = 0;

      // Wait 100 ns for global reset to finish 
      #100
      rst = 0;
      #500; 

	  repeat (18) begin 
		wr_en = 1;
		#20;
		wr_en = 0;
		#20;
		din = din + 1'b1;
      end 
	  
	  #290
	  repeat (18) begin 
		rd_en = 1;
		#40;
		rd_en = 0;
		#40;
      end	 
 
  end

endmodule

选Standard FIFO时,有效读写深度是15
写得时候,din是输入,所以不与rd_clk时钟对齐,读的时候是时钟打得出去,所以dout与时钟rd_clk对齐。
在这里插入图片描述
在这里插入图片描述

选First Word First Through, 有效深度度是17

即使没有使能,只要有读时钟,dout就会取第一个数据,第一个读使能和读时钟上升沿,dout就会取第二个数。
在这里插入图片描述
设计深度16,实际是17,上图与下图完全相符,达到深度17时full跳起,
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
注意下图,尽管没有使能rd_en, 但由于是First Word First Through模式,在empty降低后,仍将第一们数据推向输出总线,这样写的数量就减少了1,出现长7的情况。
在这里插入图片描述
2021. 5. 6 输入第一 个数据后的六个时钟周期,empty变为0,同时把第一个数据推向dout, 写计数器在第二个写时钟时将写数据计数器加1,与真实写入数据的时钟差一个时钟周期。读写计数并不保持严格的时间周期,可能错两三个时钟周期才计数
在这里插入图片描述
读取第17个数据后的下一个读时钟上升沿empty信号升起。
在这里插入图片描述

实验三 专门处理IP核流程

lab2 IP manager
在这里插入图片描述

在这里插入图片描述
以下过程类似lab1
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Component Name名字改为clk_core,同时改变下面的配置
• Primary Clock Input Frequency: 200
• Source: Differential clock capable pin
在这里插入图片描述

Port Name设置如下
• clk_out1: clk_rx, 200
• clk_out2: clk_tx, 166.667
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值