异步dcfifo的原理

Dcfifo即是Double clk fifo,意思是双时钟的fifo。或许你现在还不知道什么是fifo,那我就先从fifo(就是同步fifo,不过同步fifo在实际运用中比较少)开始说起吧!

scfifo的原理

一般的fifo是单时钟(读写同步),就是读写用同一个时钟信号,其框图如下:

异步dcfifo的读写-LMLPHP

端口说明如下:

异步dcfifo的读写-LMLPHP

异步dcfifo的读写-LMLPHP

异步dcfifo的读写-LMLPHP

官方的DCFIFO资料中有这样一个时序图,如下

异步dcfifo的读写-LMLPHP

    上图是写操作,下图是读操作,通过图可以看到读写的时钟频率是不一样,不过这一点没有关系,这里把读写的时钟假设为相同,就是同步fifo。

写操作中,wrreq信号为写申请信号,在写时钟的上升沿有效,将wrreq置高后就可以往fifo送数据,在写满fifo后并在时钟的上升沿,wrfull写满信号有效,表明fifo已经写满了,不能再往fifo内部写如数据,否则就会数据丢失,写了也是白费。如果要对fifo重新写入数据,这时可以通过fifo的异步清零aclr进行操作,aclr为高电平有效,能立刻将fifo内部的数据全部清零,这样就可以再往fifo写数据。

读操作中,rdreq信号为读申请信号,在读时钟的上升沿有效,将rdreq置高后就可以从fifo读数据,在读空fifo后并在时钟的上升沿,rdempty读空信号有效,表明fifo已经读空了,不能再从fifo内部读如数据。

当然,fifo中还有一些可以选择调用的信号,可以根据需要进行调用,这里就不作介绍了。

dcfifo的原理

异步dcfifo的读写-LMLPHP

端口说明如下:

异步dcfifo的读写-LMLPHP

异步dcfifo的读写-LMLPHP

异步dcfifo的读写-LMLPHP

    相信在了解了scfifo之后,已经知道fifo的原理了,dcfifo和scfifo的区别就在与读写时钟是否同步。

    异步dcfifo的读写-LMLPHP

    上图的分析上面已经讲解过了,不同的是,在dcfifo中读写时钟是不一致的,这也是很关键的一点,也是dcfifo运用比较多的一点。

在FPGA设计中经常性地会强调"同步"的问题,假设在A模块中采用的时钟频率是100M,在B模块中采用的时钟频率是50M,如果A和B要进行数据交换,由于两者的时钟不一样,所以就存在一个同步性的问题,一保证两者数据交换不会出现错误。要解决这个问题,就是解决跨时域操作的问题,跨时域交换数据最常用的就是采用dcfifo做为中间桥梁。假设为A模块往B模块送数据,则A模块以100M的时钟作为dcfifo的wrclk,往fifo写数据,而B模块则以50M的时钟频率作为dcfifo的rdclk,从fifo读数据,这就解决了跨时域交换数据的问题,当然这里面还有一些细节问题,不过相信你已经知道dcfifo的最大用处了。

异步dcfifo的调用过程

点击tools,选择调用宏功能模块的菜单,弹出下面的菜单;

异步dcfifo的读写-LMLPHP

选择新建一个新的宏功能模块,点击next,弹出下面的菜单;

异步dcfifo的读写-LMLPHP

在memory complier中选择FIFO,然后设置输出文件的名称也是这个宏功能模块的名称,然后弹出FIFO的设置向导窗口;

异步dcfifo的读写-LMLPHP

设置fifo的位宽、深度、同步和异步的选择,这里选择如上图所示,选择后点击next;

异步dcfifo的读写-LMLPHP

读fifo的潜伏期设置,这里选择最低的潜伏期,点击next;

异步dcfifo的读写-LMLPHP

选择fifo的接口信号,这里选择写端口的usedw、异步清零信号aclr,点击next;

异步dcfifo的读写-LMLPHP

选择fifo的模式,这里选择正常模式,存储资源的类型选择M4K,点击next;

异步dcfifo的读写-LMLPHP

