FIFO(First in First Out)是异步数据传输时经常使用的存储器。
特点:数据先进先出(后进后出)
工作流程:
在写时钟和状态信号的控制下,数据下入FIFO中。RAM的写地址从0开始,每写一次数据写指针加一,指向下一个存储单元。当FIFO写满后,数据将不再写入,否则数据会因覆盖而丢失。
FIFO数据为非空,或满状态时,在读时钟和状态信号的控制下,可以将数据从FIFO中读出。RAM的读地址从0开始,每读一次数据读地址指针加一,指向下一个存储单元。当FIFO读空后,就不能再读数据,否则读出的数据将是错误的。
FIFO的存储结构为双口RAM,所以允许读写同时进行。典型异步FIFO结构图如下所示。
读写时刻:
关于写时刻,只要FIFO中数据为非满状态,就可以进行写操作;如果FIFO为满状态,则禁止再写数据。
关于读时刻,只要FIFO中数据为非空状态,就可以进行读操作;如果FIFO为空状态,则禁止再读数据。
一段正常读写FIFO的时间段,如果读写同时进行,则要求写FIFO速率不能大于读速率。因为如果写速率过快,超过了读速率,那么FIFO中的数据就会积累,直到达到其容量上限。一旦FIFO写满,新的数据将无法再被写入,这可能导致数据丢失或覆盖,从而破坏数据的完整性和一致性。
读空状态
开始复位时,FIFO没有数据,空状态信号是有效的。当FIFO中被写入数据后,空状态信号拉低无效。当读数据地址追赶上写地址,即读写地址都相等时,FIFO为空状态。
因为是异步FIFO,所以读写地址进行比较时,需要同步打拍逻辑,就需要耗费一定时间。所以空状态的指示信号不是实时的,会有一定的延时。如果在这段延迟时间内又有新的数据写入FIFO,就会出现空状态指示信号有效,但是FIFO中其实存在数据的现象。(严格来讲,该空状态指示是错误的。但是产生空状态的意义在于防止读操作对空状态的FIFO进行数据读取。产生空状态信号时,实际FIFO中有数据,相当于提前判断了空状态信号,此时不再进行读FIFO数据操作也是安全的。所以,该设计从应用上来说是没有问题的)
写满状态
开始复位时,FIFO没有数据,满信号是无效的。当FIFO中被写入数据后,此时读操作不进行或读速率相对较慢,只要写数据地址超过读数据地址一个FIFO深度时,便会产生满状态信号。此时写地址和读地址也是相等的,但是意义易不一样的。
此时经常使用多余的1bit分别当做读写地址的拓展位,来区分读写地址相同的时候,FIFO的状态是空还是满状态。当读写地址与拓展位均相同的时候,表明读写数据的数量是一致的,则此时FIFO是空状态。如果读写地址相同,拓展位为相反数,表明写数据的数量已经超过读数据数量的一个FIFO深度,此时FIFO是满状态。当然,此条件成立的前提是空状态禁止读操作、满状态禁止写操作。
同理,由于异步延迟逻辑的存在,满状态信号也不是实时的。但是也相当于提前判断了满状态信号,此时不再进行写FIFO操作也不会影响应用的正确性。注意,写满状态信号,是在写时钟域产生的。
格雷码
- 当读写时钟都是同一个时钟时,此时FIFO是同步的,直接对读写指针进行比对,产生空、满信号即可。
- 当读写时钟是异步的时候,因为读时钟域产生读空信号,写时钟域产生写满信号,所以产生空逻辑信号时,需要将写指针同步到读时钟域,再与读指针进行比较;产生满逻辑信号时,需要将读指针同步到写时钟域,再与写指针进行比较。
(在异步FIFO设计中,读指针和写指针可能工作在不同的时钟域,这意味着它们的更新和比较不能直接在各自的时钟域中进行。
当FIFO为空时,意味着没有更多的数据可供读取。为了检测这种情况,我们需要比较读指针和写指针。但是,由于写指针在写时钟域,而读指针在读时钟域,直接比较这两个指针可能会导致错误的结果。因此,我们需要将写指针同步到读时钟域,确保在比较时两者都处于相同的时钟边界。同步后的写指针与读指针进行比较,如果它们相等或满足其他预定的条件,就表明FIFO为空,从而产生空逻辑信号。同样地,当FIFO满时,意味着没有更多的空间可以写入新的数据。为了检测这种情况,我们需要比较读指针和写指针。但是,由于读指针在读时钟域,而写指针在写时钟域,我们也需要进行同步处理。因此,将读指针同步到写时钟域,再与同步后的写指针进行比较。如果它们相等或满足其他预定的条件,就表明FIFO已满,从而产生满逻辑信号。)
- 因为读写指针的宽度一般都是大于1bit的,所以同步处理时不能直接对多位宽的读写指针进行延迟打拍,需要借助格雷码对读写指针进行转换,保证每一个周期内地址指针只有1bit变化,然后再进行延迟打拍的同步处理。
(格雷码是一种二进制编码方式,其相邻的两个数值只有一个位的差异,这种特性使得格雷码在变化时只涉及到一个位的翻转,从而减少了由于多位同时变化可能带来的不稳定性和错误。如果直接使用二进制编码的指针,由于多位可能同时变化,就可能导致同步过程中的错误或冲突。)
(4)4bit的二进制码与格雷码之间的变化关系如下所示。由图可知,二进制对应的十六进制码递增时,二进制码对应的相邻的两个格雷码之间只有1bit数据有变化。当多位宽信号每次只有1bit数据变化时,可以使用延迟打拍的方法对其进行同步处理。
- 下面对空逻辑的产生进行举例说明
(5.1)首先需要对写指针waddr进行组合逻辑的格雷码变换waddr_gray
(5.2)为了保证waddr_gray在读时钟域每次被采集时只有1bit数据变化,则waddr_gray需要在其源时钟域即写时钟域进行一拍缓存waddr_gray_d。因为waddr到waddr_gray的组合逻辑变换时,每次两者之间不只是有1bit变化的。
(5.3)在读时钟域对waddr_gray_d进行打拍同步,得到读时钟域同步后的指针为waddr_gray_rclk。
(5.4)根据格雷码的变换规则,空信号有效时二进制相等的读写指针,变为格雷码之后仍然相等。所以直接使用waddr_gray_rclk与读指针进行组合逻辑变换后的格雷码进行相等比较,即可产生读空信号逻辑。
(5.5)需要说明的是,满信号有效时,带有拓展位的读写指针高1bit相反,低位相同。所以变为格雷码之后,写满信号产生的条件,则是读写指针高2bit相反,低位相同
(因为)当读指针指向7,写指针指向8时,除了高1位,低位都相同。但不能说它为满。因此高2位可以更稳定地判断满信号。
FIFO设计
设计要求
为设计应用于各种场景的FIFO,这里对设计提出如下要求
- FIFO是异步的,即读写控制信号来自不同的时钟域。
- FIFO深度,宽度参数化,输出空、满状态信号,并输出一个可配置的满状态信号。当FIFO内部数据达到设置的参数数量时,该信号拉高,此时需要对格雷码进行反解码。
- 输入数据和输出数据位宽可以不一致,但要保证写数据,写地址位宽与读数据、读地址位宽的一致性。
例如:写数据位宽为8bit,写地址位宽为6bit(64个数据)。如果输出数据位宽要求32bit,则输出地址位宽应该为4bit(16个数据)
因为:写地址位宽为6bit,那么FIFO将有2^6=64个独立的存储单元,每个单元可以存储一个8bit的数据。因此总数量为64*8=512个数据。
因此输出地址需要512/32=16个单元,所以输出地址位宽为4bit
双口RAM设计
RAM地址位宽、数据位宽等端口参数可配置,读写位宽一致。实际中RAMDP(Dual Port)是需要使用Memory IP,这里创建的RAM并没有考虑到异步的问题
参考资料