我是靠谱客的博主 斯文老虎,最近开发中收集的这篇文章主要介绍如何实现异步FIFO,听小哥给你说说,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

65756d2162c6655ed4207470828e3957.png

\插播一条:

自己在今年整理一套单片机单片机相关论文800余篇

论文制作思维导图

原理图+源代码+开题报告+正文+外文资料

想要的同学私信找我。

f11432c95d955420f241273da162ef0c.png

异步FIFO的实现(从verilog代码到波形)

一、 异步fifo的简单介绍

我们知道,fifo最简易的构造能够由一个DPRRAM达到,只不过fifo不须要地址,每个数据的存取位置都是顺序变化的(遵守先进先出的原则),这一点是与正常的存储器不同的地方。

在设计之前,首先须要明白以下这些问题:

1.何为同步和异步?

首先要理清我们所说的“同步”与“异步”的关系。上一篇文章也有提到,“同步”是指时序逻辑的信号变化是基于同一个时钟。若信号是基于不同的时钟变化,假如clk1和clk2(这两个时钟没有确定的相位关系)称为异步。所以,这里所说的异步fifo则是读时钟和写时钟为异步的fifo。对于异步fifo,其中有一个很重要的点在于“跨时钟域处理”。

在处理器和外设之间,一般处理器的数据吞吐率很高,运用异步fifo就能避免这种速度差异造成的数据丢失问题

2.为什么要跨时钟域处理呢?

由于在同步fifo中,我们知道,产生空满信号时依据fifo_cnt计数产生。但是在异步fifo中,读指针在读时钟域,写指针在写时钟域,所以不能单独运用一个计数器去产生空满信号了。因此,我们须要将写指针同步到读时钟域去产生空信号,将读指针同步到写时钟域去产生满信号。

跨时钟域处理会面临什么问题呢?——建设时长和保持时长的违背,从而产生亚稳态。在两个时钟域的情况下,很容易出现一个时钟域的输出在另外一个时钟域中的时钟回升沿到来时发生变更的现象,从而产生亚稳态。

3.如何进行跨时钟域处理?

上小节提到同步,这里首先介绍“同步器”,对于单bit信号:从慢时钟到快时钟,我们能够通过同步器进行打拍的方式进行同步。假如同步器的第一级触发器产生亚稳态输出,这个亚稳态将在第二级触发器取样前稳定,如图1和图2所示。增加更多级触发器,能够进一步降低亚稳态出现的可能性(但会带来的问题是增加了整体电路的时延)。从快时钟到慢时钟,可能会存在数据丢失的情况,必需将源数据进行展宽,以保证在两个不间断变化的源数据之间至少有一个宗旨时钟到达。

2b3b360028c0976e12bf28b8d4af99e3.png图17a5bffc57cf82dcacd4ed4c2ceafb6b2.png图2

但是对于多bit信号,不能直接通过同步器去达到同步,可能导致错误采样。假如FFF到000转换时,每一位数据都在变化,由于每个bit的延时不同,最后可能采到的数据是001、010、100等。 因此,须要避免运用二进制计数器达到指针。

考虑到格雷码具有一定的特殊性:每次当从一个值变化到另外一个值时,有且独有一位发生变化。因此能够运用格雷码去取代二进制计数器,并且用打拍的方式去同步(独有深度为2的n次方才能用格雷码的方式去同步,这样才能保证最大值和最小值独有一位的变化)。我们能够将指针转为格雷码同步到另一个时钟域再进行比较。假如同步时钟在计数值转换期间到来,这种编码能够打消绝大局部的错误。

4.在进行同步之后,如何产生空满信号呢?

空信号:读指针即是写指针(复位时,或者读指针追上写指针)

满信号:写指针即是读指针(写更快,写完一圈追上读指针)

为了避免读写指针相同时,不知道到底是满还是空,因此在读写指针中额外增加一位,这一位用于表示是否已经发生回环,但这一位不须要存入memory中。

假如采用二进制的办法去比照指针,产生空满信号(空信号为读写指针完全相同,满信号为除最高位其余位相同),则设计时须要四个格雷码到二进制码转换器;倘若直接运用格雷码产生空满信号,能够发现,格雷码具有一定的对称性,即四位格雷码后半段与前半段高两位相反(低两位相同),如图2所示。

c94b66ca84539cc4f1a70b0fa2af5afe.png图3

