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

ops/2025/1/19 10:00:04/

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

目录

前言

FIFO%E7%9A%84%E4%BD%BF%E7%94%A8-toc" style="margin-left:0px;">一、同步FIFO的使用

1、配置

2、仿真

FIFO%E7%9A%84%E4%BD%BF%E7%94%A8-toc" style="margin-left:0px;">二、异步FIFO的使用

1、配置

2、仿真


前言

        在系统设计中,利用FIFO(first in first out)进行数据处理是再普遍不过的应用了,使用FIFO实现不同域时钟的数据同步,总线位宽调整,数据缓存等。本文以xilinx vivado中的FIFO IP 核为例,详细介绍其配置步骤,并给出详细的仿真,本文包含同步和异步(不同时钟)FIFO的详细使用步骤。


提示:以下是本篇文章正文内容,转载请附上原文链接

FIFO%E7%9A%84%E4%BD%BF%E7%94%A8">一、同步FIFO的使用

1、配置

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

首先,配置Basic界面:

Interface Type 保持默认即可,一般不选AXI接口。

FIFO Implementation 选用什么资源生成FIFO,这里选择 Common Clock Block RAM,即用块RAM资源生成一个同步FIFO

该界面下面显示的是在选定方式生成的FIFO具有的特点。

然后,配置Native Ports界面:

Read Mode 默认选Standard FIFO,First FIFO Fall Through 会在没有读的时候就在读端口放置第一个数据,如手册中的下图所示,只要写入一个数据 D1 后,在rd_en为低电平的时候,dout就会变成D1且valid一直拉高。大家可以根据自己的需求选择对应的读模式。

Data Port Parameters 用来配置读写的深度和数据位宽,这里示例配置4bit宽度,16的深度。

!!!要留意一下配置的深度和实际的深度,手册中提及了选择不同实现方式(Basic 界面)实际深度与配置的深度是有差异的,实际深度才是可以使用的深度。

ECC,Output... 是IP核纠错,输出端加寄存器的功能,在配置时其实不用管,不用勾选任何东西。

Initialization 勾选复位,类型选择同步复位,Full Flags Reset Value 是复位时满标志的默认电平,Dout Reset Value 是复位时默认的读端口输出。

再然后,配置Status Flags界面:

Optional Flags中的Almost Full Flag是快要写满标志,即再写一个数据就满了的提示, Almost Empty Flag是快要读空标志,即再读一个数据就空了的提示。

Write Acknowledge 是写数据的标志,如果勾选高电平有效,则其拉高表示数据被写入。

Overflow 是溢出标志,如果满了,继续写数据是写不了的,溢出了。

valid Flag 读数据时输出数据有效的标志。

Underflow Flag 下溢标志,如果选择高电平有效,也就是读空了继续读该标志就会拉高。

Programmable Flags 是自定义一个数据写多少个就算满的标志信号和数据还剩多少个就算空的标志信号,可以在IP核界面配置固定的值,也可以引入两个输入端口由程序编程设置。需要用到该功能的可自行配置。

此处,按下图配置届时仿真可观察这些信号。

最后,配置Data Counts界面:

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

至此,同步 FIFO 配置完成,下面进行仿真。

2、仿真

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

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2025/01/15 11:36:36
// Design Name: 
// Module Name: tb_synchronous_fifo
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//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
beginforever #(PERIOD/2)  clk=~clk;
endinitial
begin#(PERIOD*5) rst_n  =  1;
endreg [4:0] cnt;
always @(posedge clk or negedge rst_n)
beginif(!rst_n)beginwr_en<=0;cnt<=0;endelse if(cnt<16)begincnt<=cnt+1;wr_en<=1;din<=din+1;endelsebeginwr_en<=0;end
endalways @(posedge clk or negedge rst_n)
beginif(!rst_n)beginrd_en<=0;endelse if(cnt==16)beginrd_en<=1;end
endtest_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个数据,谁先写入就先被读出。大家可自行观察其他信号的变化是否和自己理解的一致。

        上面配置FIFO的深度只有16,如果写入数据个数大于16,数据能写进去吗?答案是写不进去,并不是我们理解的满了再进就会将最开始进的挤出去。VIVADO FIFO IP就是这样这样设置的,没有办法改变,那么如果某些场景下需要这种满了再进就会将最开始进的挤出去的这种功能,光调用IP还无法实现。

        例如,将上面代码中的 else if(cnt<16)  和 else if(cnt==16) 两句代码中的16改成20再仿真,结果如下,分析结果可以得出,满了继续写不会将最开始写的挤出去,而是直接忽视掉再写的数据。

FIFO%E7%9A%84%E4%BD%BF%E7%94%A8">二、异步FIFO的使用

1、配置

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

首先,配置Basic界面:

Interface Type 保持默认即可,一般不选AXI接口。

FIFO Implementation 选用什么资源生成FIFO,这里选择 Independent Clocks Block RAM,即用块RAM资源生成一个异步FIFO

相比于同步FIFO,多了synchronization Stages的配置,这个相当于写时钟域里面的数据经过多少个时钟周期同步到读时钟区域,可以理解成延时打拍同步。

该界面下面显示的是在选定方式生成的FIFO具有的特点。

然后,配置Native Ports界面:

Read Mode 同步FIFO配置有介绍,此处默认选Standard FIFO

Data Port Parameters 用来配置读写的深度和数据位宽,这里示例配置4bit宽度,16的深度。

!!!要留意一下配置的深度和实际的深度,手册中提及了选择不同实现方式(Basic 界面)实际深度与配置的深度是有差异的,实际深度才是可以使用的深度。异步FIFO此时实际可使用的深度就比我们配置的少了一个。

ECC,Output... 是IP核自己纠错,输出端加寄存器的功能,在配置时其实不用管,不用勾选任何东西。

