3. FIFO握手协议基础:握手的本质、valid-ready握手协议、握手时序图分析

各位同学,今天我们来聊聊FIFO设计里最核心、也最容易踩坑的部分——握手协议。说实话,我见过太多新手一上来就撸代码,结果仿真通过、上板就挂,十有八九都是握手没搞明白。咱们先把基础打牢,后面写代码才心里有底。

3.1 握手的本质:不就是“你准备好了吗?”

握手协议,说白了就是两个模块之间互相确认“能不能干活”的一种约定。你想想看,生活中两个人配合做事,是不是也得先打个招呼?比如你递东西给我,你得先问一句“准备好了吗?”,我回一句“好了,你给吧”,这才算一次成功的交接。

数字电路里也一样。发送方(我们叫它master)要发数据,接收方(slave)要收数据。但问题是——双方的速度可能不一样。发送方可能一口气准备好了一堆数据,接收方却还在处理上一条。这时候如果没有握手协议,数据就会丢得一塌糊涂。

握手的本质就是:用控制信号来协调数据通道的节奏,确保每一笔数据都被正确接收,不多传、不少传、不丢数据。

我在项目中遇到过最典型的例子:一个高速ADC采集模块往FIFO里写数据,ADC时钟是200MHz,FIFO的读时钟只有50MHz。如果没有握手,写一次数据读一次,那读方根本来不及处理,数据全堆在FIFO里,最后溢出。嗯,这就是为什么我们需要握手协议来“踩刹车”。

3.2 valid-ready握手协议:最经典的“一问一答”

在数字IC设计里,最常用的握手协议就是valid-ready协议。它只有两个控制信号:

  • valid:发送方告诉接收方“我这边数据准备好了,你准备收吧”
  • ready:接收方告诉发送方“我这边有空位了,你可以发了”

数据什么时候才算真正传输成功?valid和ready同时为高的时候。这个时刻,我们称之为“握手成功”。

我个人习惯把valid-ready协议分成三种情况来理解:

场景 valid ready 结果
发送方先准备好 1 0 等待接收方,数据保持
接收方先准备好 0 1 等待发送方,空等
双方同时准备好 1 1 一拍传输完成,效率最高

你看,最理想的情况就是第三种——valid和ready同时拉高,一拍搞定。但实际设计中,这种情况可遇不可求。大多数时候,总有一方要等一等。

一个小技巧:我建议在设计FIFO时,把valid和ready的生成逻辑分开写。valid由发送方控制,ready由接收方控制。这样代码结构清晰,后期调试也方便。我曾经把两个信号揉在一起写,结果查bug查了整整两天……

3.3 握手时序图分析:一张图胜过千言万语

光说理论太抽象,咱们直接看时序图。下面这张图是我用SVG画的,展示了valid-ready握手协议的三种典型场景。

T0 T1 T2 T3 T4 T5 T6 clk valid ready data 数据有效 握手成功 场景1: valid先到, ready未就绪 场景2: ready先到, valid未就绪 场景3: 同时就绪

咱们来逐段分析这张图:

  • T0~T2(场景1):valid在T0就拉高了,但ready直到T2才拉高。这期间数据一直保持有效,等待接收方就绪。注意看,数据在T0就已经准备好了,但直到T2才真正被接收。
  • T3~T4(场景2):ready在T3就拉高了,但valid直到T4才拉高。接收方空等了一个周期。这种情况在FIFO读空时很常见——读使能已经准备好了,但FIFO里还没数据。
  • T5(场景3):valid和ready同时拉高,一拍完成传输。这是最高效的情况,也是我们设计时最希望看到的。

注意:valid信号一旦拉高,在握手成功之前不能随意拉低。我曾经犯过这个错误——valid拉高后,因为某些原因又把它拉低了,结果接收方只收到了半个数据,整个系统直接崩溃。记住:valid是承诺,拉高了就要坚持到握手成功。

3.4 握手协议在FIFO中的应用

在FIFO设计中,握手协议体现在两个接口上:

  1. 写接口:写使能(wr_en)相当于valid,满标志(full)的取反相当于ready。只有wr_en为高且full为低时,数据才能写入FIFO。
  2. 读接口:读使能(rd_en)相当于valid,空标志(empty)的取反相当于ready。只有rd_en为高且empty为低时,数据才能从FIFO读出。

说白了,FIFO的满和空标志,本质上就是在告诉对方“我准备好了没有”。

避坑指南:我建议你在写FIFO代码时,把valid和ready的时序单独写成一个module,方便复用。比如我常用的一个写法:

// 握手成功检测
assign handshake_done = valid & ready;

// 数据寄存
always @(posedge clk or negedge rst_n) begin
    if (!rst_n)
        data_q <= '0;
    else if (handshake_done)
        data_q <= data_in;
end

这样写的好处是,handshake_done这个信号可以复用到多个地方,比如计数器、状态机跳转等。

好了,这一章的内容就到这里。握手协议是FIFO设计的基石,你把它吃透了,后面写代码就会顺手很多。下一章我们会深入FIFO的读写指针设计,到时候你会看到握手协议是如何与指针逻辑配合工作的。

本章要点回顾:

  • 握手的本质是协调数据通道的节奏
  • valid-ready协议是最常用的握手方式
  • 握手成功 = valid & ready 同时为高
  • valid拉高后不能随意拉低,直到握手成功
  • FIFO的满/空标志本质上就是ready信号的变体

可可精品资料库