在途事务复位处理:fatal 复位丢弃在途、Q-Channel 温和停与复位后重建
更新时间:2026-09-28。本文是「集成电路大类 · 芯片设计」复位与总线交叉主题的一篇长尾文。复位同步器:异步断言同步释放 讲了复位信号本身怎么安全地进出时序逻辑,AXI4 事务完整生命周期 讲了一笔事务从发起到写响应的全流程,但两篇都没回答一个工程上天天遇到的问题:复位沿到来的那一刻,总线上还有没收尾的事务,这些在途事务(inflight transaction)该杀、该等、还是该排?本篇把三种策略讲透。
本文要回答的问题
- 什么叫在途事务,复位瞬间它们具体卡在哪些状态?
- fatal 复位「直接丢弃」在什么时候是合法的,会留下什么后遗症?
- Q-Channel 握手怎么做到「温和停」:不再收新单、排空旧单再断电?
- 复位释放之后,主机的 outstanding 计数、互连的路由表、slave 的写缓冲怎么重建一致?
- 验证环境要怎么构造「复位打在读数据半路」的用例?
一、在途事务:复位瞬间的三种形态
一笔 AXI 事务从发出到完结要跨多个通道、多个时钟周期。复位沿到来的那一刻,在途事务通常处于三种形态之一:
| 形态 | 所处阶段 | 复位风险 |
|---|---|---|
| 地址已发、数据未收 | AW/W 或 AR 已握手,R/B 通道还空着 | slave 复位后忘掉这笔,主机永远等不到响应而死锁 |
| 数据收了一半 | 多拍读 R 通道传了 3 拍共 8 拍 | 主机缓冲里有半截数据,复位后不知道是继续还是作废 |
| 响应已发、主机未收 | B/R 最后一拍在 valid 上等 ready | slave 认为已完成,主机复位后不认账,写操作结果成谜 |
关键点在于:AXI 各通道之间没有全局状态机,"一笔事务"是主机和 slave 各自用 ID 计数器拼出来的逻辑概念。复位打掉的往往只是其中一端的状态,另一端还拿着旧 ID 在等,这就是在途事务问题比单模块复位难得多的原因。握手机制本身见 valid-ready 握手。
二、fatal 复位:直接丢弃的前提与代价
fatal 复位(硬复位、上电复位、看门狗咬死后的系统复位)的处理哲学是「不商量,全杀」:所有主机、互连、slave 进同一个复位域,在途事务连同状态一起清零。这条路合法的前提是复位域覆盖完整——只要有一个 slave 不在复位域里(比如外挂的、单独供电的 DDR 控制器),它就会带着旧状态醒来,把主机复位后的第一笔新事务错认成旧事务的延续。
丢弃在途的代价有三笔账:第一,数据一致性账——复位前发出的写可能已经改了 slave 的存储一半(写缓冲刷了一半),软件必须把这些区域标为脏、重跑;第二,死锁账——主机复位释放后 outstanding 计数清零,但如果互连里还残留着复位前的路由状态(比如互连不在同一复位域),新事务可能撞上幽灵 ID;第三,时间账——fatal 复位后软件要完整重走初始化和上下文恢复,毫秒级起步。所以 fatal 复位只该用在「系统已经谈不上正确性」的场景,正常功耗管理不该走这条路。
三、Q-Channel 温和停:先拒新单,再排空旧单
ARM 的低功耗接口(LPI)里的 Q-Channel 提供了「温和停」的标准做法。它是四信号握手:QREQn(请求停)、QACCEPTn(接受停)、QDENY(拒绝停)、QACTIVE(我还有活)。温和停的正确时序分四拍:
读这张图要抓住「先关门、后清场」的顺序:设备收到 QREQn 拉低后,第一件事是关入口——对 AXI slave 来说就是不再拉高 AW/AR 的 ready,新事务在主机侧排队而不是进来;第二件事才是等在途排空——内部 outstanding 计数器减到零、最后一拍 R/B 握手完成,这时才能拉低 QACCEPTn。顺序反了就是灾难:先接受静止再发现有在途,等于断电时腰斩事务,退化回 fatal 丢弃还丢了复位的一致性保证。QDENY 是给「排不空」留的逃生门:比如 slave 在等一个不会来的响应,与其死等不如拒绝本次静止请求,让系统管理器走超时升级(再不行才上 fatal 复位)。
QACTIVE 是反向的「唤醒雷达」:设备内部有任何可能导致它无法保持静止的活动(中断挂起、DMA 描述符待取),就拉高 QACTIVE,告诉控制器「别来烦我」或者「快把我叫醒」。clock-gating 级别的温和停与 power-gating 级别的进入/退出流程,可对照 低功耗模式进入与退出。
四、复位后重建:三方状态怎么重新对齐
无论走 fatal 丢弃还是 Q-Channel 排空,复位(或唤醒)之后都有一段「重建窗口」,三方各自的功课不同:
| 角色 | 复位后必须重建的状态 | 典型做法 |
|---|---|---|
| 主机 | outstanding ID 计数器、写缓冲、事务标签分配器 | 清零后从 ID 0 重新分配;软件侧重发被丢弃的写 |
| 互连 | 路由表、仲裁状态、per-ID 排序记分 | 复位到默认路由;仲裁器回到轮询初态避免饿死某端口 |
| slave | 写缓冲刷盘、寄存器默认值、内部 FSM | 写缓冲在复位前必须刷空或标记无效,禁止复位后补写 |
三方的重建动作可以画成一条时间线,看清谁先谁后、哪里是风险窗口:
这张图里最容易出事的不是 ①②(主控和互连的清零动作通常由复位信号硬连线保证),而是 ③ 的 slave 写缓冲——它是个「异步时钟域之外的记忆」,复位信号若没有显式接到写缓冲的有效位上,就不会被清。
最容易漏的是 slave 的写缓冲:复位前沿收到 W 通道数据、还没写进存储就复位了,如果 RTL 在复位后「好心」把缓冲里残留的数据补写进去,就制造了一次幽灵写。正确做法是复位信号直接清写缓冲有效位,宁可丢,不可补。互连侧的 ID 排序记分(保证同 ID 事务按序返回)也要随复位清空,否则新事务可能被排在复位前幽灵 ID 的后面,造成跨复位域的顺序错乱。复位域划分的系统方法见 复位设计 与 复位域交叉 RDC。
五、验证怎么考这件事
定向用例至少构造三个场景:复位沿精确打在 R 通道多拍传输中间(检查主机不死锁、不复用旧 ID);Q-Channel 静止请求与一笔新事务同时到达(检查「先关门」语义,新事务必须被拒在门外排队而不是漏进来);静止过程中 QACTIVE 突然拉高(检查中止静止、恢复服务的时序)。断言侧,QREQn 拉低到 QACCEPTn 拉低之间必须有「outstanding==0」的蕴含;复位释放后前 N 拍内任何通道不得出现复位前的旧 ID。覆盖率要统计「复位时各类在途形态」的命中,三种形态至少各一次,否则这个测试等于没做。
这一篇在知识体系里的位置
复位信号本身的安全进出见 复位同步器:异步断言同步释放,复位体系划分见 复位设计;事务生命周期全貌见 AXI4 事务完整生命周期,底层握手见 valid-ready 握手;温和停的功耗管理上下文见 低功耗模式进入与退出;跨复位域的结构性风险见 复位域交叉 RDC。
总结
在途事务复位处理只有三条路:fatal 复位全杀(前提是复位域覆盖完整,代价是数据脏、重恢复)、Q-Channel 温和停(先关入口拒新单、排空在途再确认静止,排不空就 QDENY 拒绝)、以及复位后三方重建(主机清 outstanding、互连清路由与 ID 记分、slave 写缓冲宁可丢不可补写)——验证必须用「复位打在 R 通道半路」这类定向用例加断言,确认三种在途形态都不会死锁也不会幽灵写。