Initialization 勾选复位,Reset Type 固定了只能异步复位,是相对于整个IP而言。Full Flags Reset Value 是复位后满标志的默认电平,Dout Reset Value 是复位后默认的读端口输出。

相比于同步FIFO,多了Enable Reset Synchronization,该选项是读写时钟域分开来看时,在各自的时钟域里面使用同步复位。Enable Safety Circuit 手册说是一个保护电路,默认勾选即可,不用过多纠结。

Full Flags Reset Value 是复位时满标志默认电平,Dout Reset Value 是复位时默认读端口输出。

再然后,配置Status Flags界面:

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

最后,配置Data Counts界面:

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

至此,异步 FIFO 配置完成,下面进行仿真。

2、仿真

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

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2025/01/15 12:20:08
// Design Name: 
// Module Name: tb_asynchronous_fifo
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//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
beginforever #(PERIOD/2)  wr_clk=~wr_clk;
endinitial
beginforever #(PERIOD)    rd_clk=~rd_clk;
endinitial
begin#(PERIOD*5) rst_n  =  1;
endreg flag=0;initial
begin#(PERIOD*28) flag  =  1;#(PERIOD)    flag  =  0;
endreg [4:0] cnt;
always @(posedge wr_clk or negedge rst_n)
beginif(!rst_n)beginwr_en<=0;cnt<=0;endelse if(flag)begincnt<=cnt+1;wr_en<=1;din<=din+1;endelse if(1<=cnt&&cnt<16)begincnt<=cnt+1;wr_en<=1;din<=din+1;endelsebeginwr_en<=0;end
endalways @(posedge rd_clk or negedge rst_n)
beginif(!rst_n)beginrd_en<=0;endelse if(cnt==16)beginrd_en<=1;end
endtest_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,与我们IP配置界面相吻合;第二,因为本身实际容量只有15个数据,我们写16个数据,溢出了一个,图中overflow拉高了一个电平,与同步FIFO一样,写满了就写不进去了;第三,图中两条黄色线之间相差4个读时钟周期,就是我们前面配置提到的延迟打拍保证时钟区域同步,那明明前面配置的是2,为什么这里为4呢?这是因为下图中的数字2造成的,2+2=4。

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

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


http://www.ppmy.cn/ops/151350.html

相关文章

探秘Node.js模块Modules:从入门到精通

文章目录 一、引言二、Node.js 模块初相识2.1 模块的概念与意义2.2 模块的类型 三、Node.js 模块的使用方法3.1 核心模块的调用3.2 文件模块的创建与运用3.2.1 创建自定义模块3.2.2 引入自定义模块 3.3 ES Modules 的运用3.3.1 启用 ES Modules3.3.2 导入导出规则 四、node_mod…

“深入浅出”系列之音视频开发:(3)岗位要求

算法工程师-视频编解码 职位描述 在这里&#xff0c;你将参与JVET / VVC的下一代视频编码标准设计和算法研究&#xff1b; 在这里&#xff0c;你将参与视频编码&#xff08;包括但不限于VVC/AV1/AVS3&#xff09;优化&#xff1a;通过信号处理和机器学习的快速编码决策、数据…

C++(二十二)

前言&#xff1a; 本文承接上文&#xff0c;将详细讲述C中&#xff0c;参数与指针。 一&#xff0c;无响应参数。 首先复习一下之前曾学习过的函数&#xff1a; void change(int a,int b) { int temp; tempa; ab; btemp; } 看起来是一个简单的交换a与b值的函数。 完整代…

SpringBoot Starter 通用接口加密组件(防篡改)+ RequestBodyAdvice和ResponseBodyAdvice原理

实现参考博客&#xff1a; RequestBodyAdvice和ResponseBodyAdvice原理&#xff1a; RequestBodyAdvice和ResponseBodyAdvice原理详解-CSDN博客 SpringBoot Starter 通用接口加密组件&#xff08;防篡改&#xff09;&#xff1a; SpringBoot Starter 通用接口加密组件_spri…

Redis 部署模式

Redis 提供了三种部署模式&#xff1a;单兵模式、哨兵模式、和 集群模式&#xff0c;每种模式有不同的特点和适用场景。下面分别介绍这三种模式。 1. 单兵模式&#xff08;Standalone&#xff09; 单兵模式是最简单的 Redis 部署模式&#xff0c;适合对高可用性要求不高的场景…

第10篇:从入门到精通:深入理解Python继承与多态的概念及应用

第10篇&#xff1a;继承与多态 内容简介 本篇文章将深入探讨Python中的继承与多态概念。您将学习如何通过类的继承实现代码的重用&#xff0c;掌握方法重写的技巧&#xff0c;了解如何使用super()函数调用父类的方法&#xff0c;并探索多态的实现与应用。通过丰富的代码示例&…

1.9 提示学习(Prompt Learning)之思维链(Chain-of-Thought, CoT):开山之作

提示学习(Prompt Learning)之思维链(Chain-of-Thought, CoT):开山之作 近年来,人工智能领域取得了巨大进步,尤其是在自然语言处理(NLP)方面。随着GPT模型的发展,如何有效地引导模型生成高质量的回答成为了学术界和工业界的重要研究课题。在这一过程中,**思维链(Ch…

Microi 吾码:低代码解锁服务器虚拟化的无限潜能

目录 一、服务器虚拟化的时代浪潮与核心意义 二、Microi 吾码在服务器虚拟化资源管理中的卓越表现 虚拟机资源分配与监控的智能掌控 资源调度与优化的精妙策略 三、Microi 吾码助力服务器虚拟化的网络配置与优化 虚拟网络架构的灵活构建 网络流量优化与安全保障的双重守…