经典握手信号:Valid/Ready 协议详解,四种传输场景分析

Valid/Ready 协议,说白了就是数字电路里最常用的“你准备好了吗?我准备好了!”的对话机制。我做了这么多年接口设计,可以说90%以上的模块间通信都在用这套规则。它简单、高效,而且特别好理解。

先看基本概念:

  • Valid:发送方说“我这数据有效了,你赶紧拿”
  • Ready:接收方说“我准备好了,你发吧”

数据真正传输成功的条件就一个:Valid 和 Ready 同时为高。就这么简单。

核心原则:数据只在 Valid & Ready 同时为高的时钟沿被采样。其他情况,数据要么没准备好,要么对方没空收。

四种传输场景详解

我刚开始学这个协议时,总觉得不就两个信号嘛,能有多复杂?直到我在一个项目里因为没处理好 back-to-back 传输,导致数据丢包,才老老实实把四种场景都吃透了。来,一个一个看。

场景一:Valid 先有效,Ready 后有效

发送方先把数据摆到总线上,Valid 拉高,但接收方还在忙。这时候数据就等着。等 Ready 拉高,下一个时钟沿数据就被采样走了。

// 伪代码示例
always @(posedge clk) begin
    if (valid & ready) begin
        // 数据被成功采样
        data_sampled <= data_in;
    end
end

嗯,这里要注意:Valid 一旦拉高,必须保持到握手成功。我见过有人 Valid 只拉了一个周期就撤了,结果 Ready 还没来,数据就丢了。这属于典型的“急性子”问题。

场景二:Ready 先有效,Valid 后有效

接收方提前说“我准备好了”,但发送方数据还没算出来。这时候 Ready 可以一直高着,等 Valid 一来,下一个时钟沿直接采样。

我的习惯:如果接收方总是能收数据,我建议把 Ready 直接拉高,省一个控制逻辑。但要注意,如果后面 FIFO 快满了,Ready 得及时拉低,不然会 overflow。

场景三:Valid 和 Ready 同时有效

这是最理想的情况——一拍搞定。发送方数据准备好了,接收方也正好有空。一个时钟周期,数据就传过去了。

我在做高速接口时特别喜欢这种场景,因为它没有气泡(bubble),吞吐率最高。说白了就是“天时地利人和”,一拍成交。

场景四:Valid 和 Ready 都无效

双方都没准备好。这种情况其实不用太操心,数据不会传输,总线保持原样。但要注意:如果 Valid 和 Ready 都无效的状态持续太久,说明系统可能卡住了,需要检查上游或下游的阻塞原因。

场景 Valid Ready 传输结果 典型原因
一 先高 后高 等待后传输 接收方忙
二 后高 先高 等待后传输 发送方未就绪
三 同时高 同时高 立即传输 理想情况
四 低 低 无传输 双方未就绪

Valid/Ready 协议的时序图

光说理论不够直观,我画了一张时序图,把四种场景都标出来了。你一看就明白。

信号 CLK T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 Valid Ready 传输 场景一 场景二 场景三 场景四 Valid Ready 传输成功 场景一:Valid先高→等待→Ready高→T2传输 场景三:同时高→T6立即传输

避坑指南

我曾经在一个 PCIe 控制器项目里踩过一个坑:Valid 信号在握手成功后没有及时拉低,导致同一个数据被采样了两次。你想想看,这要是地址数据,系统直接跑飞了。

重要提醒:Valid 信号必须在握手成功的下一个时钟沿拉低,除非你有连续传输的需求。否则,接收方会认为又有新数据来了。

还有一点:Ready 信号不能组合逻辑产生。我见过有人直接用组合逻辑把 FIFO 的空标志取反当 Ready,结果时序一塌糊涂。Ready 一定要用寄存器打一拍,不然毛刺会让你怀疑人生。

实际项目中的经验

我个人习惯在模块接口处加一个握手状态机,专门处理 Valid/Ready 的交互。这样主逻辑不用操心握手细节,代码也干净很多。

举个例子,一个简单的 AXI-Stream 接口:

// 握手状态机示例
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        handshake_done <= 1'b0;
    end else if (valid & ready) begin
        handshake_done <= 1'b1;  // 握手成功
    end else begin
        handshake_done <= 1'b0;
    end
end

嗯,这里要注意:handshake_done 只拉高一个周期,用来触发后续的数据处理逻辑。如果你需要连续传输,那就得用计数器或者 FIFO 来管理了。

我的建议:在设计初期就把 Valid/Ready 的时序画清楚。别偷懒,画个时序图花不了十分钟,但能省下后面 debug 的好几天。

好了,Valid/Ready 协议的四种场景就讲到这里。说白了就是“你情我愿”才能传输,其他情况要么等要么歇着。下一节我们会讲怎么用这个协议搭出更复杂的传输结构,比如 pipeline 和 back-to-back 传输。

可可精品资料库