点击Finish,调用fifo完成,接下来就是设计模块,将这个dcfifo调用起来;

读写dcfifo的控制模块设计

模块框图

异步dcfifo的读写-LMLPHP

该设计主要分为4个模块和PLL倍頻模块(提供100M的工作时钟),其中,fifo_ctrl为控制模块,负责控制对dcfifo(asy_fifo)进行读写操作,与write_fifo和read_fifo采用反馈的方式进行控制,具体方法为先控制write_fifo对asy_fifo进行写操作,write_fifo写如完成后,向fifo_ctrl反馈一个写入完成信号,fifo_ctrl便关闭对fifo的写操作,向read_fifo发送读使能的信号,read_fifo便在控制信号的控制下对fifo进行读操作,将读出的数据显示在LED上,读完成后便发送读完成信号给fifo_ctrl,fifo_ctrl在判断读操作完成后便重新对fifo进行写操作,以此循环。

其中,对asy_fifo的写时钟为100M(由PLL提供),读asy_fifo的时钟为50M(由外部晶振提供)。

各模块设计原理

这里采用至上而下的方法对整个工程进行设计:

顶层模块

顶层设计如下

异步dcfifo的读写-LMLPHP

异步dcfifo的读写-LMLPHP

fifo控制模块

fifo的控制模块根据读写的反馈信号,进行控制状态的跳转,同时输出控制信号。

上电后,控制状态为空闲态,接着转入到写状态,同时将现态的信号作为控制信号输出到write_fifo和read_fifo,在输出写控制信号后便对从write_fifo反馈的写入数量的信号进行判断,当写入了256个数据之后,便转到读状态,同时将读控制信号发送到read_fifo模块,read_fifo模块接收到读信号之后便进行读操作,读完成后便反馈读完成信号read_over,当read_over有效后,控制模块的控制状态便转到空闲态,以此循环。

异步dcfifo的读写-LMLPHP

fifo写模块

fifo写模块负责对fifo进行写操作,实际点就是发送写申请信号和发送数据,关键是什么时候进行写申请和什么时候发送什么数据,这就要听从fifo_ctrl的ctrl_signal信号,即是对ctrl_signal进行译码操作,配合着输出对fifo的写信号wrreq。

    异步dcfifo的读写-LMLPHP

    将输入的100M的clk直接输入到fifo的读时钟,将wrusedw(fifo的当前存储数量)输出到wrdata_num反馈给fifo_ctrl。

当ctrl_signal为WRITE时,写申请信号wrreq_reg有效,同时用wrdata_cnt对写入的数据数进行计数,当wrdata_cnt等于255时,fifo_ctrl将控制信号转为读状态,这时ctrl_signal为READ,wrreq_reg被清零,写操作停止,进入读操作阶段。

异步dcfifo的读写-LMLPHP

fifo读模块

fifo读模块负责对fifo进行读操作,实际点就是发送读申请信号和读取数据,关键是什么时候进行读申请和什么时候接收什么数据,这就要听从fifo_ctrl的ctrl_signal信号,即是对ctrl_signal进行译码操作,配合着输出对fifo的读申请信号rdreq。

异步dcfifo的读写-LMLPHP

读申请信号产生模块,这个模块根据ctrl_signal信号对fifo进行读申请,在READ状态时读申请信号rdreq_reg有效,其他状态无效。

异步dcfifo的读写-LMLPHP

读完成信号产生模块,在ctrl_signal为READ时开始计数,判断读取的次数是否达到256次,当达到256次时read_over输出高电平,同时read_over反馈到fifo_ctrl模块,这是current_state跳转到IDLE状态,然后进行新一轮的写读操作。

异步dcfifo的读写-LMLPHP

实验效果

实验的工程文件为"asy_fifo",其源代码文件如下:

异步dcfifo的读写-LMLPHP

为了验证实验结果,实验中调用signaltap将从fifo中读取的数据调出来进行观察,

结果如下:

异步dcfifo的读写-LMLPHP

每日推送不同科技解读,原创深耕解读当下科技,敬请关注微信公众号“科乎”。

异步dcfifo的读写-LMLPHP

05-07 15:32