5.补充自然二进制和二进制格雷码之间的相互转换公式:

二进制转格雷码:最高位保留,其他各位为该位的二进制码异或上一位的二进制码。

格雷码转二进制:最高位保留,其余各位为该位的格雷码异或上一位的二进制码。

二、 异步fifo的verilog设计

1.首先定义参数(和同步fifo一样)、异步fifo的接口信号,另外定义了一个内部参数:地址位宽。

c13b12396fa4e7c6e3f30987050bb778.png

2.定义内部信号,这些信号后面都要用到,写的时候也不必一初始就全部写全,须要用到的时候在补充。这些内部信号分别是:读(写)地址、下一个读(写)地址;写(读)地址的格雷码、下一个写(读)地址的格雷码、写(读)地址格雷码的读(写)同步;读(写)地址的格雷码的写(读)同步的二进制码。以及fifo用于读(写)所用的个数。以上这些信号将用于产生空满信号。另外还有读写有效等(用于传递给dualport_ram)。

ac90703adccb4e933767b0d34af2661f.png

3.产生读写有效信号(往memory中写或者读的有效信号):写有效发生在写使能为1且未满的情况,读有效发生在读使能为1且非空的情况。此时另外设计了一个双端口的ram,在本设计中直接调用即可。

38ca9547026082ae9281a34a144d195b.png

4.接下来对读写地址进行控制。写有效时,下一个写地址加1(为组合逻辑),在由写时钟将下一个写地址赋给当前写地址。读地址的控制类似。

2568ed89fbdef0d015ea986aa99c0e38.png

5.产生下一位写地址格雷码(下一位写地址右移一位异或本身),并用寄存器存起来。下一位读地址格雷码的产生也类似。

a710ab60c0f945d4fd47a055a5d42027.png

6.将读地址同步到写时钟(用于产生满信号),将写地址同步到读时钟(用于产生空信号)。达到方式详细是:通过将读地址的格雷码在写时钟域进行打两拍,写地址的格雷码在读时钟域进行打两拍,并用寄存器存起来。

5e7223f34a42fc3b0072f66df80d6339.png420751620a2642d718783a01403bbea8.png

7.好啦,到这里我们终于能够用我们前面准备好的信号去产生空满信号了。先准备好一个full_comb(组合逻辑的满),由于组合逻辑的满是早于时序逻辑的满,因此组合逻辑的满的产生我们用的下一时刻的地址。当下一个写地址的格雷码和读地址的格雷码的写同步的高两位相反,低两位相同的时候为1。在基于写时钟将full_comb赋值给full。另一方面,empty_comb当下一个读地址的格雷码与写地址格雷码的读同步相同时为1,并基于读时钟赋给empty信号。

34051b96adc3b60d485d2056f7790d4d.png

8.之后,产生简直满(afull)信号。由于此时我们须要统计fifo已经占用多少个存储单元,因此我们要做差,而做差操作二进制更容易达到,因此我们将地址转为二进制。

已占用的存储单元个数=下一个写地址-读地址的格雷码的写同步的二进制码

当其大于存储单元数-1时,产生组合逻辑的简直满信号,在写时钟下产生时序逻辑的简直满信号。简直空信号(aempty)的产生思维类似。

0c70564e9f457c0da7c873213a5f0156.pngb9d6d717bbedffa5750ed54f1c8b9347.png

哇!长舒一口气,我们的异步fifo的模块的设计部分就完成啦!238行代码,比同步fifo确实多了不少。由于篇幅有点长了,dualpot_ram设计、tb搭建和波形下期再见吼!

413b973d89932107ceae6c7151a43bd6.pngdffb0642493208621a4d545e1adb9b18.pngb8452afb35bab34bef321af1bc14936d.png

想要学习单片机的朋友 ,做毕业设计的同学,关注我们,口令小哥,与导师一起学习成长,共同进步,还有更多资料领取。

说了这么多,大家记得留意下方评论第一条(或者私信我)有干货~

-END-

*本文系网络转载,版权归原作者所有,如有侵权请联系删除

最后

以上就是斯文老虎为你收集整理的如何实现异步FIFO,听小哥给你说说的全部内容,希望文章能够帮你解决如何实现异步FIFO,听小哥给你说说所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(40)

评论列表共有 0 条评论

立即
投稿
返回
顶部