一、两相握手协议:从四相到两相的进化
各位同学,今天我们来聊聊两相握手协议。说实话,我刚接触这个协议时,第一反应是——这不就是把四相协议的四个边沿砍掉两个吗?后来在实际项目中踩了坑,才发现事情没那么简单。
两相握手协议,英文叫 Two-Phase Handshake,也有人叫它边沿触发握手。它和四相协议最大的区别,说白了就是:四相协议看电平,两相协议看边沿。
1.1 两相 vs 四相:核心差异
我习惯用一个比喻来理解:四相协议就像两个人轮流举手示意,每次举手都要放下来再举;两相协议则是每次举手只改变状态,不用刻意放下来。
来看个具体对比:
| 对比项 | 四相协议 | 两相协议 |
|---|---|---|
| 触发方式 | 电平触发 | 边沿触发 |
| 状态数 | 4个状态 | 2个状态 |
| 握手周期 | 4个边沿 | 2个边沿 |
| 信号变化 | 每次都要归零 | 只翻转,不归零 |
| 功耗 | 较高(翻转次数多) | 较低(翻转次数少) |
| 适用场景 | 同步设计、低速接口 | 异步设计、低功耗场景 |
你想想看,四相协议每次传输都要经历:请求拉高 → 应答拉高 → 请求拉低 → 应答拉低。这四个步骤里,有一半的时间花在"归零"上。两相协议直接砍掉了归零动作,效率自然就上来了。
1.2 边沿触发机制
两相协议的核心,就是边沿触发。什么意思呢?
在四相协议里,发送方把 req 拉高,接收方看到高电平就知道有请求。但在两相协议里,接收方看的是 req 有没有发生变化——不管是上升沿还是下降沿,只要变了,就说明有新请求。
我记得有一次做低功耗芯片设计,项目要求接口功耗必须控制在 1mW 以内。四相协议怎么优化都差一点,后来换成两相协议,功耗直接降了 40%。原因很简单:信号翻转次数少了一半。
关键点:两相协议中,每个信号只表示"状态发生了变化",而不表示"状态是高还是低"。所以接收方必须用边沿检测电路来捕捉变化。
1.3 状态机设计
两相协议的状态机,比四相简单得多。我一般用两个状态来描述:
- IDLE(空闲态):等待请求边沿
- BUSY(忙碌态):处理数据,等待应答边沿
来看一个典型的发送端状态机:
// 两相握手发送端状态机
typedef enum {
IDLE,
WAIT_ACK
} tx_state_t;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= IDLE;
req <= 0;
end else begin
case (state)
IDLE: begin
if (data_valid) begin
req <= ~req; // 翻转请求信号
state <= WAIT_ACK;
end
end
WAIT_ACK: begin
if (ack != req) begin // 检测到应答边沿
state <= IDLE;
end
end
endcase
end
end
嗯,这里要注意:判断应答是否到达,不是看 ack 是高还是低,而是看 ack 和 req 是否相等。如果 ack == req,说明接收方还没响应;如果 ack != req,说明接收方已经翻转了 ack,响应到达了。
接收端的状态机也类似:
// 两相握手接收端状态机
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
ack <= 0;
data_out <= 0;
end else begin
if (req != ack) begin // 检测到请求边沿
data_out <= data_in;
ack <= ~ack; // 翻转应答信号
end
end
end
个人经验:我曾经在一个项目中,接收端直接用组合逻辑判断 req != ack,结果出现了毛刺。后来加了两级同步器,问题就解决了。跨时钟域处理,两相协议同样不能省。
1.4 优缺点分析
两相协议不是万能的,它有明显的优势和劣势。
优点:
- 效率高:每个握手周期只需要两次信号翻转,比四相快一倍
- 功耗低:信号翻转次数少,动态功耗自然低
- 状态机简单:两个状态就能搞定,代码量少
- 适合异步设计:不需要全局时钟同步,天然支持异步接口
缺点:
- 边沿检测复杂:需要额外的边沿检测电路,增加面积
- 调试困难:信号一直在翻转,波形看起来眼花缭乱
- 复位状态敏感:上电后 req 和 ack 的初始值必须一致,否则会误触发
- 不支持多数据打包:每次握手只能传一笔数据,不像四相协议可以流水线
避坑指南:我曾经在一个项目中,复位后 req 初始化为 0,ack 初始化为 1,结果一上电就触发了握手。后来我养成了习惯:所有两相协议的 req 和 ack 必须同步复位到相同值。
1.5 知识体系图
下面这张图,是我自己总结的两相握手协议知识体系,你可以把它当作学习路线图:
1.6 什么时候选两相?
我个人总结了一个选择原则:
- 功耗敏感项目(比如 IoT、可穿戴设备)→ 优先考虑两相
- 高速接口(比如 DDR、SerDes)→ 两相协议效率更高
- 异步跨时钟域 → 两相协议天然支持,不需要额外同步
- 调试友好型项目 → 还是用四相吧,波形看起来舒服多了
好了,两相握手协议的核心内容就这些。记住一句话:两相协议用边沿说话,四相协议用电平说话。理解了这个本质,剩下的都是细节。
课后思考:如果让你设计一个两相协议的接收端,如何保证在高速时钟下不会漏掉请求边沿?提示:想想边沿检测电路的建立时间约束。