AXI4 CACHE PROT 属性:ARCACHE/AWCACHE 编码与 AxPROT 特权安全位
更新时间:2026-09-25。本文承接 AXI4 完整协议 与 AXI4 burst 类型与边界,专攻地址相位上两组「元数据」信号:它们不传数据,却决定这笔事务被怎么缓存、被谁放行。验证环境里,属性配错往往不报错、但系统行为悄悄走样,是典型的高潜伏坑。
本文要回答的问题
- ARCACHE/AWCACHE 的 4 个 bit 各是什么含义?bufferable 和 modifiable 差在哪?
- Device、Normal Non-cacheable、Write-through、Write-back 各自编码是多少?
- read-allocate / write-allocate 两个提示位在读、写事务上怎么解释?
- AxPROT 三个 bit 分别代表什么?firewall 和桥怎么消费它?
一、属性是地址相位上的元数据
AxCACHE 和 AxPROT 都挂在**读地址通道(AR)和写地址通道(AW)**上,随 AxVALID 一起发出,整笔 burst 内保持不变。它们不参与数据搬运,只回答两个问题:这笔访问指向的内存该怎么处理(CACHE)、发起访问的是谁(PROT)。
读写通道的属性信号分别叫 ARCACHE[3:0]、AWCACHE[3:0] 和 ARPROT[2:0]、AWPROT[2:0],编码规则完全相同,但允许 master 给读、写打不同的值。属性只在地址相位出现一次,数据相位(W、R)上没有对应信号,所以从机必须在地址拍把属性和 AxID、AxADDR 一起存下来,服务后续每一拍;WSTRB 只选字节 lane,不改变内存类型。
一个 SoC 的地址映射表通常在每个地址窗旁直接标注默认属性,软件和 RTL 都照这张表走。典型样例如:0x0000_0000–0x7FFF_FFFF 的 DDR 标 Normal Write-back(1111),0x8000_0000 附近的片内 SRAM 标 Normal Non-cacheable 或 Write-through,0x4000_0000 起的 UART/I2C/GPIO 寄存器窗标 Device Non-bufferable(0000),安全引擎所在窗口额外只对 Secure PROT 开放。DMA 引擎拿到一个目标地址后该打什么属性,本质上就是查这张地址映射表——很多 DMA 描述符里干脆有一个字段让软件直接指定 cache/prot 编码。
二、ARCACHE/AWCACHE:逐 bit 拆解
4 个 bit 从低到高分别是 bufferable、modifiable、read-allocate、write-allocate:
| bit | 名称 | 置 1 的含义 |
|---|---|---|
| [0] | Bufferable | 互连可以先收下事务、稍后再送达终点;写响应可以在数据真正到达终点前返回 |
| [1] | Modifiable | 互连可以修改事务形态:拆包、合并、宽度转换、多读一些数据 |
| [2] | Read Allocate | 建议读缺失时在 cache 中分配一行 |
| [3] | Write Allocate | 建议写缺失时在 cache 中分配一行 |
**Bufferable(bit0)**只影响「到达时间」。对写事务:非 bufferable 时,BRESP 必须等数据真正被终点接受后才能返回;bufferable 时,互连入口的写缓冲即可给应答,终点稍后再慢慢收。读事务天然要等数据回来,bit0 对读基本没有实际意义,通常输出 0。
**Modifiable(bit1)**影响「事务形态」。置 1 后,互连允许做读预取(多读几个字节)、把多个小事务合并成一笔大 burst、或在宽窄端口之间做拆包拼包。典型场景:64 位主口后面挂着 32 位的 SRAM,upsizer 可以把两笔相邻的 32 位访问攒成一笔 64 位;CPU 读一个字,互连可以顺手把整行都取回来供后续命中。置 0 时事务必须原样抵达:一次 4 字节的写就是一次 4 字节的写,不能被合并进邻居,也不能被拆成两笔。Device 内存强制 bit1=0 正是这个原因——对控制寄存器多写一个字节、多发一拍,都可能触发意料之外的硬件动作。
两个 allocate bit 是提示而不是命令,cache 可以自行决定听不听。一个容易读错的细节:bit2/bit3 的解释随事务方向变化——
- 读事务上 bit2(RA)置位 = 本次读缺失建议分配;bit3(WA)置位是给 cache 的前瞻提示:这片区域很快会被写,可提前为写分配做准备。
- 写事务上 bit3(WA)置位 = 本次写缺失建议分配;bit2(RA)置位是反向提示:这片区域很快会被读。
规约还要求:两个 allocate bit 只有在 bit1(modifiable)为 1 时才允许置 1。出现 allocate 位而 modifiable 为 0 的组合属于非法编码。
bufferable 改变的另一个关键点是顺序点。non-bufferable 写的顺序点在终点寄存器,BRESP 返回意味着硬件已经执行了这次写;bufferable 写的顺序点只在互连入口,BRESP 返回只代表「系统收下了」,终点可能几百拍后才看到。软件清一个中断标志、然后马上开中断,如果这次写是 bufferable 的,中断可能在写真正到达外设前先被重新放行。对这类「必须先落地再继续」的序列,要走 non-bufferable,或在中间插一次读回做屏障。

