一文看懂异步 FIFO 架构(一) 单时钟的异步 FIFO

本文转载自:Linest-5的CSDN博客

注:本文由作者授权转发,如需转载请联系作者本人

FIFO 的用途
首先, FIFO 通常用于跨时钟域,因此是双时钟设计。换句话说,该设计使用两个时钟,因此最常见的情况是设计的 FIFO 没有假定这两个时钟之间的关系。但是,我们不会从这样的架构开始我们将从仅在一个时钟上运行的 FIFO 的简单情况开始。我想这样的电路在实践中的用途有限,但它非常有用,可以为更复杂的设计奠定基础。

单时钟 FIFO 的例子
FIFO 有几种可能的架构。其中包括波纹 FIFO、移位寄存器和其他我们不太关心的架构。我们将专注于涉及随机存取存储器阵列的架构。这样的架构如图 1 所示。

FIFO 空满信号
我们看到有一个具有独立读写端口的 RAM 阵列。这是为了方便而选择的。如果您有一个单端口内存,则必须包含一个仲裁器,该仲裁器可以一次授予对一个操作(读取或写入)的访问权限。我们选择双端口 RAM(不一定是真正的双端口,因为我们只是想要一个单独的读写端口),因为这些说明了更现实的情况。

读写端口具有独立的读写地址,由两个宽度为log2(array_size) 的计数器生成。我们现在不太关心数据宽度,但这确实成为以后选择架构的重要参数。为了一致性,我们将这些计数器称为“读指针”和“写指针”。写指针指向下一个将被写入的位置,而读指针指向接下来要读取的位置。写增加写指针,读增加读指针。

我们看到的最后一个块是“状态”块。该模块的职责是向 FIFO 生成“空”和“满”信号。这些信号告诉外界 FIFO已达到终端条件:如果“full”处于拉高状态,则 FIFO 已达到写入终止条件,如果“empty”处于拉高状态,则 FIFO 已达到读取终止条件。写入的终止条件意味着 FIFO 没有空间来容纳更多数据,而读取的终止条件意味着 FIFO 没有更多数据可用于读出。状态块还可以报告 FIFO 中空或满位置的数量,这是通过指针上的算术运算来完成的。

空或满位置的实际计数在 FIFO 本身中没有多大作用;它被用作向外界报告的机制。然而,空和满信号在 FIFO 中起着非常重要的作用,它们分别阻止对进一步读取和写入的访问。这种阻塞的重要性不在于数据可能会被覆盖(或读出两次);关键在于指针位置是我们对 FIFO 的唯一控制,写入或读取会改变指针。如果我们不阻止指针在终止条件下更改状态,我们将有一个“吃”数据(没有可写入空间时,数据持续写入被覆盖)或“生成”数据(没有数据可读时,数据持续重复读出)的 FIFO,这是完全不可接受的。

FIFO 读写指针
进一步分析:DPRAM 可能有“寄存”读取这意味着来自阵列的输出数据已寄存。如果是这样,则必须将读取指针设计为“读取和递增”。这意味着您必须在 FIFO 输出的数据有效之前提供明确的读取信号。另一方面,如果 DPRAM 没有寄存输出,则只要写入有效数据即可;您先读取此数据,然后再增加指针。这会影响从 FIFO 中读取数据的逻辑以及执行空/满计算的逻辑。为简单起见,我们将只处理 DPRAM 不提供寄存输出的情况。将相同的推理(我们将使用)扩展到寄存输出 DPRAM 的情况并不是很复杂。

在功能上,FIFO 的工作方式如下:复位时,指针均为 0。这是 FIFO 的空状态,empty 被拉高,full 为低。空时,读取被阻止,因此唯一可能的操作是写入。写入加载数组的位置 0 并将写入指针增加到 1。这会导致空信号变为低电平。假设没有读取且后续周期仅写入 FIFO,则写入指针将在某个时间等于 array_size ‑1。这意味着数组中的最后一个位置是下一个将被写入的位置。在这种情况下,写入将导致写入指针变为 0,并设置为满。

请注意,在这种情况下,写入和读取指针相等,但 FIFO 已满,而不是空。这意味着满/空决定不仅仅基于指针值,而是基于导致指针变得相等的操作。如果指针相等的原因是复位或读取,则认为 FIFO 为空;如果原因是写入,则 FIFO 已满。

空满信号条件
现在假设我们开始一系列读取。每次读取都会增加读取指针,直到读取指针等于array_size ‑1。此时,来自该位置的数据在 FIFO 的输出总线上可用。随后的逻辑读取该数据并提供读取信号(一个时钟有效)。这会导致读指针再次变为等于写指针(在两个指针都完成了数组的一个周期之后)。但是,由于这种相等是由于读取而产生的,因此设置了空。

因此,对于空标志: 写入无条件清除空。 read_pointer = (array_size ‑1) 并且读取设置为空。

满标志:读取无条件清除满。 write_pointer = (array_size ‑1)并且写入设置为满。

但是,这是一种特殊情况,因为通常读取可能会在 FIFO 不为空时立即开始(读取逻辑不需要等待 FIFO 变满),因此必须修改这些条件以适应任何 read_pointer 和 write_pointer的值。

我们已经将数组组织为一个循环列表。因此,如果写指针在数值上比读指针大 1 并且发生读操作,则FIFO 为空。只要我们使用无符号(n 位)算术,这对于上述边界情况就可以正常工作。类似地,如果读指针在数值上比写指针大 1 并且发生了写操作,则 FIFO 已满。

这导致了前面说的读空和写满的条件发生变化:写入无条件清除空信号。(write_pointer = read_pointer + 1) 并且读操作设置为空。

读取无条件清除满信号。(read_pointer = write_pointer + 1) 并且写操作设置为满。

请注意,同时读取和写入会增加两个指针,但不会改变空标志和满标志的状态。满边界和空边界不允许同时读操作和写操作。

电路图如图二所示

注:本文基于《asynchronous fifo architectures》整理

最新文章

最新文章