Xilinx-IP核 FIFO

一、功能介绍

https://www.xilinx.com/content/xilinx/zh/products/intellectual-property/fifo_generator.html

  • FIFO 深度可达 4,194,304 个字
  • 原生 FIFO 配置支持从 1 到 1,024 位的 FIFO 数据宽度,而 AXI FIFO 配置的该数据宽度则高达 4,096 位
  • 非对称长宽比(读写端口比可从 1:8 到 8:1)
  • 支持独立或通用时钟域
  • 可选存储器类型(Block RAM、分布式 RAM、移位寄存器或内建 FIFO)
  • 原生接口或 AXI 接口(AXI4、AXI4-Lite 或 AXI4-Stream)
  • 同步或异步复位选项
  • 支持数据包模式
  • 支持纠错 (ECC) 和注入特性,适用于特定配置
  • 支持首字直接通过 (FWFT)
  • 支持嵌入式寄存器选项,适用于基于 Block RAM 和内建 FIFO 原语的实现方案
  • 支持 — 空/满、基本空/满和可编程空/满信号

二、FIFO实现方式区别

1. Common Clock FIFO (同步FIFO)

1.1 CommonClockBlockRAM:

时钟域: 读写操作使用相同的时钟。

存储资源: 使用FPGA的Block RAM(块RAM)作为存储介质。

特点: Block RAM是FPGA中的专用存储资源,容量较大,适合存储大量数据。

同步FIFO使用Block RAM时,读写操作在同一个时钟域内进行,时序简单,延迟较低。

适用场景: 适用于需要较大存储容量且读写操作在同一时钟域内的应用。

1.2 CommonClockDistributedRAM:

时钟域: 读写操作使用相同的时钟。

存储资源: 使用FPGA的分布式RAM(Distributed RAM)作为存储介质。

特点: 分布式RAM使用FPGA的逻辑单元(LUT)实现,容量较小,但灵活性高。

同步FIFO使用分布式RAM时,适合存储较小的数据量,且读写操作在同一时钟域内。

适用场景: 适用于存储容量需求较小且读写操作在同一时钟域内的应用。

1.3 CommonClockShiftRegister:

时钟域: 读写操作使用相同的时钟。

存储资源: 使用移位寄存器(Shift Register)作为存储介质。

特点: 移位寄存器通常由FPGA的逻辑单元(LUT)实现,适合存储非常小的数据量。

同步FIFO使用移位寄存器时,数据按位移动,适合小规模数据的缓冲。

适用场景: 适用于存储容量需求非常小且读写操作在同一时钟域内的应用。

1.4 CommonClockBuiltinFIFO:

时钟域: 读写操作使用相同的时钟。

存储资源: 使用FPGA内置的专用FIFO资源。

特点: 一些FPGA提供了专用的FIFO硬件资源,这些资源经过优化,能够提供较高的性能和较低的功耗。

同步FIFO使用内置FIFO资源时,读写操作在同一时钟域内,时序简单。

适用场景: 适用于需要高性能、低功耗且读写操作在同一时钟域内的应用。

2. Independent Clock FIFO (异步FIFO)

2.1 IndependentClocksBlockRAM:

时钟域: 读写操作使用不同的时钟。

存储资源: 使用FPGA的Block RAM作为存储介质。

特点: Block RAM容量较大,适合存储大量数据。

异步FIFO使用Block RAM时,读写操作在不同的时钟域内进行,

通常需要额外的同步电路来处理跨时钟域的信号传递。

适用场景: 适用于需要较大存储容量且读写操作在不同时钟域内的应用。

2.2 IndependentClocksDistributedRAM:

时钟域: 读写操作使用不同的时钟。

存储资源: 使用FPGA的分布式RAM作为存储介质。

特点: 分布式RAM灵活性高,但容量较小。

异步FIFO使用分布式RAM时,读写操作在不同的时钟域内进行,适合存储较小的数据量。

适用场景: 适用于存储容量需求较小且读写操作在不同时钟域内的应用。

2.3 IndependentClocksBuiltinFIFO:

时钟域: 读写操作使用不同的时钟。

存储资源: 使用FPGA内置的专用FIFO资源。

特点: 异步FIFO使用内置FIFO资源时,读写操作在不同的时钟域内进行,

通常内置FIFO资源已经优化了跨时钟域的信号处理,能够提供较高的性能和较低的功耗。

适用场景: 适用于需要高性能、低功耗且读写操作在不同时钟域内的应用。

三、设置界面

`timescale 1ns/100ps
module tb_fifo_generator();

    reg                                 rst='d1                     ;
    reg                                 wr_clk='d1                  ;
    reg                                 rd_clk='d1                  ;
    reg                [  17: 0]        din='d1                     ;
    reg                                 wr_en='d0                   ;
    reg                                 rd_en='d0                   ;

    wire               [  35: 0]        dout                        ;
    wire                                full                        ;
    wire                                almost_full                 ;
    wire                                empty                       ;
    wire                                almost_empt                 ;
    wire               [   7: 0]        rd_data_count               ;
    wire               [   8: 0]        wr_data_count               ;
    wire                                wr_rst_busy                 ;
    wire                                rd_rst_busy                 ;

    wire               [  16: 0]        douthigh                    ;
    wire               [  16: 0]        doutlow                     ;

    initial begin
        rst=1'b1;
        #1000;
        rst=1'b0;
    end

    always #2 wr_clk = ~wr_clk; //写快读蛮,但是读一次处理俩个写
    always #3 rd_clk = ~rd_clk;

    always @(posedge wr_clk ) 
    begin
        if(din >='d1000)
            wr_en <= 1'b0;
        else if(~wr_rst_busy && ~rst)
            wr_en <= 1'b1;
        else
            wr_en<= 1'b0;
    end 

    always @(posedge wr_clk ) 
    begin
        if(wr_en)
            din <= din + 1'b1;
    end 

    always @(posedge rd_clk ) 
    begin
        rd_en <= (~empty) && (~rd_rst_busy);
    end 

    assign douthigh = dout[35:18];
    assign doutlow  = dout[17:0 ];

fifo_generator_0 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 [17 : 0] din
    .wr_en                              (wr_en                     ),// input wire wr_en
    .rd_en                              (rd_en                     ),// input wire rd_en
    .dout                               (dout                      ),// output wire [35 : 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 [8 : 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


P.S.: 将写数据关掉,读写时钟频率设置相同后,观察到:

  1. 写使能开始后,第二个时钟沿写数据角度的计数器开始计数
  2. 读数据角度的计数器在第7个时钟沿开始计数,且第一个数据占用了6个周期,后续恢复正常,进2出1(测试同步时钟时并未出现这种情况,clk时钟图)
  3. empty信号在读数据计数器非零后的第2个时钟沿拉低
  4. 以上在实操中需注意时延问题,可通过仿真获取实际时延情况
  5. 虽然没有读数据使能,但dout会与非空状态同步传出第一组数据并保持

全部评论

相关推荐

02-19 13:42
门头沟学院 Java
运气爆棚福星高赵:清✌️不用很在意项目,八股算法是重点,八股算法说的过去绝对要您
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务