3. 握手协议:VALID/READY握手机制、依赖关系、背压处理、传输完成条件
各位同学,今天我们来聊聊AXI总线最核心、也是最基础的东西——握手协议。说白了,就是数据怎么在Master和Slave之间“商量着”传输。
我刚入行那会儿,总觉得握手协议不就是两个信号嘛,VALID和READY,有啥好学的?结果第一次调AXI接口的时候,死锁了整整两天。嗯,从那以后我再也不敢小看这两个信号了。
3.1 VALID/READY握手机制
AXI的传输,靠的就是VALID和READY这一对信号。它们俩的关系,有点像“你递东西,我接东西”。
- VALID:发送方说“我准备好了,数据在总线上,你来拿”。
- READY:接收方说“我准备好了,你可以把数据给我了”。
数据真正传输成功的条件只有一个:VALID和READY同时为高。就在它们都拉高的那个时钟上升沿,数据被锁存,传输完成。
核心要点:只有VALID和READY同时为高,才算一次成功的传输。缺一个都不行。
你想想看,如果只有VALID拉高,READY没拉高,数据就卡在总线上,发送方得一直等着。反过来,如果READY拉高了,VALID没拉高,接收方就干等着,啥也收不到。
3.2 三种握手场景
在实际项目中,VALID和READY的时序关系有三种情况。我给大家画个图,一看就明白。
三种场景,对应三种不同的握手情况:
- VALID先有效:发送方先准备好,等接收方。这是最常见的场景,比如Slave正在忙,Master得等着。
- READY先有效:接收方先准备好,等发送方。比如Slave早就空着了,但Master的数据还没准备好。
- 同时有效:一拍搞定,零等待。这是最高效的情况,但实际项目中不常见。
我的经验:在设计高性能AXI接口时,尽量让VALID和READY同时有效。但别强求,很多时候Slave的处理速度跟不上,背压是必然的。
3.3 依赖关系
握手信号之间是有依赖关系的。这个坑,我踩过不止一次。
AXI协议规定:VALID信号不能依赖READY信号。什么意思呢?就是说,发送方拉高VALID的时候,不能等着READY拉高才拉高VALID。VALID必须“独立”拉高。
但READY可以依赖VALID。接收方可以等到看见VALID拉高了,再拉高READY。这完全没问题。
警告:如果你在代码里写了类似 assign valid = ready && data_ready 这样的逻辑,那就违反了协议!VALID不能等READY。我曾经在一个项目中看到有人这么写,结果综合出来的电路在时序分析时出了大问题。
为什么会这样规定?你想想看,如果VALID依赖READY,那万一READY一直不拉高,VALID就永远拉不高,系统就死锁了。AXI协议设计者早就想到了这一点。
3.4 背压处理
背压(Backpressure),说白了就是接收方处理不过来,让发送方“慢一点”。在AXI总线里,背压是通过READY信号来实现的。
当Slave处理不过来的时候,它会把READY拉低。这时候,即使Master的VALID是拉高的,数据也传不过去。Master就得保持VALID和数据的稳定,一直等到Slave把READY拉高为止。
我给大家看一段典型的背压处理代码:
// Slave接收端背压处理示例
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
ready <= 1'b0;
fifo_wr_en <= 1'b0;
end else begin
// 如果FIFO快满了,拉低READY,产生背压
if (fifo_almost_full) begin
ready <= 1'b0;
end else begin
ready <= 1'b1;
end
// 只有在VALID和READY同时为高时才写入FIFO
if (valid && ready) begin
fifo_wr_en <= 1'b1;
end else begin
fifo_wr_en <= 1'b0;
end
end
end
这段代码的逻辑很清楚:FIFO快满的时候,拉低READY,告诉Master“别发了,我吃不下了”。等FIFO被读走一些数据,再拉高READY,继续接收。
背压的本质:就是接收方通过READY信号控制数据流的速度。这是AXI总线实现流量控制的核心机制。
3.5 传输完成条件
一次传输什么时候算完成?很简单:VALID和READY同时为高的那个时钟上升沿。
但这里有个细节要注意——对于突发传输(Burst),每个数据节拍(Beat)都要单独握手。也就是说,一次突发传输有N个数据,就需要N次成功的握手。
| 传输类型 | 完成条件 | 说明 |
|---|---|---|
| 单次传输 | VALID & READY = 1 | 一次握手即完成 |
| 突发传输 | 每个Beat都完成握手 | N个Beat需要N次握手 |
| 写响应 | BVALID & BREADY = 1 | 写响应通道单独握手 |
| 读数据 | RVALID & RREADY = 1 | 最后一个数据带RLAST信号 |
我记得有一次调试一个DMA控制器,发现读传输总是少一个数据。查了半天,原来是RLAST信号没处理好。最后一个数据传完了,RLAST没拉高,Master以为还有数据要传。嗯,这种边界情况最容易出问题。
调试小技巧:在仿真的时候,把VALID和READY同时为高的时刻打印出来,数一数握手次数对不对。如果突发长度是8,那就应该有8次握手。少一次都不行。
3.6 本章小结
握手协议是AXI总线的基础,也是最容易出错的地方。我个人习惯在设计任何AXI接口时,先把握手逻辑单独写出来,验证好了再集成到系统中。
记住三个要点:
- VALID不能依赖READY,这是死规矩
- 背压通过READY实现,别让FIFO溢出
- 传输完成的唯一标志是VALID和READY同时为高
把这些搞清楚了,后面的通道协议学起来就轻松多了。