异步FIFO理解及设计

一、异步FIFO理解

1.1异步FIFO结构

由图可见,异步FIFO的核心部件就是一个 Simple Dual Port RAM ;左右两边的长条矩形是地址控制器,负责控制地址自增、将二进制地址转为格雷码以及解格雷码;下面的两对D触发器 sync_r2w 和 sync_w2r 是同步器,负责将写地址同步至读时钟域、将读地址同步至写时钟域。 

1.2异步FIFO空满的判断 

        在同步FIFO设计中,fifo_num是由写地址减去读地址所得到,利用fifo_num 来作为FIFO空或满的判断依据。而对于异步FIFO而言,数据是由某一个时钟域的控制信号写入FIFO,而由另一个时钟域的控制信号将数据读出FIFO。也就是说,读写指针的变化动作是由不同的时钟产生的,处在不同的时钟域上,所以不能直接相减。因此,对FIFO空或满的判断也是跨时钟域的,我们首先需要解决的就是如何进行异步FIFO空满的判断。

        对于异步FIFO 而言,我们用wr_num和rd_num(对应同步FIFO中的fifo_num)作为读写时钟域各自维护的一套数据计数器。wr_num作为FIFO写满的判断依据,rd_num作为FIFO读空的判断依据。为了得到wr_num,写地址wr_ptr_exp与其处于同一时钟域(写时钟域),然后,读地址rd_ptr_exp则需要从读时钟域同步到写时钟域才能使用,若没有同步,wr_num则会出现亚稳态,从而影响full和almost_full的指示信号,造成数据的丢失。同理,对于rd_num来讲,我们需要将写地址同步到读时钟域来进行rd_num的计算。

  • “写满”的判断:需要将读指针同步到写时钟域,再与写指针判断
  • “读空”的判断:需要将写指针同步到读时钟域,再与读指针判断

1.2.1跨时钟域:读慢写快  、 读快写慢  

  •  判断写满:(虚满:因为实际读地址>=同步后的地址)

(1)读慢写快:读地址同步到写时钟域后(快时钟采样慢时钟信号),经过两级触发器的时间消耗,实际的读地址一定是大于等于同步到写时钟域之后的读地址(用于wr_num计算,判断FIFO是否读满),此时若wr_num判断FIFO写满(实际写指针未超过读指针一圈),即满非真满。可以想象一下,假设一个深度为100的FIFO,在写到第98个数据的时候就报了“写满”,会引起什么后果?答案是不会造成功能错误,只会造成性能损失(2%),大不了FIFO的深度我少用一点点就是的。只会造成性能损失。 

  •  判断读空:(虚空:实际写地址>=同步后的地址)

(1)读快写慢:同理,写地址同步到读时钟域后(快时钟采样慢时钟信号),实际的写地址一定是大于等于同步到读时钟域之后的写地址(用于rd_num计算,判断FIFO是否读空),此时若rd_num判断FIFO读空(实际读指针未赶上写指针),即空非真空。可以想象一下,假设某个FIFO,在读到还剩2个数据的时候就报了“读空”,会引起什么后果?答案是不会造成功能错误,只会造成性能损失(2%),大不了我先不读了,等数据多了再读就是的。 

上面两种情况都是慢时钟域信号同步到快时钟域,我们采取打两拍可以正常进行FIFO功能,但是对于快同步到慢是否会有问题,即快时钟域的信号同步到慢时钟域造成的漏采  ?

  •  判断写满: (虚满:漏掉读指针,对于写满来说,实际读指针跑到了前面)

(2)读快写慢: 进行写满判断的时候需要将读指针同步到写时钟域,因为读快写慢,所以当写时钟同步读指针的时候,必然会漏掉一部分读指针,我们不用关心那到底会漏掉哪些读指针,我们在乎的是漏掉的指针会对FIFO的写满产生影响吗?比如读指针从0读到10,期间写时钟域只同步捕捉到了3、5、8这三个读指针而漏掉了其他指针。当同步到8这个读指针时,真实的读指针可能已经读到10 ,相当于在写时钟域还没来得及觉察的情况下,读时钟域可能从FIFO读了数据出来,这样在判断它是不是满的时候会出现不是真正满的情况,漏掉的指针也没有对FIFO的逻辑操作产生影响。

  •  判断读空:(虚空:漏掉写指针,对于读空来说。实际的写指针跑到了前面)

(2)读慢写快: 进行读空判断的时候需要将写指针同步到读指针 ,因为读慢写快,所以当读时钟同步写指针的时候,必然会漏掉一

### 异步FIFO深度设计原理 异步FIFO设计目的是为了平衡不同频率域之间的数据传输速率差异,防止因读写速度不匹配而导致的数据丢失。通过设置合理的FIFO深度,可以确保即使在瞬态负载下也能维持稳定的数据流[^1]。 对于异步FIFO而言,其工作环境涉及两个独立时钟域——读时钟和写时钟。这两个时钟可能具有不同的频率甚至相位关系,因此需要特别注意如何同步来自不同时间基准的信息。为了避免跨时钟域转移过程中可能出现的竞争条件(Metastability),通常会在边界处加入多级寄存器来隔离这些潜在的风险因素[^2]。 ### 避免使用奇数深度的原因 针对为何避免使用奇数值作为FIFO深度这一问题,在具体实现上主要是出于简化逻辑复杂度以及提高可靠性的考量: - **地址指针表示法**:当采用二进制编码方案时,如果允许任意长度,则意味着每次跨越半个周期都需要特殊处理;而对于偶数长度来说,正好对应着完整的半周期变化范围,使得判断满/空状态更加直观简单。此外,某些情况下还会引入额外的一位用于指示循环结束的状态转换,这同样适用于幂次方形式的容量设定[^4]。 - **格雷码的应用场景**:虽然不是直接原因,但在一些高级应用中确实存在利用格雷码代替传统二进制的情况。由于格雷码特性决定了相邻两组代码间仅有一位发生变化,这样有助于减少毛刺现象的发生几率,进而提升系统的稳定性。然而值得注意的是,这种做法更多体现在优化而非强制规定方面[^3]。 综上所述,选择偶数或者更进一步地说是2^n这样的结构化尺寸不仅能够降低硬件资源消耗,还能增强整体架构的安全性和可维护性。 ```cpp // 示例C++伪代码展示了一个简单的FIFO类定义 class FIFO { private: int *buffer; // 数据存储区 size_t head = 0; // 写入位置索引 size_t tail = 0; // 读取位置索引 public: bool isFull() const { /* ... */ } bool isEmpty() const { /* ... */ } }; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值