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

目录

FIFO 的用途

单时钟 FIFO 的例子

FIFO 空满信号

FIFO 读写指针

空满信号条件


 

FIFO 的用途

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

单时钟 FIFO 的例子

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

一文看懂异步 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) 并且写操作设置为满。

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

电路图如图二所示

一文看懂异步 FIFO 架构(一) 单时钟的异步 FIFO_第2张图片

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

 

 

 

你可能感兴趣的:(#,常见,IP,FPGA,tcp/ip,网络协议,网络,fpga开发,数字IC)