2、AXI通道详解:读地址通道(AR)、读数据通道(R)、写地址通道(AW)、写数据通道(W)、写响应通道(B)的信号定义与时序
各位同学,今天我们来啃一啃AXI总线最核心的部分——五个独立通道。说实话,我刚接触AXI时,被这五个通道搞得有点晕。后来在项目里调了几个月,才真正摸透它们的脾气。
AXI协议把一次传输拆成了五个通道,各干各的活。你想想看,这就像一条流水线,每个工位只做一件事,效率自然高。这五个通道分别是:读地址通道(AR)、读数据通道(R)、写地址通道(AW)、写数据通道(W)、写响应通道(B)。
嗯,咱们一个一个来看。
2.1 读地址通道(AR)
读地址通道,说白了就是Master告诉Slave:「我要读数据,地址在这!」。这个通道只负责传地址和控制信息,不传数据本身。
关键信号就那么几个:
| 信号 | 方向 | 说明 |
|---|---|---|
| ARID | Master→Slave | 读事务ID,用于匹配地址和返回的数据 |
| ARADDR | Master→Slave | 读起始地址 |
| ARLEN | Master→Slave | 突发长度,表示一次突发传输多少笔数据 |
| ARSIZE | Master→Slave | 每笔数据的字节数 |
| ARBURST | Master→Slave | 突发类型:FIXED、INCR、WRAP |
| ARVALID | Master→Slave | 地址有效信号 |
| ARREADY | Slave→Master | Slave准备好接收地址 |
这里有个握手规则,我建议你牢牢记住:ARVALID和ARREADY必须同时为高,地址才算被成功传递。我在一个项目中遇到过,Master把ARVALID拉高后,Slave的ARREADY迟迟不来,结果Master傻等了好几个周期。后来查了半天,原来是Slave的仲裁逻辑没处理好。
核心要点:读地址通道是单次握手的。地址传过去后,这个通道就空闲了,直到下一次读请求。
2.2 读数据通道(R)
读数据通道是Slave回复数据的通道。它和读地址通道是配对的——你发一个地址,我回一堆数据(如果是突发传输的话)。
关键信号:
| 信号 | 方向 | 说明 |
|---|---|---|
| RID | Slave→Master | 读事务ID,必须和ARID一致 |
| RDATA | Slave→Master | 读回来的数据 |
| RRESP | Slave→Master | 读响应状态:OKAY、EXOKAY、SLVERR、DECERR |
| RLAST | Slave→Master | 最后一笔数据的标志 |
| RVALID | Slave→Master | 数据有效信号 |
| RREADY | Master→Slave | Master准备好接收数据 |
你可能会问:「为什么读数据通道里要有RLAST?」嗯,这个问题问得好。因为一次突发传输可能有多笔数据,Master需要知道哪一笔是最后一笔。没有RLAST的话,Master就得自己数数,万一数错了就麻烦了。
个人经验:我曾经设计过一个DMA控制器,读数据时RVALID和RREADY的握手时序没处理好,导致数据丢了一拍。排查了两天才发现,原来是RREADY拉高的时机早了半个周期。这种问题在仿真里很难抓到,建议你在验证时多关注握手信号的交叉点。
2.3 写地址通道(AW)
写地址通道和读地址通道长得几乎一模一样,只是前缀从AR变成了AW。它负责告诉Slave:「我要往这个地址写数据!」
信号列表:
| 信号 | 方向 | 说明 |
|---|---|---|
| AWID | Master→Slave | 写事务ID |
| AWADDR | Master→Slave | 写起始地址 |
| AWLEN | Master→Slave | 突发长度 |
| AWSIZE | Master→Slave | 每笔数据字节数 |
| AWBURST | Master→Slave | 突发类型 |
| AWVALID | Master→Slave | 地址有效 |
| AWREADY | Slave→Master | Slave准备好接收地址 |
这里有个有意思的点:写地址通道和写数据通道是独立的。也就是说,地址可以先发,数据可以后发;或者数据先发,地址后发;甚至同时发。协议没有规定它们的先后顺序。
注意:虽然协议允许地址和数据乱序,但很多Slave实现要求地址必须先到。我建议你在设计Master时,尽量让地址先于数据发出,这样兼容性最好。
2.4 写数据通道(W)
写数据通道负责传输实际要写的数据。它和读数据通道最大的区别是:写数据通道里多了一个WSTRB信号。
关键信号:
| 信号 | 方向 | 说明 |
|---|---|---|
| WID | Master→Slave | 写事务ID(注意:AXI3有,AXI4已废弃) |
| WDATA | Master→Slave | 写数据 |
| WSTRB | Master→Slave | 字节选通信号,哪一位为1就写哪个字节 |
| WLAST | Master→Slave | 最后一笔数据标志 |
| WVALID | Master→Slave | 数据有效 |
| WREADY | Slave→Master | Slave准备好接收数据 |
WSTRB这个信号,说白了就是让你能按字节写。比如你只想写一个32位数据的最低字节,那就把WSTRB[0]拉高,其他位拉低。这个功能在操作外设寄存器时特别有用。
举个例子:
// 假设数据总线宽度为32位(4字节)
// 只想写地址0x1000的最低字节
WADDR = 0x1000
WDATA = 0x12345678
WSTRB = 4'b0001 // 只写byte0
// 结果:地址0x1000处写入0x78,其他三个字节不变
关键点:写数据通道的最后一笔数据必须带有WLAST信号。Slave收到WLAST后,才知道这次突发传输结束了,可以开始处理写响应了。
2.5 写响应通道(B)
写响应通道是五个通道里最简单的一个。它只做一件事:Slave告诉Master「你刚才写的那批数据,我处理完了,结果如何」。
信号列表:
| 信号 | 方向 | 说明 |
|---|---|---|
| BID | Slave→Master | 写事务ID,必须和AWID一致 |
| BRESP | Slave→Master | 写响应状态 |
| BVALID | Slave→Master | 响应有效 |
| BREADY | Master→Slave | Master准备好接收响应 |
注意:一次突发传输只产生一个写响应。不管你的突发长度是1还是16,Slave只会在所有数据都处理完后,返回一个BRESP。
我曾经犯过一个错误:在设计一个AHB转AXI的桥接器时,我以为每笔数据都要返回一个响应,结果给每个WLAST都配了一个B通道响应。仿真时没发现问题,上板后Slave那边直接崩溃了。后来查协议才发现,一次突发只对应一个响应。
避坑指南:写响应通道的BVALID必须在WLAST被确认之后才能拉高。有些新手设计时,BVALID和WVALID同时拉高,这会导致Master收到响应时,数据还没写完呢。
2.6 五个通道的时序关系
咱们用一张图来理清五个通道的关系:
从这张图你能看出几个关键点:
- 读操作:先走AR通道发地址,然后走R通道收数据。两个通道独立握手。
- 写操作:先走AW通道发地址,同时走W通道发数据(可以不同步),最后走B通道收响应。
- 五个通道完全独立:每个通道都有自己的VALID/READY握手信号,互不干扰。
2.7 握手协议详解
AXI的握手协议,说白了就是VALID和READY的「约会」过程。有三种情况:
- VALID先到,READY后到:最常见的情况。Master把数据准备好,等Slave来取。
- READY先到,VALID后到:Slave提前告诉Master「我准备好了」,Master再发数据。
- VALID和READY同时到:一拍搞定,效率最高。
我个人习惯用第一种方式,因为设计起来最简单。但如果你追求高性能,可以尝试让VALID和READY同时到达。
重要提醒:VALID信号一旦拉高,就不能再拉低,直到对应的READY也拉高。这是AXI协议的死规定,违反了就是协议错误。我曾经见过一个实习生,在VALID拉高后又因为某些原因把它拉低了,结果仿真直接报错。
2.8 突发传输的完整流程
咱们用一个实际例子来串一遍。假设Master要向Slave写4笔数据,每笔32位,地址从0x1000开始递增:
// 写地址通道
AWADDR = 0x1000
AWLEN = 3 // 4笔数据(LEN+1)
AWSIZE = 2 // 4字节(2^2 = 4)
AWBURST = 1 // INCR模式
AWVALID = 1
// 等待AWREADY = 1
// 写数据通道(可以比地址晚几个周期)
WDATA[0] = 0xAABBCCDD, WSTRB = 4'b1111, WVALID = 1
WDATA[1] = 0x11223344, WSTRB = 4'b1111, WVALID = 1
WDATA[2] = 0x55667788, WSTRB = 4'b1111, WVALID = 1
WDATA[3] = 0x99AABBCC, WSTRB = 4'b1111, WVALID = 1, WLAST = 1
// 每笔数据都要等WREADY
// 写响应通道(在所有数据传完后)
BRESP = 0 // OKAY
BVALID = 1
// 等待BREADY = 1
你看,整个流程就是:发地址 → 发数据(可以穿插) → 收响应。读操作类似,只是少了响应通道,数据通道里直接带响应。
经验之谈:设计AXI互联时,我最头疼的就是处理多个Master同时访问同一个Slave的情况。这时候需要仲裁器来决定谁先用地址通道。我建议你给每个Master分配不同的ID,这样Slave返回数据时可以根据ID来区分。
好了,五个通道的细节就讲到这里。记住一句话:地址通道管「去哪」,数据通道管「传啥」,响应通道管「结果咋样」。搞清楚了这三个角色,AXI的基本框架你就拿下了。