Xilinx零基础学习FPGA笔记——第四课,FIFO IP核的使用

实验需求:

配置异步FIFO IP核,可以缓存31字节的数据,并仿真

锁相环配置

在FPGA设计中,锁相环(PLL)用于生成不同频率的时钟信号。假设使用Xilinx FPGA,可以通过Vivado中的Clock Wizard IP核来配置PLL,生成50MHz和35MHz的时钟信号。

  1. 打开Vivado,创建一个新的工程。
  2. 在IP Catalog中搜索并添加“Clock Wizard” IP核。
  3. 配置Clock Wizard,设置输入时钟为50MHz,输出时钟为50MHz和35MHz。
  4. 生成IP核并实例化到顶层模块中。

异步FIFO配置

异步FIFO用于在不同时钟域之间传递数据。在Vivado中,可以使用FIFO Generator IP核来配置异步FIFO。

  1. 在IP Catalog中搜索并添加“FIFO Generator” IP核。
  2. 设置FIFO深度为32字节。
  3. 生成IP核并实例化到顶层模块中。

顶层模块设计

在顶层模块中,实例化PLL和FIFO IP核,并连接相关信号。

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2025/05/09 23:10:25
// Design Name: 
// Module Name: Class_Top_fifo
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module Class_Top_dcfifo(
        input               clk_in1,
        input               reset_n,
        input               wr_en,
        input               rd_en,
        input  [7 : 0]      din,
        output [7 : 0]      dout,
        output [31 : 0]     wr_data_gcount,
        output [31 : 0]     rd_data_gcount,
        output              full,
        output              empty,
        output              locked,
        output              clk_wr,
        output              clk_rd
    );
    
   // reg   din_T  ;


    reg  [7 : 0] din_T  ;
    wire clk_out_75MHZ;
    wire clk_out_35MHZ;
    

    wire              wr_rst_busy;
    wire              rd_rst_busy;
    
//wire  wr_en_T;
//wire  rd_en_T;

