小梅哥Xilinx FPGA学习笔记22——ip核之FIFO

目录

一:章节说明

1.1 FIFO IP简介

1.2 FIFO Generato IP 核信号框图

1.3 实验任务

二:FIFO 写模块设计

2.1 简介     

2.2 模块框图

2.3 模块端口与功能描述

2.4 写模块代码

三 FIFO 读模块设计

3.1 简介  

3.2 模块框图

3.3 模块端口与功能描述

3.4 读模块代码

四: 顶层模块设计

4.1 概述

4.2 模块端口与功能描述

4.3 代码编写

五 仿真测试验证实现

5.1 仿真验证代码

5.2 仿真结果


一:章节说明

1.1 FIFO IP简介

       FIFO 本质上是由 RAM 加读写控制逻辑构成的一种先进先出的数据缓冲器,其与普通存储器 RAM 的区别在于 FIFO 没有外部读写地址线,使用起来非常简单,但 FIFO 只能顺序写入数据,并按顺序读出数据, 其数据地址由内部读写指针自动加 1 完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定 的地址,不过也正是因为这个特性,使得 FIFO 在使用时并不存在像 RAM 那样的读写冲突问题。
       根据 FIFO 工作的时钟域,可以将 FIFO 分为同步 FIFO 和异步 FIFO 。同步 FIFO 是指读时钟和写时钟 为同一个时钟,在时钟沿来临时同时发生读写操作,常用于两边数据处理带宽不一致的临时缓冲。异步 FIFO 是指读写时钟不一致,读写时钟是互相独立的,一般用于数据信号跨时钟阈处理。
对于 FIFO 我们还需要了解一些常见参数:
1FIFO 的宽度: FIFO 一次读写操作的数据位宽 N
2FIFO 的深度: FIFO 可以存储多少个宽度为 N 位的数据。
3、将空标志: almost_empty FIFO 即将被读空。
4、空标志: empty FIFO 已空时由 FIFO 的状态电路送出的一个信号,以阻止 FIFO 的读操作继续从 FIFO 中读出数据而造成无效数据的读出。
5、将满标志: almost_full FIFO 即将被写满。
6、满标志: full FIFO 已满时由 FIFO 的状态电路送出的一个信号,以阻止 FIFO 的写操作继续向 FIFO 中写数据而造成溢出。
7 、写时钟: FIFO 时所遵循的时钟,在每个时钟的上升沿触发。
8 、读时钟: FIFO 时所遵循的时钟,在每个时钟的上升沿触发。
这里还有两点需要大家注意:
1、“ almost_empty ”和“ almost_full ”这两个信号分别被看作“ empty ”和“ full ”的警告信号,他们相对于真正的空( empty )和满( full )都会 提前一个时钟周期拉高
2 FIFO 中,先写入的数据被置于高位,后写入的数据被置于低位,由于其先入先出的特性,所以读出的数据也是高位在前,低位在后。这一点在读写数据位宽不对等时尤为重要,例如我们写数据位宽为 8 ,读数据位宽为 2 ,当写入的数据为 11000111 时,读出的数据依次为 11、00、01、11

1.2 FIFO Generato IP 核信号框图

       首先说明下,上图中黑色箭头表示此信号为必要信号;蓝色箭头表示此信号为可选信号;灰色箭头表示此信号为可选的边带信号。从图中我们可以了解到,当被配置为同步 FIFO 时,只使用 wr_clk ,所有的输入输出信号都同步于 wr_clk 信号。而当被配置为异步 FIFO 时,写端口和读端口分别有独立的时钟,所有与写相关的信号都是同步于写 时钟 wr_clk ,所有与读相关的信号都是同步于读时钟 rd_clk

        这里我们对框图中的常用信号端口做一下讲解,其他很少用到的信号如果大家感兴趣的话也可以在课后打开 IP 核的数据手册进行学习,各常用端口的功能描述如下:

1.3 实验任务

       本节的实验任务是使用 Vivado 生成一个异步 FIFO ,并实现以下功能:当 FIFO 为空时,向 FIFO 中写入数据,直至将 FIFO 写满后停止写操作;当 FIFO 为满时,从 FIFO 中读出数据,直到 FIFO 被读空后停 止读操作,以此向大家详细介绍一下 FIFO IP 核的使用方法。
1.4 配置FIFO步骤
       详细步骤可以参考正点原子 领航者ZYNQ 之 FPGA 开发指南 P584
网盘链接如下:

      https://pan.baidu.com/s/1vXxmhg_mZm_OVg4xQeiCVQ  提取码:zdyz

