问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

VIVADO FIFO (同步和异步) IP 核详细使用配置步骤

创作时间:
作者:
@小白创作中心

VIVADO FIFO (同步和异步) IP 核详细使用配置步骤

引用
CSDN
1.
https://blog.csdn.net/m0_66360845/article/details/145163327

在系统设计中,FIFO(先进先出)是一种常用的数据处理方式,可用于不同域时钟的数据同步、总线位宽调整和数据缓存等场景。本文将以Xilinx Vivado中的FIFO IP核为例,详细介绍其配置步骤,并通过仿真验证展示同步和异步FIFO的具体使用方法。

一、同步FIFO的使用

1. 配置

在IP Catalog界面搜索FIFO并双击FIFO Generator开始配置IP核。对IP核命名,不妨取名为test_synchronous_fifo(同步FIFO的测试)。

Basic界面配置

  • Interface Type保持默认即可,一般不选AXI接口。
  • FIFO Implementation选择Common Clock Block RAM,即用块RAM资源生成一个同步FIFO。

Native Ports界面配置

  • Read Mode默认选Standard FIFO。First FIFO Fall Through会在没有读的时候就在读端口放置第一个数据。
  • Data Port Parameters用于配置读写的深度和数据位宽,这里示例配置4bit宽度,16的深度。
  • 注意配置的深度和实际深度的差异,选择不同实现方式(Basic界面)时实际深度与配置深度可能有差异。
  • Initialization勾选复位,类型选择同步复位,Full Flags Reset Value是复位时满标志的默认电平,Dout Reset Value是复位时默认的读端口输出。

Status Flags界面配置

  • Almost Full Flag是快要写满标志。
  • Write Acknowledge是写数据的标志。
  • Overflow是溢出标志。
  • Valid Flag是读数据时输出数据有效的标志。
  • Underflow Flag是下溢标志。
  • Programmable Flags是自定义数据写多少个就算满的标志信号和数据还剩多少个就算空的标志信号。

Data Counts界面配置

可以勾选Data Count,指示FIFO中还有多少个数据。由于此时是同步FIFO,所以只有一个Data Count。

2. 仿真

创建一个名为tb_synchronous_fifo的testbench文件,测试以上配置的FIFO。

`timescale 1ns / 1ps
module tb_synchronous_fifo();
parameter  PERIOD   = 2;
reg clk=1;
reg rst_n=0;
reg [3 : 0] din=0;
reg wr_en=0;
reg rd_en=0;
wire [3 : 0] dout;
wire full;
wire almost_full;
wire wr_ack;
wire overflow;
wire empty;
wire almost_empty;
wire valid;
wire underflow;
wire [3 : 0] data_count;
initial
begin
    forever #(PERIOD/2)  clk=~clk;
end
initial
begin
    #(PERIOD*5) rst_n  =  1;
end
reg [4:0] cnt;
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        begin
            wr_en<=0;
            cnt<=0;
        end
    else if(cnt<16)
        begin
            cnt<=cnt+1;
            wr_en<=1;
            din<=din+1;
        end
    else
        begin
            wr_en<=0;
        end
end
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        begin
            rd_en<=0;
        end
    else if(cnt==16)
        begin
            rd_en<=1;
        end
end
test_synchronous_fifo u_test_synchronous_fifo (
  .clk(clk),                    // input wire clk 
  .srst(!rst_n),                // input wire srst ip核本身是高电平复位
  .din(din),                    // input wire [3 : 0] din
  .wr_en(wr_en),                // input wire wr_en
  .rd_en(rd_en),                // input wire rd_en
  .dout(dout),                  // output wire [3 : 0] dout
  .full(full),                  // output wire full
  .almost_full(almost_full),    // output wire almost_full
  .wr_ack(wr_ack),              // output wire wr_ack
  .overflow(overflow),          // output wire overflow
  .empty(empty),                // output wire empty
  .almost_empty(almost_empty),  // output wire almost_empty
  .valid(valid),                // output wire valid
  .underflow(underflow),        // output wire underflow
  .data_count(data_count)       // output wire [3 : 0] data_count
);
endmodule

从仿真结果可以看出写入16个数据,读出16个数据,谁先写入就先被读出。如果写入数据个数大于16,数据将无法写入,VIVADO FIFO IP就是这样设置的,无法改变。

二、异步FIFO的使用

1. 配置

在IP Catalog界面搜索FIFO并双击FIFO Generator开始配置IP核。对IP核命名,不妨取名为test_asynchronous_fifo(异步FIFO的测试)。

Basic界面配置

  • Interface Type保持默认即可,一般不选AXI接口。
  • FIFO Implementation选择Independent Clocks Block RAM,即用块RAM资源生成一个异步FIFO。
  • 多了synchronization Stages的配置,这个相当于写时钟域里面的数据经过多少个时钟周期同步到读时钟区域,可以理解成延时打拍同步。

Native Ports界面配置

  • Read Mode同同步FIFO配置。
  • Data Port Parameters用于配置读写的深度和数据位宽,这里示例配置4bit宽度,16的深度。
  • Initialization勾选复位,Reset Type固定为异步复位,Full Flags Reset Value是复位后满标志的默认电平,Dout Reset Value是复位时默认的读端口输出。
  • 多了Enable Reset Synchronization,该选项是读写时钟域分开来看时,在各自的时钟域里面使用同步复位。Enable Safety Circuit是一个保护电路,默认勾选即可。

Status Flags界面配置

同步FIFO配置界面已一 一说明。此处,按下图配置届时仿真可观察这些信号。

Data Counts界面配置

Data Count,指示FIFO中还有多少个数据。由于此时是异步FIFO,所以读写各有一个Data Count。

2. 仿真

创建一个名为tb_asynchronous_fifo的testbench文件,测试以上配置的异步FIFO。

`timescale 1ns / 1ps
module tb_asynchronous_fifo();
parameter  PERIOD   = 2;
reg rst_n=0;
reg wr_clk=1;
reg rd_clk=1;
reg [3 : 0] din=0;
reg wr_en=0;
reg rd_en=0;
wire [3 : 0] dout;
wire full;
wire almost_full;
wire wr_ack;
wire overflow;
wire empty;
wire almost_empty;
wire valid;
wire underflow;
wire [3 : 0] rd_data_count;
wire [3 : 0] wr_data_count;
wire wr_rst_busy;
wire rd_rst_busy;
initial
begin
    forever #(PERIOD/2)  wr_clk=~wr_clk;
