3、AHB协议详解(一):AHB信号定义、单次传输与流水线、地址与数据相位
各位同学,今天我们来啃AHB协议这块硬骨头。说实话,AHB是我在项目中打交道最多的总线协议之一,也是很多新人容易踩坑的地方。我个人习惯把AHB协议拆成三块来理解:信号怎么接、传输怎么走、时序怎么对。咱们今天先讲前两块。
3.1 AHB信号定义:别被一堆信号吓到
第一次看AHB协议文档,你可能会被几十个信号搞得头晕。其实说白了,核心信号就那么几类。我当年刚入行时,师傅跟我说:「你先记住这10个信号,其他的都是衍生品。」
咱们先看最关键的几个:
| 信号名 | 方向 | 宽度 | 说明 |
|---|---|---|---|
| HCLK | 输入 | 1 | 总线时钟,所有信号都在上升沿采样 |
| HRESETn | 输入 | 1 | 异步复位,低有效 |
| HADDR[31:0] | Master→Slave | 32 | 地址总线 |
| HWDATA[31:0] | Master→Slave | 32 | 写数据总线 |
| HRDATA[31:0] | Slave→Master | 32 | 读数据总线 |
| HWRITE | Master→Slave | 1 | 写使能:1为写,0为读 |
| HSIZE[2:0] | Master→Slave | 3 | 传输大小:字节、半字、字等 |
| HBURST[2:0] | Master→Slave | 3 | 突发类型:单次、增量、回绕等 |
| HTRANS[1:0] | Master→Slave | 2 | 传输类型:IDLE、BUSY、NONSEQ、SEQ |
| HREADY | Slave→Master | 1 | 从机准备好信号,高有效 |
| HRESP[1:0] | Slave→Master | 2 | 传输响应:OKAY、ERROR、RETRY、SPLIT |
3.2 单次传输:最基础的读写操作
单次传输,说白了就是Master发一个地址,Slave回一个数据。听起来简单,但时序细节不少。
先看一个最简单的写操作:
// 单次写传输时序示例
// 时钟周期 T1: Master 驱动地址和控制信号
// 时钟周期 T2: Master 驱动写数据,Slave 采样地址
// 时钟周期 T3: Slave 完成写操作,拉高 HREADY
always @(posedge HCLK or negedge HRESETn) begin
if (!HRESETn) begin
HADDR <= 32'b0;
HWRITE <= 1'b0;
HWDATA <= 32'b0;
end else begin
// 假设状态机控制
if (start_transfer) begin
HADDR <= addr;
HWRITE <= 1'b1; // 写操作
HWDATA <= wdata;
end
end
end
嗯,这里要注意:地址和数据不是同时有效的。地址先出来,数据要等一个周期。为什么?因为Slave需要时间解码地址,决定把数据写到哪个寄存器里。
读操作稍微有点不同:
// 单次读传输时序示例
// T1: Master 发地址
// T2: Slave 采样地址,开始准备数据
// T3: Slave 通过 HRDATA 返回数据
// Slave 侧逻辑
always @(posedge HCLK) begin
if (HWRITE == 1'b0 && HTRANS == NONSEQ) begin
// 采样地址,准备读数据
read_addr <= HADDR;
// 数据在下一个周期准备好
HRDATA <= mem[HADDR];
end
end
3.3 地址与数据相位:流水线的核心思想
AHB最巧妙的设计就是地址相位和数据相位分离。你想想看,如果每次都要等数据回来才能发下一个地址,那效率得多低?
流水线的思路是这样的:
- 地址相位:Master在T1发地址,持续一个周期
- 数据相位:Slave在T2返回数据,可能持续多个周期(如果HREADY拉低)
- 关键点:T2的地址相位可以和T1的数据相位重叠
我画个简化的时序图帮你理解:
// 流水线传输示例(背靠背传输)
// 时钟: T1 T2 T3 T4
// 地址: A1 A2 A3 A4
// 数据: --- D1 D2 D3
// HREADY: 1 1 1 1
// 注意:A2的地址相位和D1的数据相位在T2重叠
为什么会这样设计?说白了就是为了提高总线利用率。如果每次传输都要等两个周期,总线利用率只有50%。用了流水线后,理想情况下可以达到接近100%。
但这里有个坑:如果Slave来不及处理怎么办?比如Slave是个慢速外设,读一次要等10个周期。这时候Slave会把HREADY拉低,Master就得等着。
3.4 实际项目中的经验总结
我在几个项目里验证过AHB接口,总结了几条经验:
- 地址对齐别搞错:HSIZE=2(字传输)时,地址最低两位必须是0。我见过有人写地址0x04传一个字,结果Slave把数据写到了0x05开始的位置——因为地址没对齐。
- HTRANS状态机要严谨:IDLE、BUSY、NONSEQ、SEQ这四个状态,跳转条件必须覆盖全。漏掉一个分支,仿真可能跑飞。
- HREADY的默认值:如果总线上只有一个Slave,HREADY默认拉高。如果有多个Slave,需要通过地址译码器给每个Slave分配地址空间,没被选中的Slave要把HREADY拉高(表示不参与传输)。
- 复位后的第一个传输:复位后Master必须先发一个IDLE传输,再发NONSEQ。直接发NONSEQ可能会被Slave当成非法操作。
好了,今天的内容就到这里。AHB的信号定义和单次传输是基础中的基础,后面的突发传输、Split传输、仲裁机制都是在这个基础上扩展的。下一讲我们会深入突发传输和地址边界对齐的问题——那个才是真正考验功底的地方。
记住:验证AHB接口,先把HCLK、HREADY、HTRANS这三个信号盯死。这三个信号不出错,后面就稳了。