AXI4 outstanding 与 ID 保序:多笔在途、乱序返回与死锁规避
更新时间:2026-09-19。本文是「芯片设计 · 进阶层」接口主题簇文章。前置阅读 AXI4 完整协议 讲清了五通道与 burst,valid/ready 握手 讲清了单拍转移规则;本篇解决「一笔没回来能不能发下一笔」以及「回来的顺序对不上号怎么办」。
本文要回答的问题
- 什么是 outstanding?它和带宽、延迟是什么关系?
- AXI 的 ID 信号起什么作用?为什么要允许乱序?
- 同 ID / 不同 ID 的保序规则分别是什么?
- Interconnect 里最常见的死锁是怎么形成的,怎么在 RTL 里规避?
一、outstanding:让请求在总线上「排队在途」
如果主机必须「发一笔地址 → 等这笔数据回来 → 再发下一笔」,那么整条通路在从机访问延迟(如 DDR 几十拍)内只有一拍在传数据,带宽利用率极低。AXI 的做法是地址通道与数据通道分离,主机可以连续发出多笔地址请求,这些尚未拿到响应的请求称为 outstanding(在途事务)。
时间拍 → 1 2 3 4 5 6 7 8
ARVALID ■■■ ■■■ ■■■ (连发 3 笔读地址)
ARRDY ■ ■ ■
RVALID ■■■■■ ■■■■■ ■■■■■ (从机隔延迟后陆续回数据)
└─────── 3 笔同时在途,流水线被填满 ───────┘- outstanding 深度:主机/从机各自能同时容纳的在途事务数。深度 N 意味着不必等前序响应即可发第 N 笔。
- 有效吞吐近似
min(接口宽度/拍, N / 往返延迟)。延迟越大,要打满带宽所需的 outstanding 深度就越大——这就是为什么访存通路常配 8/16/32 深度。 - 代价:每笔在途都要在从机/Interconnect 里占一个事务上下文表项(存地址、ID、长度、已返回拍数),深度越大面积越大,且乱序完成需要重排序缓冲。
二、ID:给每笔事务贴上「对号」标签
五个通道都带 ID:AWID(写地址)、ARID(读地址)、BID(写响应)、RID(读数据)、WID(AXI3 有、AXI4 已删除,写数据 ID 由 AWID 隐含)。它的核心用途是:当多笔事务在途时,标识返回的数据/响应属于哪一笔。
正因为有 ID,从机和 Interconnect 才被允许这样优化:
- 慢的事务(命中一个延迟很高的从机)不必堵住快的事务(命中一个立刻能回的从机);
- 不同端口、不同 ID 的事务可以并行、乱序完成,谁先就绪谁先回。
三、保序规则:同 ID 严格有序,不同 ID 可乱序
AXI 协议的排序模型可以浓缩成两条铁律:
- 同一 ID 的事务必须按发起顺序完成。 从机对同
ARID的两笔读,必须先回第一笔的全部 beat,再回第二笔;写响应BID同理。 - 不同 ID 的事务之间没有顺序保证,可以任意顺序完成。
| 情形 | 是否允许乱序 | 典型用途 |
|---|---|---|
| 同 ARID 多笔读 | 否,严格按序 | 单一发起者、要求程序序 |
| 不同 ARID 读 | 允许 | 多主机/多线程交错、快事务超慢事务 |
| 写数据 W(AXI4) | 同 AWID 内有序,不同 AWID 不可 interleave | 写数据通道全局不可穿插 |
| 读数据 R(AXI3) | 不同 RID beat 可 interleave | AXI4 已禁止读 interleave |
AXI3 → AXI4 的关键收紧:AXI4 禁止读数据交叉(no read interleaving),一笔读事务的 beat 必须连续发完再发下一笔;写数据本就不允许 interleave。这大幅简化了从机和 Interconnect 的数据 MUX,但仍保留「事务级乱序」能力。
主机侧若不能接受乱序(例如简单的取指/配置读),最省事的做法是全部使用同一个固定 ID,自然退化为保序;要利用乱序性能才给不同事务分配不同 ID,并在接收端按 RID 做重排序(reorder buffer)。
四、Interconnect 死锁:写数据通道的经典坑
多主机经 Interconnect 访问多从机时,写通路最容易死锁,根因是 AW 通道和 W 通道是两条独立的 valid/ready 流,到达从机的先后顺序不确定,而很多从机要求「先收齐 AW 才收 W」或反过来。
典型死锁环:
主机0:AW 已被仲裁到从机A,但 W 因 W 通道被主机1占满而发不出
主机1:AW 已被仲裁到从机B,但 W 同理被占住
从机:只在收到 AW 后才拉 WREADY;主机只在 W 发出后才推进
结果:AW 与 W 互相等待,环形依赖,全线停摆工程上的标准规避手段:
- 写数据重排序 / W-FIFO 关联 AW:在 Interconnect 内为每个在途写事务建表项,W 数据按内部 tag 缓存,保证在从机端口上「AW 与其 W 数据作为一对」按从机接受顺序提交,切断跨事务依赖环。
- 保证单端口上 AW 与 W 的配对深度:从机设计成 AW、W 任一先到都能各自缓存(
aw_done/w_done两个独立标志,参见 AXI4-Lite 从机 的做法),不强制先后。 - 限制 outstanding 并预留一个可排空表项:避免所有上下文表项被占满后无法接收「解锁」事务(与网络拥塞死锁同理)。
- 不要让 valid 依赖 ready:
valid一旦举起必须自保持,不能组合地等ready,否则环路上可能出现组合环路或活锁。
五、RTL 实现要点:一个在途表项的最小结构
支持 N 笔 outstanding 的从机/适配器,核心是一张深度 N 的表:
typedef struct packed {
logic valid; // 该表项占用
logic [3:0] id; // 事务 ID(回 RID/BID 用)
logic [7:0] len; // 剩余 beat 数
logic [31:0] addr; // 当前地址(burst 递增用)
} ax_slot_t;
ax_slot_t slot [0:N-1];
// 分配:AR 握手时找一个空表项存入;释放:该笔最后一个 beat 发出后清空
// 保序:同 ID 时只允许该 ID 最老的表项驱动 RVALID保序约束的实现关键:当某个 ID 最老的在途事务未完成时,即使同 ID 更新的事务已就绪也不允许它抢先返回——通常用一个「按 ID 记录最老表项指针」的 FIFO 或记分板(scoreboard)来仲裁 R 通道。
六、常见的坑
- 简单主机误以为响应保序。 给所有事务用了不同 ID 却没做 RID 重排序,结果慢读晚回、数据错配到错误的寄存器写——要么固定 ID,要么实现 reorder。
- outstanding 深度按理想延迟估算。 只算从机延迟、漏算 Interconnect 仲裁等待和刷新惩罚,实际带宽打不满;应按 P99 延迟留余量。
- 从机强依赖 AW 先于 W。 在多主机 Interconnect 下埋死锁;正确做法是 AW/W 各自可独立缓存。
- 表项泄漏。 异常提前终止(如 DECERR 早退、复位)没释放 outstanding 表项,跑久了表项被占满、总线挂死——每条退出路径都要释放槽位。
- 跨桥接丢 ID 宽度。 经窄 ID 桥(如 AXI-to-APB)后高位 ID 被截断,回来 BID/RID 与发出的对不上;桥接器需保证 ID 透传或主机只用桥支持的 ID 位宽。
相关与延伸
协议基础见 AXI4 完整协议 与 valid/ready 握手;从机寄存器写法见 AXI4-Lite 从机设计;多从机互连与仲裁见 AXI Crossbar 与 Interconnect;时序收敛加拍见 AXI 寄存器切片;仲裁公平性见 Round-Robin 仲裁器。
总结
AXI4 用「地址/数据通道分离 + 多笔在途」填满流水线拿带宽,用 ID 给在途事务对号:同 ID 严格保序、不同 ID 可乱序但接收端要重排序;Interconnect 必须把 AW/W 作为可独立缓存的一对来切断环形依赖,否则写通道极易死锁。