1)实验平台:正点原子新起点V2开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=609758951113 2)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-300792-1-1.html 3)对正点原子FPGA感兴趣的同学可以加群讨论:994244016 4)关注正点原子公众号,获取最新资料更新
第二十章IP核之FIFO实验 FIFO的英文全称是First In First Out,即先进先出。FPGA使用的FIFO一般指的是对数据的存储具有先进先出特性的一个缓存器,常被用于数据的缓存或者高速异步数据的交互,也即所谓的跨时钟域信号传递。它与FPGA内部的RAM和ROM的区别是没有外部读写地址线,采取顺序写入数据,顺序读出数据的方式,使用起来简单方便,由此带来的缺点就是不能像RAM和ROM那样可以由地址线决定读取或写入某个指定的地址。本章我们将对Quartus II软件生成的FIFO IP核进行读写测试,来向大家介绍Altera FIFO IP核的使用方法。 本章包括以下几个部分: 2020.1简介 20.2实验任务 20.3硬件设计 20.4程序设计 20.5下载验证 20.1简介 FIFO从输入时钟的角度来分,有两种类型:单时钟FIFO(SCFIFO)和双时钟FIFO(DCFIFO),其中双时钟FIFO又可从输出数据的位宽的角度分为普通双时钟(DCFIFO)和混合宽度双时钟FIFO(DCFIFO_MIXED_WIDTHS)。单时钟FIFO和双时钟FIFO的符号图如图 20.1.1所示。从图中可以看到,单时钟FIFO具有一个独立的时钟端口clock,因此所有的输入输出信号都同步于clock信号。而在双时钟FIFO结构中,写端口和读端口分别有独立的时钟,所有与写相关的信号都是同步于写时钟wrclk,所有与读相关的信号都是同步于读时钟rdclk。在双时钟FIFO的符号图中,位于图中上侧部分的以“data”和“wr”开头的信号为与写相关的所有信号,位于中间部分的“q”和以“rd”开头的信号为与读相关的所有信号,位于底部的为异步清零信号。
图 20.1.1 单时钟 FIFO 与双时钟 FIFO 的符号图 对于FIFO需要了解一些常见参数: FIFO的宽度:FIFO一次读写操作的数据位N; FIFO的深度:FIFO可以存储多少个宽度为N位的数据。 空标志:对于双时钟FIFO又分为读空标志rdempty和写空标志wrempty。FIFO已空或将要空时由FIFO的状态电路送出的一个信号,以阻止FIFO的读操作继续从FIFO中读出数据而造成无效数据的读出。 满标志:对于双时钟FIFO又分为读满标志rdfull和写满标志wrfull。FIFO已满或将要写满时由FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO中写数据而造成溢出。 读时钟:读FIFO时所遵循的时钟,在每个时钟的上升沿触发。 写时钟:写FIFO时所遵循的时钟,在每个时钟的上升沿触发。 对于FIFO的基本知识先了解这些就足够了,可能有人会好奇为什么会有单时钟FIFO和双时钟FIFO,它们各自的用途是什么。之所以有单时钟FIFO和双时钟FIFO是因为各自的作用不同。单时钟FIFO常用于同步时钟的数据缓存,双时钟FIFO常用于跨时钟域的数据信号的传递,例如时钟域A下的数据data1传递给异步时钟域B,当data1为连续变化信号时,如果直接传递给时钟域B则可能会导致收非所送的情况,即在采集过程中会出现包括亚稳态问题在内的一系列问题,使用双时钟FIFO能够将不同时钟域中的数据同步到所需的时钟域中。 20.2实验任务 本节实验任务是使用Quartus II生成FIFO IP核,并实现当FIFO为空时就开始向FIFO中写入数据,直到FIFO写满为止;当FIFO为满时则开始从FIFO中读出数据,直到FIFO读空为止的功能,来向大家详细介绍一下FIFO IP核的使用方法。 20.3硬件设计 本章实验只用到了输入的时钟信号和按键复位信号,没有用到其它硬件外设。 本实验中,各端口信号的管脚分配如下表所示。 因为引脚数极少这里不再给出TCL文件。 20.4程序设计 根据实验任务要求和模块化设计的思想,我们需要如下5个模块:fifo模块、写fifo模块、读fifo模块、PLL IP核模块以及顶层模块,顶层模块例化了其余模块实现前四个模块的数据交互。由于FIFO多用于跨时钟域信号的处理,所以本实验我们使用双时钟FIFO来向大家详细介绍双时钟FIFO IP核的创建和使用,我们使用两个不同的时钟分别作为RAM的写时钟和读时钟,这两个时钟由PLL IP核生成,输出的时钟分别是50Mhz和25Mhz。系统的功能框图如下所示:
图 20.4.1 系统框图 接下来我们创建一个名为ip_fifo的工程,在这里我们就不再给出Quartus II软件创建工程的详细过程,如果大家对Quartus II软件的创建过程还不熟悉的话,可以参考“第四章 Quartus II软件的安装和使用”章节中的Quartus II软件的使用部分。新建后的工程如下所示:
图 20.4.2 工程新建完成页面 创建好了工程以后,接下来我们创建FIFO IP核。我们在Quartus II软件的菜单栏中找到【Tools】→【MegaWizard Plug-In Manager】按钮并点击打开,Tool工具栏打开面及打开后弹出的页面如图 20.4.3和图 20.4.4所示。
图 20.4.3 工具栏打开IP核页面
图 20.4.4 创建IP核向导页面 在该页面中,可以看到有三个选项,第一个是创建一个新的IP核,第二个是编辑一个已经创建好的IP核,第三个是复制一个已经创建好的IP核。因为我们这里是首次创建IP核,因此直接选择默认的第一个选项,然后点击【Next>】,进入如图 20.4.5所示页面。
图 20.4.5 选择FIFO IP核页面 在该页面中,我们可以在Memory Compiler下找到FIFO IP核,也可以直接在搜索框中输入FIFO找到它。我们找到FIFO IP核以后,单击选中它,然后我们需要选择FIFO IP核保存的路径及名称。首先大家在工程所在路径par文件夹下创建一个文件夹ipcore,由于本次实验会用到多个IP核,为了方便管理IP核,我们在ipcore文件夹下创建一个async_fifo文件夹,用于存放FIFO IP核(如果之前没有创建ipcore和async_fifo文件夹的话)。 接下来在“What name do you want for the output file”一栏中输入IP存放的路径及名称,这里我们命名为async_fifo并且选择创建的IP核代码为Verilog HDL(默认为Verilog HDL)。完成这些设置以后,我们点击【Next>】,进入如图 20.4.6所示页面。
图 20.4.6 FIFO IP核模式配置页面 How wide should the FIFO be:设置FIFO的位宽,这里我们选择8bits; How deep should the FIFO be:设置FIFO的深度,也就是能存放多少个指定位宽的数据,这里我们选择256words,这样设置以后FIFO的容量大小为256个8bits; Do you want a common clock for reading and writing the FIFO:设置FIFO的驱动时钟类型,可以选择单时钟FIFO或者双时钟FIFO。FIFO一般用来实现数据的缓存和跨时钟的处理,因此我们选择双时钟FIFO。 选择完之后,我们直接点击【Next>】,进入如图 20.4.7所示页面。
图 20.4.7 DCFIFO1配置页面 从该页面的“Which type of optimization do you want?”我们可以看出,该页面主要是用于对我们的DCFIFO进行优化的,在箭头1、2、3所指处有三种针对读时钟同步、亚稳态保护、面积和速度的优化类型,下面我们简单的介绍一下这三种优化类型: Lowest latency but requires synchronized clocks(最低延迟,但要求同步时钟):此选项使用一个同步阶段,没有亚稳态保护,适用于同步时钟。它是最小尺寸,提供良好的Fmax。 TYPE_Cmal setting for unsynchronized clocks(异步时钟时的最小设置):这个选项使用两个同步阶段,具有良好的亚稳态保护。它是中等尺寸,提供良好的Fmax。 Best metastability protection, best fmax and unsynchronized clocks(异步时钟时最好的亚稳态保护,最好的Fmax,不同步):这个选项使用三个或更多的同步阶段,具有最好的亚稳态保护。它是最大尺寸,给出了最好的Fmax。 在使用过程中,通常我们选择的是默认的中等优化,具体的优化主要还是看你的工程的要求,假如你的工程对速度和稳定性要求很高,同时资源又很多,那么你就可以使用第三个选项,假如你的工程资源很紧张,那么你可以选择使用第一个资源少的优化。在此我们保持默认的设置,直接点击【Next>】,进入如图 20.4.8所示页面。
图 20.4.8 DCFIFO2配置页面 该页面用于选择可选的输出控制信号,从读方(Read side)和写方(Write side)分别进行选择。下面我们简单的介绍一下: rdfull和wrfull:FIFO满的标记信号,为高电平时表示FIFO已满,此时不能再进行写操作。 rdempty和wrempty:FIFO空的标记信号,为高电平时表示FIFO已空,不能在进行读操作。 rdusedw[]和wrusedw[]:显示存储在FIFO中数据个数的信号。 Add an extra MSB to usedw ports:将rdusedw和wrusedw数据位宽增加1位,用于保护FIFO在写满时不会翻转到0。 Asynchronous clear:异步复位信号,用于清空FIFO。 这里我们选择读空、读满、读侧数据量和写空、写满信号、写侧数据量,并勾选使能异步复位,然后继续点击【Next>】,进入如图 20.4.9所示页面。
图 20.4.9 Rdreq Option,Blk Type的配置页面 该页面用于选择输出模式和存储器类型。最上面的红框选择输出模式,输出模式有两种:正常模式和前显模式。对于正常模式,FIFO将端口rdreq看做正常的读请求并在该端口信号为高电平进行读操作。对于前显模式,FIFO将端口rdreq看做读确认信号,将rdreq信号置为高电平时将输出FIFO中的下一个数据字(如果存在)。如果使用前显模式,将会使设计性能下降。这里我们使用默认值:正常模式。 接下来的红框用于指定实现存储器使用的存储块类型和存储器的存储深度,具体可选值与使用的FPGA芯片有关,默认为Auto,我们一般使用默认值就可以了,所以这里直接点击【Next>】,进入如图 20.4.10所示页面。
图 20.4.10 Optimization,Circuitry Protection 的配置页面 该页面主要用于选择是否禁止上溢检测和下溢检测的保护电路。如果你不需要上溢检测和下溢检测保护电路,那么你可以通过Disable来禁止它们,以此来提高我们的FIFO性能。 上溢检测保护电路主要是用于在FIFO满时禁止wrreq端口,下溢检测保护电路主要是用于在FIFO空时,禁止rdreq端口,它们默认的状态是打开的。这里我们使用默认设置。 “Implement FIFO storage with logic cells only, even if the device contains memory blocks?”选项使用逻辑单元实现FIFO存储器,即使器件拥有存储块。这里使用默认设置,用存储块实现FIFO。 然后直接点击【Next>】,进入如图 20.4.11所示页面。
图 20.4.11 第一个输出时钟c0配置页面 从该页面中,我们可以看出,如果我们想要仿真FIFO IP核,那么我们就需要用到“altera_mf”这个仿真库。如果我们想要将此FIFO IP核用在其他的EDA工具上,我们可以通过选择“Generate netlist”这个选项来生成IP_syn.v文件,用于其他的EDA工具中。这里需要注意的是,并不是所有的第三方EDA工具都支持。点击【Next>】,进入如图 20.4.12所示页面。
图 20.4.12 Summary 的配置页面 在该页面,我们可以看到,该IP核能生成的所有文件都在该页面中,在这么多的文件中,我们只要选择FIFO_inst.v文件就可以了,方便对FIFO的例化。至此,关于FIFO IP核的配置就讲解完了。然后我们点击【Finish】完成整个IP核的创建。接下来Quartus II软件会在ipcore文件夹下创建FIFO的IP核文件,然后询问我们是否添加至工程,点击“YES”按钮将生成的IP核添加至工程,如下图所示页面。
图 20.4.13 IP核添加至工程确认界面 接下来返回到工程界面,在File界面里,我们可以看到生成的fifo.qip已经添加到工程中,如图 20.4.14所示界面。
图 20.4.14 FIFO添加至工程界面 打开async_fifo.v文件,我们可以看到使用Modelsim对fifo文件进行仿真时需要添加一个名为altera_mf的仿真库,如下图所示:
图 20.4.15 FIFO_clk文件注释说明 至此,FIFO IP核的创建已经全部完成,如果需要修改IP核的话,点击在Quartus II软件的菜单栏中找到【Tools】→【MegaWizard Plug-In Manager】按钮并点击打开,图 20.4.16为打开后的页面。
图 20.4.16 修改IP核页面 和我们第一次创建IP核不同的是,这一次我们选择第二个选项,修改已经存在的IP核,然后点击【Next>】,进入选择IP核路径页面,双击ipcore文件夹,进入如图 20.4.17所示页面。然后双击fifo.v文件,点击【Next>】开始重新配置FIFO IP核。
图 20.4.17 选择需要修改的IP核路径页面 除此之外,我们再创建一个PLL IP核(命名为pll_clk),共输出两路时钟,时钟频率分别是50Mhz和25Mhz,存放路径为par/ipcore/pll_clk,创建过程此处不再赘述。 接下来我们设计一个verilog文件来对FIFO写入数据,文件名为fifo_wr.v,编写的verilog代码如下:
1 module fifo_wr(
2 input clk, //时钟信号
3 input rst_n, //复位信号
4
5 //fifo的写端口
6 input wr_full, //写侧满信号
7 input wr_empty, //写侧空信号
8 output wr_req, //写请求信号
9 output reg [7:0] wr_data //写入FIFO的数据
10 );
11
12 //reg define
13 reg wr_req_t;
14
15 //*****************************************************
16 //** main code
17 //*****************************************************
18
19 //防止fifo写满后继续写入数据
20 assign wr_req = wr_req_t & (~wr_full);
21
22 //wr_req_t信号赋值
23 always @(posedge clk or negedge rst_n) begin
24 if(!rst_n)
25 wr_req_t
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?