4、AHB协议详解(二):AHB突发传输(INCR/WRAP)、传输大小与对齐、响应信号(OKAY/ERROR/RETRY/SPLIT)
好,咱们接着聊AHB。上一章我们把AHB的基本握手和单次传输讲透了。这一章,我重点说说突发传输、数据对齐,还有那几个让人头疼的响应信号。这些内容,说白了就是AHB协议里最容易踩坑的地方。
4.1 突发传输:INCR与WRAP
突发传输,英文叫Burst。什么意思呢?就是一次发起,连续传好几笔数据。你想想看,如果每次传一个数据都要重新仲裁、重新给地址,那效率得多低?所以AHB设计了突发传输。
AHB支持两种突发类型:INCR(递增突发)和WRAP(回卷突发)。我个人习惯把INCR叫做“线性增长”,WRAP叫做“绕圈圈”。
4.1.1 INCR(递增突发)
INCR最简单。地址从起始地址开始,每传一笔数据,地址就增加一个传输大小。比如你做一个INCR4的32位传输,起始地址是0x100,那么地址依次是:0x100、0x104、0x108、0x10C。就这么简单。
我在项目中遇到过一个问题:有人把INCR和INCR4搞混了。INCR是长度不定的突发,从1到16都可以。而INCR4、INCR8、INCR16是固定长度的。嗯,这里要注意:INCR(不定长)在协议里其实很少用,因为总线仲裁器没法预判你要传多久。我建议你尽量用固定长度的INCR4/8/16。
4.1.2 WRAP(回卷突发)
WRAP就有点意思了。它也是递增,但到了边界就“卷”回来。为什么会这样?说白了,就是为了配合Cache Line。你想想,Cache Line通常是16字节或32字节,WRAP正好在这个范围内循环。
举个例子:WRAP4的32位传输,起始地址0x10C。注意,WRAP的边界是4拍×4字节=16字节对齐。所以边界是0x100。地址序列是:0x10C、0x110、0x114、0x100。看到了吗?到了0x114之后,下一拍就卷回0x100了。
关键点:WRAP的边界计算方式:边界 = (起始地址 / (传输大小 × 拍数)) 向下取整 × (传输大小 × 拍数)。说白了,就是按总传输字节数对齐。
我记得有一次调试一个DMA控制器,WRAP地址算错了,结果数据全写到了错误的位置。查了两天才发现是边界计算少了对齐。从那以后,我每次写WRAP逻辑都会画个地址图。
4.2 传输大小与对齐
AHB支持三种传输大小:8位(Byte)、16位(Halfword)、32位(Word)。这个不难理解。但关键是对齐。
AHB协议要求:地址必须与传输大小对齐。什么意思?
- 8位传输:地址可以是任意值
- 16位传输:地址必须是2的倍数(0、2、4、6...)
- 32位传输:地址必须是4的倍数(0、4、8、C...)
你可能会问:如果不对齐会怎样?嗯,协议里说这是“未定义行为”。说白了,就是芯片可能正常工作,也可能死给你看。我建议你永远不要依赖未定义行为。
避坑指南:我曾经在一个项目中,软件工程师传了一个未对齐的地址给硬件。结果硬件没做保护,直接用了低两位地址做字节选通。最后数据写到了错误的字节位置。这个bug查了整整一周。所以,我建议你在RTL里加一个地址对齐检查,发现不对齐就报ERROR。
另外,HSIZE信号除了表示传输大小,还隐含了数据总线的宽度信息。比如HSIZE=2(4字节)时,数据总线至少是32位。如果总线是64位,HSIZE=2表示一次只传32位有效数据,另外32位是无效的。
4.3 响应信号:OKAY、ERROR、RETRY、SPLIT
响应信号HRESP[1:0]是AHB协议里最值得细说的部分。它只有2位,但包含了4种状态。我刚开始学的时候,总觉得RETRY和SPLIT差不多,后来踩了坑才明白它们的区别。
| HRESP[1:0] | 响应类型 | 含义 |
|---|---|---|
| 00 | OKAY | 传输成功完成 |
| 01 | ERROR | 传输失败 |
| 10 | RETRY | 重试(总线不释放) |
| 11 | SPLIT | 拆分(总线释放) |
4.3.1 OKAY
这个最简单。传输正常完成。你给地址,从设备说“收到,数据给你”。一拍搞定。
4.3.2 ERROR
传输出错了。比如地址越界、保护错误、奇偶校验失败等等。从设备返回ERROR时,数据线上的值是不可靠的。主设备收到ERROR后,应该放弃这次传输。
我记得有一次,一个从设备地址译码逻辑写错了,导致所有访问都返回ERROR。主设备那边一直重试,系统直接卡死。嗯,所以ERROR响应一定要配合合理的错误处理机制。
4.3.3 RETRY
RETRY的意思是:“我现在忙,你等会儿再来问。”但注意,总线不释放。也就是说,从设备占着总线,其他主设备没法用。这其实是个很“霸道”的做法。
你想想看,如果从设备一直说RETRY,那总线就被它一个人占着,其他主设备都干瞪眼。所以RETRY一般只用于很快就能处理完的情况,比如内部FIFO满了一两个周期。
小技巧:我建议你在设计从设备时,尽量少用RETRY。如果处理时间超过几个周期,用SPLIT更合适。RETRY用多了,总线利用率会直线下降。
4.3.4 SPLIT
SPLIT和RETRY最大的区别是:SPLIT会释放总线。从设备说:“我现在忙,你先去干别的,等我准备好了再通知你。”然后总线仲裁器就可以把总线分配给其他主设备。
SPLIT的实现比较复杂。从设备需要记住哪个主设备在等它,然后通过SPLIT完成信号(HSPLIT)通知仲裁器。仲裁器再重新把总线给那个主设备。
说实话,SPLIT在低端芯片里用得不多。因为实现成本高,而且容易出bug。我参与过的一个项目里,SPLIT逻辑占了从设备将近30%的面积。后来我们评估了一下,其实用RETRY加短等待也能接受。
4.4 突发传输中的响应时序
突发传输中,每个数据拍都可以有不同的响应。但要注意:只有最后一拍可以返回ERROR。为什么?因为如果中间某一拍返回ERROR,前面的数据已经传了,后面的数据还没传,这状态就乱了。
举个例子:一个INCR4传输,第1拍OKAY,第2拍OKAY,第3拍ERROR。那么第4拍怎么办?协议规定:从设备在返回ERROR后,必须继续完成剩余的传输拍数,但数据无效。主设备收到ERROR后,应该丢弃之前收到的所有数据。
重要:突发传输中,如果从设备想终止传输,应该在最后一拍返回ERROR。中间拍只能返回OKAY、RETRY或SPLIT。这是很多新手容易犯的错误。
好了,这一章的内容就这些。突发传输、对齐、响应信号,这三个知识点是AHB协议的核心。你把这些搞懂了,AHB协议就算入门了。下一章我们聊聊AHB的仲裁和地址译码,那又是另一番天地。