2. FIFO核心原理:先进先出原则、读写指针机制、空/满标志判断

大家好,我是你们的硬件工程师老K。今天咱们来聊聊FIFO最核心的三个东西:先进先出、读写指针、空满判断。这三个概念,说白了就是FIFO的灵魂。你把这三点吃透了,后面写代码、调时序、debug都会顺很多。

2.1 先进先出原则——排队买奶茶的智慧

FIFO的全称是First In First Out,翻译过来就是“先进先出”。这个概念其实特别生活化。你想想看,排队买奶茶,谁先来谁先拿到,这就是FIFO。

在数字电路里,FIFO就是一个数据队列。数据从一端写入,从另一端读出。先写进去的数据,必须先被读出来。这个顺序不能乱。

为什么一定要先进先出? 我遇到过不少刚入行的同学问我这个问题。其实原因很简单:很多应用场景要求数据保持原有的顺序。比如你采集一段音频信号,先采到的样本必须先处理,否则声音就乱套了。再比如网络数据包,顺序乱了,接收端根本拼不回去。

核心要点: FIFO不改变数据的相对顺序。它就像一个透明的管道,数据进去是什么顺序,出来还是什么顺序。

2.2 读写指针机制——两个“游标”的故事

FIFO内部是怎么实现先进先出的?靠的就是两个指针:写指针(Write Pointer)和读指针(Read Pointer)。

我个人习惯把这两个指针想象成两个“游标”。写指针指向下一个要写入的位置,读指针指向下一个要读出的位置。每次写入一个数据,写指针就往后移动一格。每次读出一个数据,读指针也往后移动一格。

这两个指针,说白了就是两个计数器。它们循环递增,从0走到FIFO深度-1,然后回到0重新开始。这就是所谓的“环形缓冲区”思想。

我给大家画个图,一看就明白了:

D0 D1 D2 D3 D4 D5 写指针 读指针 写入→ →读出 已写入数据 空单元

你看这个图,写指针指向D3位置,说明D0、D1、D2已经写入了。读指针指向D1位置,说明D0已经被读走了。两个指针之间的区域,就是当前FIFO里存着的数据。

小技巧: 我建议你在设计FIFO时,把指针宽度设得比地址位宽多1位。这样判断空满会方便很多。后面我会详细讲为什么。

2.3 空/满标志判断——FIFO的“红绿灯”

空标志和满标志,是FIFO对外最重要的两个状态信号。它们告诉外部电路:现在能不能写?能不能读?

空标志(Empty Flag): 当读指针追上了写指针,说明FIFO里一个数据都没有了。这时候读操作是无效的,读出来的数据是垃圾。

满标志(Full Flag): 当写指针追上了读指针,说明FIFO已经存满了。这时候写操作会覆盖掉还没读走的数据,造成数据丢失。

嗯,这里要注意一个关键点:空和满的时候,两个指针的值是相等的!那怎么区分呢?

我刚开始学的时候也困惑过这个问题。后来老师告诉我一个方法:看指针的额外标志位。

具体做法是这样的:

  • 给每个指针多加一个标志位,比如叫wrap bit
  • 每次指针从最大值回到0时,这个标志位翻转一次
  • 空状态:两个指针的值相等,且标志位也相等
  • 满状态:两个指针的值相等,但标志位不同

说白了,就是用这个额外的标志位来区分“空”和“满”。这个方法在实际工程中非常常用。

避坑指南: 我曾经在一个项目里吃过亏。当时设计了一个深度为16的FIFO,指针用4位二进制表示。结果空满判断总是出错。后来发现,当指针从15回到0时,如果不加额外标志位,空和满根本分不清。从那以后,我所有FIFO设计都老老实实加了标志位。

咱们来看一段简单的Verilog代码,演示空满判断的逻辑:

// 假设FIFO深度为16,指针宽度为5位(4位地址+1位标志)
reg [4:0] wr_ptr;  // 写指针
reg [4:0] rd_ptr;  // 读指针

// 空标志:指针完全相等
assign empty = (wr_ptr == rd_ptr);

// 满标志:地址位相等,但标志位不同
assign full  = (wr_ptr[4] != rd_ptr[4]) && 
               (wr_ptr[3:0] == rd_ptr[3:0]);

这段代码看着简单,但背后有个细节:为什么满标志要判断地址位相等且标志位不同?因为满的时候,写指针刚好比读指针多绕了一圈。标志位不同,就表示“多绕了一圈”。

2.4 三种常见判断方式对比

在实际工程中,空满判断有好几种实现方式。我给大家整理了一个表格,方便对比:

判断方式 原理 优点 缺点
额外标志位法 指针多1位标志位,空满时地址相同但标志位不同 实现简单,资源消耗少 指针宽度增加1位
计数器法 用一个计数器记录FIFO中数据个数 空满判断直观,还能知道剩余空间 计数器逻辑稍复杂,深度大时计数器位宽大
格雷码法 指针用格雷码编码,跨时钟域时更安全 适合异步FIFO,抗亚稳态 格雷码转二进制需要额外逻辑

我个人最常用的是额外标志位法。原因很简单:它够简单,够可靠。在同步FIFO里,这个方法几乎不会出问题。如果是异步FIFO,我建议用格雷码法,因为跨时钟域传递时格雷码更安全。

总结一下: FIFO的核心原理其实不复杂。先进先出是规则,读写指针是工具,空满标志是状态。这三个东西组合在一起,就构成了FIFO最基本的骨架。你把这个骨架搭好了,后面加什么功能都方便。

好了,这一章的内容就到这里。记住我刚才说的:指针多加一位标志位,空满判断就不会搞混。这个经验是我用实际教训换来的,希望对你有帮助。

可可精品资料库