二:FIFO 写模块设计

2.1 简介     

       首先介绍下 FIFO 写模块的设计,在 FIFO 写模块中,我们的输入信号主要有系统时钟信号(写时钟域的时钟)、系统复位信号;因为 FIFO 的写操作需要在 FIFO 完成复位后进行,所以我们还需要输入 wr_rst_busy (写复位忙)信号来判断 FIFO 是否结束了复位状态;实验任务中我们提到了 FIFO 为空时进行写操作,因 此还需要引入一个空相关的信号,这里我们引入的是 empty (空)信号;实验任务中我们还提到了写满了要 停止写操作,所以这里我们引入了 almost_full (将满)信号,因为将满信号表示 FIFO 还能再进行最后一次 写操作,使用这个信号的话我们正好可以在写入最后一次数据后关闭写使能,当然引入 full(满)信号也是可以,区别只是在于这么做会在写使能关断前执行一次无效的写操作。

2.2 模块框图

2.3 模块端口与功能描述

2.4 写模块代码

module fifo_wr(
//mudule clockinput wr_clk , // 时钟信号input rst_n , // 复位信号
//FIFO接口 input wr_rst_busy , // 写复位忙信号input empty , // FIFO 空信号input almost_full , // FIFO 将满信号output reg fifo_wr_en , // FIFO 写使能output reg [7:0] fifo_wr_data // 写入 FIFO 的数据);   reg empty_d0;
reg empty_d1;    
//因为 empty信号是和读信号的时钟同步的,对于写始终来说他是异步信号,所以要进行打拍处理   
always@(posedge wr_clk or negedge rst_n)   if(!rst_n)beginempty_d0 <= 0;      empty_d1 <= 0;endelse beginempty_d0 <= empty;empty_d1 <= empty_d0;end
//fifo写使能信号赋值,当 FIFO 为空时开始写入,写满后停止写    
always@(posedge wr_clk or negedge rst_n)   if(!rst_n)  fifo_wr_en <= 0;else if(!wr_rst_busy)beginif(empty_d1)fifo_wr_en <= 1;          else if(almost_full)fifo_wr_en <= 0;       else fifo_wr_en <= fifo_wr_en; endelsefifo_wr_en <= 0;//对 fifo_wr_data 赋值,0~254   
always@(posedge wr_clk or negedge rst_n)   if(!rst_n)  fifo_wr_data <= 0;else if(fifo_wr_en && fifo_wr_data < 254)fifo_wr_data <= fifo_wr_data + 1;elsefifo_wr_data <= 0;endmodule

FIFO 读模块设计

3.1 简介  

       首先介绍下 FIFO 读模块的设计,在 FIFO 读模块中,我们的输入信号主要有系统时钟信号(读时钟域时钟)和系统复位信号;因为 FIFO 的读操作需要在 FIFO 完成复位后进行,所以我们还需要输入 rd_rst_busy(读复位忙)信号来判断 FIFO 是否结束了复位状态;实验任务中我们提到了 FIFO 为满时进行读操作,因 此还需要引入一个满相关的信号,这里我们引入的是 full (满)信号;实验任务中我们还提到了读空了要停 止读操作,所以这里我们引入了 almost_empty (将空)信号,因为将空信号表示 FIFO 还能再进行最后一次读操作,使用这个信号的话我们正好可以在读出最后一个数据后关闭读使能,当然引入 empty (空)信号也 是可以,区别只是在于这么做会在读使能关断前执行一次无效的读操作。

3.2 模块框图

3.3 模块端口与功能描述

3.4 读模块代码

module fifo_rd(
//system clockinput rd_clk , //时钟信号input rst_n , //复位信号
//FIFO接口input rd_rst_busy , //读复位忙信号input [7:0] fifo_rd_data, //从 FIFO 读出的数据input full , //FIFO 满信号input almost_empty, //FIFO 将空信号output reg fifo_rd_en //FIFO 读使能);reg full_d0;reg full_d1;//因为 full 信号是属于 FIFO 写时钟域的,所以对 full 打两拍同步到读时钟域下  
always@(posedge rd_clk or negedge rst_n)   if(!rst_n)beginfull_d0 <= 0;      full_d1 <= 0;endelse beginfull_d0 <= full;full_d1 <= full_d0;end    //对 fifo_rd_en 进行赋值,FIFO 写满之后开始读,读空之后停止读    
always@(posedge rd_clk or negedge rst_n)   if(!rst_n)   fifo_rd_en <= 0;else if(!rd_rst_busy)beginif(full_d1)fifo_rd_en <= 1;    else if(almost_empty)fifo_rd_en <= 0;  endelsefifo_rd_en <= 0; endmodule

四: 顶层模块设计

4.1 概述

       本次实验的目的是为了将 Xilinx FIFO Generato IP 核配置成一个异步 FIFO 并对其进行读写操作,因此可以给模块命名为 ip_fifo ;因为我们做的是异步 FIFO ,所以我们需要一个 PLL IP 核来输出 50MHz 的写时 钟和 100MHz 的读时钟,当然输出其它频率的时钟也是可以的;然后我们还需要一个写模块( fifo_wr )和 一个读模块( fifo_rd ),写模块通过 FIFO 的状态来判断是否给出写请求信号和写数据,读模块通过 FIFO 的状态来判断是否给出读请求信号,并接收从 FIFO 中读出的数据;系统时钟和系统复位是一个完整的工 程中必不可少的输入端口信号,这里就不再多讲了。经过上述分析我们可以画出一个大致的模块框图,如 下图所示:

            

4.2 模块端口与功能描述

4.3 代码编写

module ip_fifo(input sys_clk,input sys_rst_n
);wire  locked;    
wire  clk_50M;    
wire  clk_100M;    
wire  rst_n;
wire  wr_rst_busy;
wire  empty;
wire  almost_full;
wire  [7 : 0]fifo_wr_data;
wire  rd_rst_busy;
wire  [7 : 0]fifo_rd_data;
wire  fifo_rd_en;
wire  fifo_wr_en;
wire  almost_empty;
wire  [7 : 0]rd_data_count;
wire  [7 : 0]wr_data_count;
wire  full;//通过系统复位信号和时钟锁定信号来产生一个新的复位信号,代表当输出频率时钟稳定后,且复位完成后才能执行
assign rst_n = sys_rst_n & locked;
//例化 PLL IP 核   
clk_wiz_0 clk_wiz_0
(.clk_out1(clk_50M),     // output clk_out1.clk_out2(clk_100M),     // output clk_out2.locked(locked),       // output locked.clk_in1(sys_clk)  // input clk_in1 
);        
//例化 FIFO IP 核    
fifo_generator_0 your_instance_name (.rst(~rst_n),                      // input wire rst.wr_clk(clk_50M),                // input wire wr_clk.rd_clk(clk_100M),                // input wire rd_clk.din(fifo_wr_data),                      // input wire [7 : 0] din.wr_en(fifo_wr_en),                  // input wire wr_en.rd_en(fifo_rd_en),                  // input wire rd_en.dout(fifo_rd_data),                    // output wire [7 : 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 [7 : 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
);    //例化写 FIFO 模块    
fifo_wr fifo_wr(.wr_clk(clk_50M)              , // 时钟信号.rst_n(rst_n)                 , // 复位信号.wr_rst_busy(wr_rst_busy)     , // 写复位忙信号.empty(empty)                 , // FIFO 空信号.almost_full(almost_full)     , // FIFO 将满信号.fifo_wr_en(fifo_wr_en)                 ,.fifo_wr_data(fifo_wr_data)     // 写入 FIFO 的数据
);       //例化读 FIFO 模块  
fifo_rd fifo_rd(.rd_clk          (clk_100M)     , //时钟信号.rst_n           (rst_n)        , //复位信号.rd_rst_busy     (rd_rst_busy)  , //读复位忙信号.fifo_rd_data    (fifo_rd_data) , //从 FIFO 读出的数据.full            (full)         , //FIFO 满信号.almost_empty    (almost_empty) , //FIFO 将空信号.fifo_rd_en      (fifo_rd_en)     //FIFO 读使能
); endmodule
        可以看出 ip_fifo 顶层模块只是例化了 FIFO IP 核( fifo_generator_0 )、 PLL IP clk_wiz_0 )、读模块( fifo_rd )和写模块( fifo_wr ),其中写模块负责产生 FIFO IP 核写操作所需的所有数据、写请求等信 号;读模块负责产生 FIFO IP 核读操作所需读请求信号,并将读出的数据也连接至读模块。 因为读写模块的时钟皆来自 PLL IP 核,而 PLL IP 核需要一定的时间才能输出稳定的时钟,所以在第29 行代码中我们通过系统复位和时钟锁定来产生一个信号复位信号,使读 / 写模块及 FIFO IP 核在时钟稳定 后才进入工作状态。

五 仿真测试验证实现

5.1 仿真验证代码

`timescale 1ns / 1ps
module ip_fifo_tb();parameter CLK_PERIOD = 20; //时钟周期 20ns
//reg define
reg sys_clk;
reg sys_rst_n;//信号初始化initial beginsys_clk = 1'b0;sys_rst_n = 1'b0;#200;sys_rst_n = 1'b1;//模拟按下复位#10000 ;sys_rst_n = 0;#160 ;sys_rst_n = 1;end//产生时钟always #(CLK_PERIOD/2) sys_clk = ~sys_clk;ip_fifo u_ip_fifo (.sys_clk (sys_clk ),.sys_rst_n (sys_rst_n)
);endmodule

5.2 仿真结果

从仿真中可见FIFO读取设计正确。
因为RAM以及FIFO在FPGA中较为重要,所以后面还会有学习RAM以及FIFO的相关案例,敬请期待。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/609370.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OpenAI ChatGPT-4开发笔记2024-03:Chat之Tool和Tool_Call(含前function call)

Updates on Function Calling were a major highlight at OpenAI DevDay. In another world,原来的function call都不再正常工作了&#xff0c;必须全部重写。 function和function call全部由tool和tool_choice取代。2023年11月之前关于function call的代码都准备翘翘。 干嘛…

进阶学习——Linux网络

目录 一、网络配置命令 1.ifconfig——IP地址 1.1ifconfig的基础用法 1.1.1ifconfig命令详解 1.2常用格式 1.3修改网卡名称 1.3.1临时修改 1.3.2永久修改 1.4临时修改网卡 1.4.1设置虚拟网卡 1.4.2延伸——ethtool 1.5永久修改网卡 1.6实验 —— 双网卡配置 1.…

【方法】如何修改Word文档密码?

我们在生活和工作中经常会使用到Word&#xff0c;有时候需要保护Word文档&#xff0c;还会设置密码&#xff0c;那如果后续想要修改密码&#xff0c;要怎么操作呢&#xff1f; 下面来看看Word文档常用的3种密码是如何修改的。 一、打开密码 想要修改“打开密码”&#xff0c…

2023-12-02 青少年软件编程(C语言)等级考试试卷(七级)解析

2023-12-02 青少年软件编程(C语言)等级考试试卷(七级)解析 一、编程题(共4题,共100分)T1. 迷宫 一天Extense在森林里探险的时候不小心走入了一个迷宫,迷宫可以看成是由n * n的格点组成,每个格点只有2种状态,.和#,前者表示可以通行后者表示不能通行。同时当Extense…

大学生如何当一个程序员——第三篇:热门专业学习之路7

区块链 1.区块链行业介绍2.Golang从入门到高级3.数据库操作和Golang Web4. Golang 实战项目5.密码学6. 共识算法7. Solidity8. 以太坊原理9.以太坊客户端10.去中心换拍卖系统DApp11.超级账本和DApp实战12.C编程快速入门13.比特币14.EOS 各位小伙伴想要博客相关资料的话关注公众…

Scikit-Learn线性回归(六)

Scikit-Learn线性回归六&#xff1a;Lasso回归 1、Lasso回归 1、Lasso回归 本文接上篇&#xff1a;Scikit-Learn线性回归(五)

基于Python爬虫的B站弹幕可视化

介绍 这是一个基于Python的B站弹幕可视化项目&#xff0c;主要使用了python django、requests、jieba等库。该项目实现了以下功能&#xff1a; 1. 爬取Bilibili视频弹幕数据&#xff1a;通过爬虫获取视频的标题、视频总时长、封面图&#xff0c;视频地址以及所有弹幕数据等。 …

Cesium笔记 初始化 原生Cesium

1、创建vue项目 vue create my_demo 2、下载Cesium 可以从官网下载&#xff0c;也可以使用node下载 npm install cesium 3、把node_modules文件夹中下载得Cesium&#xff0c;移出到public文件夹下 4、将Cesium.js 以及样式文件widgets.css在index.html中引用 <!DOCT…

“器官短缺”将被打破 基因编辑猪成为人类的“二师兄”

器官移植被称为生命之灯。但是&#xff0c;受制于传统观念及对人体器官捐献意义的不了解&#xff0c;人体器官捐献的数量&#xff0c;还远远达不到需求。目前&#xff0c;全国有近30万的患者在等待器官移植&#xff0c;但每年只有近一万的患者能真正得到器官移植&#xff0c;缺…

电脑怎么抠图?分享4款神奇的工具!

随着数字时代的来临&#xff0c;电脑抠图技术已经成为设计师、摄影师和广大创意人士必备的技能之一。那么&#xff0c;究竟有哪些工具可以帮助我们实现这一神奇的技术呢&#xff1f;今天&#xff0c;我们就来一探究竟&#xff01; 万能图片编辑器 它的抠图功能能够快速地识别图…

Python 二进制、八进制、十六进制表示法与十进制互转的方法

1、Python中二进制、八进制、十进制与十六进制的表示方法如下表&#xff1a; 名称描述示例二进制&#xff08;Binary&#xff09;以 0b 或 0B 开头&#xff0c;后面跟着由 0 和 1 组成的数字序列0b1010八进制&#xff08;Octal&#xff09;以 0o 或 0O 开头&#xff0c;后面跟…

JAVA实现文件上传至阿里云

注册阿里云账号后,开通好对象存储服务&#xff08;OSS&#xff09;&#xff0c;三个月试用 阿里云登录页 (aliyun.com) 目录 一.创建Bucket 二.获取AccessKey&#xff08;密钥&#xff09; 三.参考官方SDK文件&#xff0c;编写入门程序 1.复制阿里云OSS依赖&#xff0c;粘贴…

1042: 数列求和3 和 1057: 素数判定 和 1063: 最大公约与最小公倍

1042: 数列求和3 题目描述 求1-2/33/5-4/75/9-6/11...的前n项和&#xff0c;结果保留3位小数。 输入 输入正整数n(n>0)。 输出 输出一个实数&#xff0c;保留3位小数&#xff0c;单独占一行。 样例输入 5 样例输出 0.917 #include<stdio.h> int main(){in…

栈和堆,以STM32为例说明

文章目录 1. 前言2. 栈3. 堆参考 1. 前言 我们先温习一下变量的基础知识&#xff0c;啥是全局变量&#xff0c;啥是局部变量&#xff0c;这里就不赘述了。 变量的存储方式有&#xff1a;静态存储和动态存储。 静态存储方式&#xff1a;指在程序运行期间由系统分配固定的存储空…

Open3D 基于kdtree树的邻近点搜索(10)

Open3D 基于kdtree树的邻近点搜索(10) 一、算法简介二、算法实现1.K邻近点搜索2.R邻域点搜索三、结果释义一、算法简介 KD 树(k-dimensional tree)是一种用于组织 k 维空间中点的数据结构,旨在提供高效的 k 最近邻搜索和范围搜索(如半径邻域搜索)。KD 树通过递归地将空间…

Linux上对大于2T的硬盘分区

1、查看当前的分区有哪些&#xff1f; 查看机器已装载的硬盘 lsblk 释义&#xff1a; NAME 名称 MAJ:MIN 主设备号:次设备号 RM 是否可卸载设备 SIZE 容量 RO 是否只读 TYPE 类型&#xff08;disk:磁盘,part:主分区,lvm:动态分区…

DataGear专业版 1.0.0 发布,数据可视化分析平台

DataGear专业版 1.0.0 正式发布&#xff0c;欢迎大家试用&#xff01; http://datagear.tech/pro/ DataGear专业版 基于 开源版 开发&#xff0c;新增了诸多企业级特性&#xff0c;包括&#xff1a; MySQL、PostgreSQL、Oracle、SQL Server以及更多兼容部署数据库支持OAuth2…

C语言函数栈帧的创建和销毁

1.什么是函数栈帧 函数栈帧&#xff08;stack frame&#xff09;就是函数调用过程中在程序的调用栈&#xff08;call stack&#xff09;所开辟的空间&#xff0c;这些空间是用来存放&#xff1a; 函数参数和函数返回值 临时变量&#xff08;包括函数的非静态的局部变量以及编译…

【OCR】 - Tesseract OCR在mac系统中安装

Tesseract OCR 在Mac环境下安装Tesseract OCR&#xff08;Optical Character Recognition&#xff09;通常可以通过Homebrew包管理器进行。以下是安装步骤&#xff1a; 安装Homebrew 如果你还没有安装Homebrew&#xff0c;请访问 https://brew.sh/ 并按照页面上的说明安装。…

继续理解Nacos的CP和AP架构模型!

本篇文章延续文章“如何理解Nacos册CP和AP架构模型”&#xff0c;大家可以配套一起学习。 Nacos注册中心处理HTTP注册请求 在文章“如何理解Nacos册CP和AP架构模型”中已经提到过&#xff0c;Nacos注册中心用Restful API InstanceController的方法register()处理HTTP类型的注…