1.FIFO IP核简介
根据FIFO 工作的时钟域,可以将FIFO 分为同步FIFO 和异步FIFO。同步FIFO 是指读时钟和写时钟为同一个时钟,在时钟沿来临时同时发生读写操作。异步FIFO 是指读写时钟不一致,读写时钟是互相独立的。Xilinx 的FIFO IP 核可以被配置为同步FIFO 或异步FIFO,其信号框图如下图所示。从图中可以了解到,当被配置为同步FIFO 时,只使用wr_clk,所有的输入输出信号都同步于wr_clk 信号。而当被配置为异步FIFO时,写端口和读端口分别有独立的时钟,所有与写相关的信号都是同步于写时钟wr_clk,所有与读相关的信号都是同步于读时钟rd_clk。
对于FIFO 需要了解一些常见参数:
FIFO 的宽度:FIFO 一次读写操作的数据位N;
FIFO 的深度:FIFO 可以存储多少个宽度为N 位的数据。
空标志:empty。FIFO 已空时由FIFO 的状态电路送出的一个信号,阻止FIFO 的读操作继续从FIFO中读出数据而造成无效数据的读出。
满标志:full。FIFO 已满或将要写满时由FIFO 的状态电路送出的一个信号,以阻止FIFO 的写操作继续向FIFO 中写数据而造成溢出。
读时钟:读FIFO 时所遵循的时钟,在每个时钟的上升沿触发。
写时钟:写FIFO 时所遵循的时钟,在每个时钟的上升沿触发。
2.FIFO IP核的使用
根据实验任务要求和模块化设计的思想,我们需要如下4 个模块:fifo IP 核、写fifo 模块、读fifo 模块以及顶层例化模块实现前三个模块的信号交互。由于FIFO 多用于跨时钟域信号的处理,所以本实验我们使用异步FIFO 来向大家详细介绍双时钟FIFO IP 核的创建和使用。为了方便大家理解,这里我们将读/写时钟都用系统时钟来驱动。系统的功能框图如下图所示:
首先创建一个名为ip_fifo 的工程,接下来我们创建fifo IP 核。在Vivado 软件的左侧“Flow Navigator”栏中单击“IP Catalog”,在“IP Catalog”窗口中,在搜索栏中输入“fifo”关键字,这时Vivado 会自动查找出与关键字匹配的IP 核名称,我们双击“FIFO Generator”,如下图所示。
弹出“Customize IP”窗口,如下图所示。
接下来就是配置IP 核的时钟参数的过程。
最上面的“Component Name”一栏设置该IP 元件的名称,这里保持默认即可。在第一个“Basic”选项卡中,“Interface Type”选项用于选择FIFO 接口的类型,这里我们选择默认的“Native”,即传统意义上的FIFO接口。“Fifo Implementation”选项用于选择我们想要实现的是同步FIFO 还是异步FIFO 以及使用哪种资源实现FIFO,这里我们选择“Independent Clocks Block RAM”,即使用块RAM 来实现的异步FIFO。如下图所示。
接下来是“Native Ports”选项卡,用于设置FIFO 端口的参数。
“Read Mode”选项用于设置读FIFO时的读模式,这里我们选择默认的“Standard FIFO”。
“Data Port Parameters”一栏用于设置读写端口的数据总线的宽度以及FIFO 的深度,写宽度“Write Width”我们设置为8 位,写深度“Write Depth”我们设置为256,注意此时FIFO IP 核所能实现的实际深度却是255;虽然读宽度“Read Width”能够设置成和写宽度不一样的位宽,且此时读深度“Read Depth”会根据上面三个参数被动地自动设置成相应的值;但是我们还是将读宽度“Read Width”设置成和写宽度“Write Width”一样的位宽,这也是在实际应用中最常用的情况。
由于我们只是观察FIFO 的读写,所以最下面的“Reset Pin”选项我们可以不使用,把它取消勾选。其他设置保持默认即可,如下图所示。
“Status Flags”选项卡,用于设置其他的边带信号,这里我们并不使用它们,保持默认即可,如下图所示。
“Data Counts”选项卡用于设置FIFO 内数据计数的输出信号,此信号表示当前在FIFO 内存在多少个有效数据。为了更加方便地观察读/写过程,这里我们把读/写端口的数据计数都打开,且计数值总线的位宽设置为满位宽,即8 位(根据你的深度所定),如下图所示。
最后的“Summary”选项卡是对前面所有配置的一个总结,在这里我们直接点击“OK”按钮即可,如下图所示。
接着就弹出了“Genarate Output Products”窗口,我们直接点击“Generate”即可,如下图所示。
之后我们就可以在“Design Run”窗口的“Out-of-Context Module Runs”一栏中出现了该IP 核对应的run“fifo_generator_0_synth_1”,其综合过程独立于顶层设计的综合,所以在我们可以看到其正在综合,如下图所示
在其Out-of-Context 综合的过程中,我们就可以进行RTL 编码了。首先打开IP 核的例化模板,在“Source”窗口中的“IP Sources”选项卡中,依次用鼠标单击展开“IP”-“fifo_generator _0”-“Instantitation Template”,我们可以看到“fifo_generator_0.veo”文件,它是由IP 核自动生成的只读的verilog 例化模板文件,双击就可以打开它,如下图所示
我们对代码进行仿真,TestBench 中只要送出时钟的复位信号即可。写满后转为读的仿真波形图如下图所示:
由波形图可知,当写满255 个数据后,fifo_full 满信号就会拉高。经过延时之后,fifo_rd_en 写使能信号拉高,经过一拍之后就开始将fifo 中的数据送到fifo_dout 端口上。写满后转为读的仿真波形图如下图所示:
由波形图可知,当读完255 个数据后,fifo_empty 空信号就会拉高。经过延时之后,fifo_wr_en 写使能信号拉高,经过一拍之后就开始向fifo 中继续写入数据。