数字IC手撕代码-同步FIFO
目录
原理介绍
同步FIFO的工作方式
FIFO空满的产生
计数器判断空满
代码
Dual Port RAM
sync_FIFO
testbench
波形图

原理介绍
在设计系统时,会包含工作在不同时钟频率下的元件,例如处理器和外设。数据在这些元件之间传输时先进先出(FIFO first in first out)阵列起到了重要作用。FIFO是用于对在通信总线上传输的数据进行排列的简单存储结构。
因此,FIFO常用来传输跨不同时钟域的数据。
本节介绍简单的同步FIFO架构,读写使用同样的时钟,为我们后续写异步FIFO(读写时钟非同源)做铺垫。
下面给出了一个同步FIFO的通用架构,DPRAM(Dual Port RAM 双端口RAM)作为存储器来存储信息,在此之上添加判断DPRAM空满信息的组件后,整个模块就是一个同步FIFO了,读写分别使用不同的使能和地址信号(读、写使能,读、写地址分立),使得整个模块可以进行同时读写。

图中的“状态模块”产生FIFO的空满信号,如果“fifo_full”有效,则说明FIFO内部的空间已满,不能再写入数据。如果“fifo_empty”有效,则说明FIFO内乜有可供读取的下一个有效数据。通过对读写指针位置的判断,该模块也可以指示出任意时刻FIFO中空或满区域的个数。
同步FIFO的工作方式
复位后,读写指针都归0。此时“fifo_empty”信号置为有效而“fifo_full”保持低电平。因为FIFO为空,所以阻止对FIFO的读操作,只能进行写操作。后续的写操作会增加写指针的值,并将“fifo_empty”信号置为无效。在写到最后一个数据时,写指针等于RAM_SIZE-1。此时进行一个写指针会使写指针滚回到0,并将“fifo_full”信号置为高电平。
总之,在读、写指针相等时,FIFO要么空要么满,所以需要对两种情况进行区分。
FIFO空满的产生
以深度为4的FIFO为例,一开始读写指针指向同一个位置,FIFO为空。写入三个数据之后,写指针指向RAM_SIZE-1=3的位置,此时再写入一个数据,写指针(wr_ptr)滚回0,和读指针指向同一个位置,此时FIFO为满。

fifo_full = (rd_ptr == (wr_ptr + 1'b1))&& wr_fifo
从而有判断FIFO为满的RTL 代码:
类似的,当读操作使得两个指针在下一个时钟相等时,FIFO变空,产生“fifo_empty”信号。有如下关系:无论读写指针此时指向什么位置,当rd_ptr+1==wr_ptr时,FIFO再读出一个数据就空了。
fifo_empty = (wr_ptr == (rd_ptr + 1'b1))&& rd_fifo
从而有判断FIFO为空的RTL 代码:
计数器判断空满
FIFO还有另一种利用计数器来指示FIFO空满的方法。
计数器的宽度要与FIFO的深度相等,这样计数器才能记录FIFO数据的最大个数。计数器在复位时初始化为0,随后的任何写操作会将其递增1,任何读操作会使其递减1。
在计数器为0时,很容易判断FIFO处于空状态,而当计数器的值等于FIFO的大小时,就能判断FIFO处于满状态。
对于这种采用计数器来判断空满的方式实现比较简单,但是和上一个比较读写指针位置的方法相比资源占用会高一些。因为这种方法要求增加额外的硬件(计数器)来进行计数。
代码
简单来说,FIFO就是一个有判断空满逻辑的双端口RAM,下面我们来写一下以指针循环一周期判断空满的方式的同步FIFO,但是在之前我们先要写一个双端口RAM来存储数据。
Dual Port RAM
整个双端口RAM其实就是一个简单的写使能时,把数据写入输入的写地址。读使能时,把数据从地址里读出来的那么一个功能,后续在FIFO中例化该Dual Port RAM模块。
sync_FIFO
此外,还写了一个判断位宽的函数clog.v
testbench
波形图

仿真结果和分析的结果一致, 写入16个数据将FIFO写满,此时full信号拉高;读出16个数据将FIFO读空,此时empty信号拉高;写入8个数据之后,同时读写,写入数据和读出数据均保持一致,功能正确。
了解了同步FIFO的设计方法后,再进行异步FIFO的设计就比较简单了,下篇博客记录如何写一个异步FIFO,解决FIFO中跨时钟域的问题。