ARM Cortex M33非对齐访问
前一阵子在某芯片上遇到了一个设计问题:芯片中的控制核为ARM Cortex-M33内核(SSE200 IP),并在芯片中存在多个物理地址并不连续的SRAM,其中M33 Local Mem地址范围为0x2000_0000, 另一内存地址为0x41xx_xxxx.
遇到的具体问题为,在locam memory中,任何的非对齐访问全是正常的,但是在0x41xx_xxxx为基地址的内存上,任何非对齐的访问将会导致芯片卡死。
后经过仿真分析发现,Cortex M33处理器,如果地址[31:29]为0或者1, arm在总线上会发出两个非对齐访问(胶水逻辑), 但如果[31:29]为2,则没有非对齐访问的操作。
后查找手册
根据Cortex-M33 TRM r1p0 38页:
对于Device类型的内存,不允许非对齐访问并会产生错误异常根据Cortex-M33 TRM r1p0 161页面:
对于Device类型的内容,非对齐访问的结果为不可预测,在Cortex-M33上会禅城非对齐的UsageFault。这里面奇怪的是在此芯片上并未产生Usage Fault(可被捕获),而是完全停止响应,似乎更像陷入到不可预测的锁死窗台,似乎和IP的配置有关?根据Armv8-M ARM(DDI0553 B.s), B7.11 Device memory:
- Device memory is a memory type that is assigned to regions of memory where accesses can have side effects.
- Device memory is not cacheable.
- …
- Any unaligned access to Device memory generates an UNALIGNED UsageFault exception
至此,已经知道arm对于不同的memory type(Normal/Device)使用了不同的访问逻辑, 那么对应到这个具体的出错案例,0x2000_xxxx 和 0x41xx_xxxx的memory type呢?
- 根据Armv8-M ARM, B8.1 System address map:
所以,0x41xx_xxxx在CM33下默认映射就是Device类型的访问,其根本不支持非对齐访问,这也正是这个问题的根源。
那么ARM为什么要这么约束呢?
根据AMBA总线AHB协议中地址的限定,其支持单字节,双字节,四字节的地址类型,双字节时,HADDR[0]=1’b0, 四字节时,HADDR[1:0]=2’b00。所以,当CPU遇到指令集发出非对齐访的ld/st时,那么就遇到了第一个问题:是否原封不动的发出总线请求:
- 如果原封不动的发出请求,则违反总线协议
- 如果在处理器外围增加胶水逻辑,负责拆分非对齐的总线请求,这样能做到对软件透明,但是会遇到另外一个问题:这个拆分对软件并不透明,对于外设寄存器这样的类型的访问,被拆分成两次以上独立的访问有可能与硬件的规划是冲突的,比如利用非对齐地址更改Bit8和Bit4, 加入硬件期待的时这两个Bit同时置位,但CPU却因为非对齐地址的问题这两个比特的更新被拆分为了两次操作完成,而这样的操作是软件、调试器不可感知的。
通过这样限定内存地址类型来调整CPU的行为似乎就显得非常合理了,SRAM类型的就为了满足软件的自由度可以进行自由拆分,而外设类型的地址访问,则考虑到某些硬件外设的特殊时许要求,则需要保持“as-is”这样的逻辑。
那么,这次遇到的0x41xx_xxxx地址的内存,其实也属于SoC架构的小疏忽了,不应该让一个SRAM类型的地址被映射到0x4xxx_xxxx这样的地址范围上,从而让ARM认为这是个Device, 而非SRAM。
而问题的修补办法只有软件限制非对齐访问,当然这样的访问也并非全是坏事:可以减少非对齐访问导致增加的额外周期,提高CPU对内存访问效率。