end
initial
begin
    forever #(PERIOD)    rd_clk=~rd_clk;
end
initial
begin
    #(PERIOD*5) rst_n  =  1;
end
reg flag=0;
initial
begin
    #(PERIOD*28) flag  =  1;
    #(PERIOD)    flag  =  0;
end
reg [4:0] cnt;
always @(posedge wr_clk or negedge rst_n)
begin
    if(!rst_n)
        begin
            wr_en<=0;
            cnt<=0;
        end
    else if(flag)
        begin
            cnt<=cnt+1;
            wr_en<=1;
            din<=din+1;
        end
    else if(1<=cnt&&cnt<16)
        begin
            cnt<=cnt+1;
            wr_en<=1;
            din<=din+1;
        end
    else
        begin
            wr_en<=0;
        end
end
always @(posedge rd_clk or negedge rst_n)
begin
    if(!rst_n)
        begin
            rd_en<=0;
        end
    else if(cnt==16)
        begin
            rd_en<=1;
        end
end
test_asynchronous_fifo u_test_asynchronous_fifo (
  .rst(!rst_n),                   // input wire rst
  .wr_clk(wr_clk),                // input wire wr_clk
  .rd_clk(rd_clk),                // input wire rd_clk
  .din(din),                      // input wire [3 : 0] din
  .wr_en(wr_en),                  // input wire wr_en
  .rd_en(rd_en),                  // input wire rd_en
  .dout(dout),                    // output wire [3 : 0] dout
  .full(full),                    // output wire full
  .almost_full(almost_full),      // output wire almost_full
  .wr_ack(wr_ack),                // output wire wr_ack
  .overflow(overflow),            // output wire overflow
  .empty(empty),                  // output wire empty
  .almost_empty(almost_empty),    // output wire almost_empty
  .valid(valid),                  // output wire valid
  .underflow(underflow),          // output wire underflow
  .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
  .wr_rst_busy(wr_rst_busy),      // output wire wr_rst_busy
  .rd_rst_busy(rd_rst_busy)       // output wire rd_rst_busy
);
endmodule

观察仿真结果:

  1. 复位时满信号为1,与IP配置界面相吻合。
  2. 因为本身实际容量只有15个数据,写16个数据时溢出了一个,图中overflow拉高了一个电平。
  3. 图中两条黄色线之间相差4个读时钟周期,就是前面配置提到的延迟打拍保证时钟区域同步,那明明前面配置的是2,为什么这里为4呢?这是因为下图中的数字2造成的,2+2=4。

接下来将IP配置界面的同步拍数改为3,那么仿真图中两条黄色线之间则会有5个读时钟周期,以保证数据同步到读时钟域。

至此,本文结束。如果想设置写到一定数量就有满标志提示,还剩多少个就有空标志提示,就需要去配置Status Flags界面的Programmable Flags。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号