三、内存类型:Device 与 Normal
bit1 同时承担内存类型划分:bit1=0 是 Device,bit1=1 是 Normal。
Device 内存面向外设寄存器、FIFO、门铃(doorbell):事务必须原样、按序到达终点,不能预取、不能合并、不能因为「优化」多发一次——对状态寄存器多读一次都可能清掉标志位。Normal 内存面向 SRAM、DDR:允许合并、预取、缓存,是性能优化的前提。
Device 内部再用 bit0 区分 bufferable / non-bufferable:Device Bufferable 只适合「写一次就走、不需要确认落地」的场景,比如通知对端引擎开工的门铃;控制寄存器和任何需要读回确认的位置都应该用 Device Non-bufferable。Normal 的非缓存形态同理,但 Normal Non-cacheable 事务仍然是 modifiable 的,互连可以合并、预取和做宽度转换,这是它和 Device 的本质差别,不能因为「都不进 cache」就把两者混为一谈:
| 编码 | 内存类型 | 典型落点 |
|---|---|---|
0000 | Device, Non-bufferable | 外设寄存器(默认、最安全) |
0001 | Device, Bufferable | 只写一次的门铃、流式写端口 |
0010 | Normal, Non-cacheable, Non-bufferable | 共享内存、描述符 ring |
0011 | Normal, Non-cacheable, Bufferable | 非缓存但可缓冲的大块写 |
选择路径可以按下面的矩形决策图理解:先按「终点是寄存器还是内存」分 Device/Normal,再按「要不要落 cache」分 Non-cacheable 与缓存型。
四、缓存型组合:Write-through 与 Write-back
bit1=1 且 allocate 位参与编码时,规约定义了六种缓存型组合。下表是工程上最常用的编码速查(读、写通道同表,按事务方向解释 RA/WA):
| 编码 | 写策略 | 分配提示 |
|---|---|---|
0110 | Write-through | No allocate |
0111 | Write-through | Write allocate |
1010 | Write-back | No allocate |
1011 | Write-back | Write allocate |
1110 | Write-through | Read allocate |
1111 | Write-back | Read allocate |
表中的 No allocate(0110/1010)表示即使事务可缓存,缺失时也不在本 cache 分配行——典型用途是绕过 cache 的流式大数据扫描:视频帧顺序读一遍、永不复用,分配进来只会把热数据挤出去。CPU 实际发出的编码随页表属性(页表里的 cacheable/bit、write-allocate 位)生成,软件改页表内存类型,总线上看到的 CACHE 编码就跟着变。
两种写策略的差别在脏数据什么时候出门:
- Write-through(写穿透):每次写都同时更新 cache 和下游内存,内存始终是新的;写流量直接压到总线上,优点是简单、一致性好,缺点是带宽开销大。
- Write-back(写回):写只落 cache,把整行标脏,等行被替换或软件做 cache 维护(clean/flush)时才整行写回;总线流量小,但需要脏位、替换逻辑和维护操作配合(DMA 与 cache 共享内存时必须先 clean,见 DMA cache 维护)。
write-allocate 在写缺失时还有一个隐蔽动作:cache 通常要先把整行从内存读回来(read-for-ownership,读且获得独占权),再合并本次写入。也就是说一个标着 write-allocate 的 4 字节写,下游可能看到一笔完整的 WRAP line 填充加后续写回。这就是为什么访问属性会和 burst 类型联动:cacheable 的内存访问在总线上几乎总是以对齐的 cache line 事务出现,而软件最初发出的可能只是一个 store。理解这条链路,调试「我只写了 4 字节,为什么总线上冒出整行读」时才不会误判成 RTL 错误。
五、AxPROT:访问者的三张身份标签
AxPROT[2:0] 描述「谁在访问」,三个 bit 互相独立:
| bit | 0 | 1 |
|---|---|---|
| [0] Privileged | 非特权(用户态) | 特权(内核态) |
| [1] Non-secure | Secure 安全态 | Non-secure 非安全态 |
| [2] Instruction | Data 数据访问 | Instruction 取指访问 |
几个常见组合:Linux 用户态取指 = 101(指令、非安全、非特权),内核态数据访问 = 010(数据、非安全、特权),安全世界固件 = 000。注意 bit1 是反相命名(0 才是 Secure),接错成高有效是 TrustZone 过滤最常见的低级错误。
三个 bit 的消费动机各不相同:特权位让系统外设(比如中断控制器的管理寄存器)只接受内核态访问,用户态驱动碰这些地址直接被 firewall 挡回;安全位是 TrustZone 的分界线,安全 RAM、安全密钥引擎只对 Secure 事务开窗;指令位主要给 I-cache 和取指通路用——取指访问可以被当作只读、只在 I-cache 分配,数据写绝不允许走 I-cache 通道,这也是自修改代码必须显式做 I-cache 失效的原因。简单的 DMA 引擎通常恒输出数据 + 非安全 + 非特权(000/010 由软件配置),它本身没有特权概念,访问权限由驱动软件把它指向合法地址窗来保证。AXI5 在 PROT 上又扩展了 bit3(NSNE,Non-secure Non-early 早期总线观察位),并把更丰富的内存类型移到独立信号,但 AXI4 系统只需关心上述三位。
六、这些属性被谁消费
- Interconnect:modifiable 决定宽窄转换、拆包合并单元能不能动手;bufferable 决定入口能不能插写缓冲;PROT 接 firewall 做权限过滤(实现细节见 总线 firewall 与 TrustZone 过滤 与 AXI crossbar 互连)。
- Cache:内存类型决定查不查 cache;allocate 提示决定缺失时分不分配;WT/WB 决定脏数据出门时机。cache 行内还要记录归属的安全/非安全身份,防止跨世界偷看。每一行还带有自己的内存类型标签,软件改页表把一段内存从 cacheable 改成 Device 时,必须先把旧行 clean 并 invalidate,否则 cache 里可能还留着按旧属性缓存的数据,总线上却是新属性,两边对同一份内容各说各话——这类「属性切换」序列在驱动初始化和休眠恢复路径上真实出现,验证时要覆盖。
- 桥:AXI 转 AHB 时,AxPROT 映射到
HPROT,ARCACHE/AWCACHE 映射到 HPROT 的 cacheable/bufferable 位;转 APB5 时映射到PPROT。映射规则见 APB/AHB 外设桥。外设侧通常只接受 Device/Non-cacheable 编码,桥遇到 cacheable 事务要么拒绝、要么按配置降级。 - DDR 控制器:Non-cacheable 与 Device 事务要保证顺序点,cacheable 的写回整行可以和其他事务一起重排调度。
互连在转发时能不能改写属性,规约有方向性约束:bufferable 可以「加上」(non-bufferable 事务可以被缓冲),modifiable 事务可以被进一步变换或降级,但 Device 事务永远不能被升级成可修改/可缓存——一旦升级,合并和预取带来的额外访问就可能打到寄存器上。PROT 的安全位必须原样传播,非安全事务绝不能在某个端口被洗成安全事务;特权位也只允许由 firewall 做减法检查。AXI5 为了堵住实现歧义,把「谁可以改、能改哪些位」写成了显式的信号(如 AxMMUSID、NSE 等),AXI4 则靠上述约定和集成时的配置保证。
七、常见的坑
- 外设访问被打成 cacheable:写 FIFO/寄存器被合并或缓存,动作丢失,状态位读到的也是旧值。正确搭配是
0000+ FIXED(见 AXI4 burst 类型与边界)。 - allocate 位置了但 modifiable=0:非法编码,严格从机应回 SLVERR,宽松从机可能直接行为错乱;DV 里要定向约束并反向测试这种组合。
- bufferable 当成「写成功」:提前拿到的 BRESP 只代表进了缓冲,复位或时钟门控一来,缓冲里的事务可能整批丢失;要确认落终点必须用 non-bufferable 事务或读回校验。低功耗设计里这点尤其要小心:进低功耗前如果没有等缓冲排空,醒来后外设状态和软件以为的完全对不上。
- PROT bit1 极性接反:安全事务被当非安全、直接被 firewall 拦死;非安全事务被当安全则更危险,属于越权放行。信号名
NONSEC高有效,和 bit 值语义要逐位对,集成评审时把 master 输出、互连配置、firewall 窗口表三处放在一起核。 - 所有 master 默认输出全 0 就以为安全:全 0 确实是最保守的 Device/安全/特权组合,但 DMA 打内存也用全 0 会让带宽和 cache 全部失效——属性要按落点配,不是一律清零。
八、DV 验证关注点
属性信号位宽小、不直接产出数据,最容易在验证计划里被漏掉,建议按下面三层建检查点:
- 协议合法层:约束 allocate 位与 modifiable 的依赖(RA/WA=1 必须 bit1=1);ARCACHE bit0 读侧固定为 0;属性在 burst 全程稳定。这些写 SVA 即可,非法组合定向反向测试从机响应。覆盖率上,CACHE 要把 16 个编码与 RA/WA 方向交叉,PROT 要把 8 个编码打全,只随机出现
0000和1111的环境等于没验属性。 - 行为层:选 Device/Non-cacheable/WT/WB 四个代表编码端到端跑:Device 写必须原样到终点、不能出现合并或多写,WT 写后内存立即可见,WB 写后在 clean 前内存不变、clean 后整行写回;bufferable 写检查 BRESP 可以早于终点接受,且最终送达内容和顺序不能丢。
- 过滤层:PROT 与 firewall 地址窗矩阵交叉,越权组合(用户态打特权寄存器、非安全打安全 RAM、取指访问数据区)必须收到错误响应且无副作用,重点检查「被拒事务不能已经改了终点状态」。
参考模型侧,scoreboard 要把属性纳入事务记录:同地址、不同安全身份的访问不能命中同一份期望内存,否则非安全访问读到安全区旧值会被错误放行。
这一篇在知识体系里的位置
协议骨架见 AXI4 完整协议;地址推进规则见 AXI4 burst 类型与边界;权限过滤实现见 总线 firewall 与 TrustZone 过滤;cache 内部组织见 Cache 组织与替换,多核一致性见 MESI 缓存一致性;DMA 视角的属性处理见 DMA cache 维护。
总结
ARCACHE/AWCACHE 四位 = bufferable(可缓冲)、modifiable(可改形态)、read/write-allocate(缺失分配提示):bit1=0 是 Device(0000/0001),bit1=1 是 Normal(0010/0011 非缓存,0110–1111 按 Write-through/Write-back 与分配组合编码);AxPROT 三位分别是特权、非安全(1=NS,注意极性)、指令位,被互连 firewall、cache 和 AHB/APB 桥逐位消费——属性必须按落点配,外设清零、内存按缓存策略编码。