//assign  wr_en_T=wr_en;
//assign  rd_en_T=rd_en;


    reg              wr_en_T ;
    reg              rd_en_T  ;


  clk_35M_75M_ip u1_clk_35M_75M_ip
   (
    // Clock out ports
    .clk_out1(clk_out_75MHZ),     // output clk_out1
    .clk_out2(clk_out_35MHZ),     // output clk_out2
    // Status and control signals
    .resetn(reset_n), // input resetn
    .locked(locked),       // output locked
   // Clock in ports
    .clk_in1(clk_in1));      // input clk_in1
    
    dcfifo_std8x31_ip u1_dcfifo (
      .rst((!reset_n&locked)),                      // input wire rst
      .wr_clk(clk_wr),                // input wire wr_clk
      .rd_clk(clk_rd),                // input wire rd_clk
      .din(din_T),                      // input wire [7 : 0] din
      .wr_en(wr_en_T),                  // input wire wr_en
      .rd_en(rd_en_T),                  // 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

assign  clk_wr=clk_out_75MHZ;
assign  clk_rd=clk_out_75MHZ;
/下降沿给数据///
always @(negedge clk_wr or negedge reset_n)
begin
    if(!reset_n)
        din_T<=0;
    else
      din_T<=din;
end

/下降沿给使能信号///
always @(negedge clk_rd or negedge reset_n)
begin
    if(!reset_n)
        rd_en_T<=0;
    else
        rd_en_T<=rd_en;
end
/下降沿给使能信号///
always @(negedge clk_wr or negedge reset_n)
begin
    if(!reset_n)
        wr_en_T<=0;
    else
        wr_en_T<=wr_en;
end

 gen_wr_fifo wr_u1(       
       . rst_n((reset_n&locked)),
       . clk_wr(clk_wr),
       . wr_en(wr_en_T),
       . full(full),
       . wr_real_counts(wr_data_gcount)
    );

gen_rd_fifo rd_u1(
        . rst_n((reset_n&locked)),
        . clk_rd(clk_rd),
        .rd_en(rd_en_T),
        . empty(empty),
        . rd_real_counts(rd_data_gcount));

endmodule

仿真测试

编写测试平台(Testbench)对设计进行仿真测试,验证FIFO在不同时钟域下的读写操作。

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2025/05/09 23:30:45
// Design Name: 
// Module Name: Test_dcfifo_tb
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module Test_dcfifo_tb( );
        parameter TEST_DATA_SIZE = 1024;    // 测试数据量
        reg clk_50MHz_in;
        reg rst_n;
        reg wr_en;
        reg rd_en;
        
        wire locked;
        wire full;
        wire empty;

       
        reg  [7:0]   test_data [0:TEST_DATA_SIZE-1]; // 测试数据池
       wire clk_wr;
        wire clk_rd;
        wire [31:0]   wr_counts;//已经写入的总个数
        wire [7:0]    gdin;
        wire [31:0]   rd_counts;//读出的总个数
        wire [7:0]    data_out;//读取的实时数据
        reg  [7:0]    expected_data[0:TEST_DATA_SIZE];//读取的数据
        integer i=0;
        reg  [7:0] userData;

        Class_Top_dcfifo  U1(
            .clk_in1(clk_50MHz_in),
            .reset_n(rst_n),
            .wr_en(wr_en),
            .rd_en(rd_en),
            .din(gdin),
            .dout(data_out),
            .wr_data_gcount(wr_counts),
            .rd_data_gcount(rd_counts),
            .full(full),
            .empty(empty),
            .locked(locked),
            .clk_wr(clk_wr),
            .clk_rd(clk_rd));
                
        // 测试过程
        initial begin
            clk_50MHz_in=0;
            rst_n = 0;  // 复位
            wr_en = 0;
            rd_en = 0;
            // 生成随机数据
            generate_test_data;
            #300 ;
            userData=8'b0;
            rst_n = 1;
            @(posedge locked);
              #30;
写满设计
        for(i=0;i<35;i=i+1)
        begin
     
            @(negedge clk_wr);
                userData= test_data[i];
                wr_en = 1;
         end
          #100 ;
          @(posedge clk_wr);
            wr_en = 0;
          #200 ;
读空设计  
        for(i=0;i<35;i=i+1)begin
            @(negedge clk_rd);
            rd_en = 1;
             #10;
        end
        #200 ;
            @(posedge clk_rd);
            #10;
            rd_en = 0;    
        #200 ;
        
        
        $stop ;  
         end   
        
        
assign  gdin= userData;

//always @(posedge clk_rd)
// begin
//    if(data_out!= expected_data) begin      // 同步值一致性检查
//    $display("Time=%0t: 第%d个数据data_out读取结果为:0x%h,与实际写入值 expected_data:0x%h不匹配", $time, rd_counts,data_out,expected_data);
//    end
//end
   // 生成50MHz时钟
always #10 clk_50MHz_in = ~clk_50MHz_in; // 20ns周期,50MHz

task generate_test_data;
    for( i=0; i<TEST_DATA_SIZE; i=i+1) begin
        test_data[i] = (i+11)%255; // 生成随机测试数据
    end
endtask

endmodule

仿真实验

实验1、连续读写,写35MHZ

测试方案1:

写时钟75MHZ,读时钟35HZ,持续读写

仿真波形:

现象:因为写的速度比较快,所以在写入数量与读取数量差值在31的时候,full为高电平;

测试方案2:

写时钟35MHZ,读时钟75HZ,持续读写

仿真波形:

结论:通过仿真数据分析,写入值和读出值数据能一一对应上!因为读比写快,所以会有empty信号为低电平输出

测试方案3:

写时钟75MHZ,读时钟75MHZ,持续读写

结论:通过仿真数据分析,写入值和读出值数据能一一对应上!因为用的时同一个时钟信号,所以无full 和empty 信号输出。

测试方案4:

写时钟75MHZ,读时钟75MHZ,先写满溢出设计,后读空

仿真波形:写满波形

读空波形:         

读取的第一个数据就是写入的第一个数据,至此,FIFO实验测试成功!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值