ARM学习(11)数据总线/地址总线访问数据过程理解

笔者来聊聊数据总线/地址总线访问数据过程

例子引入

笔者在实际项目中开发的时候,碰到了一个数据访问对齐的data abort 错误,其实这个错误之前就知道,CortexR5 学习的时候了解到的,(异常模式学习(CortexR5)),但是了解的相对比较浅,这次深入的探究一下。

正常来说,访问u32的数据,地址需要4Byte对齐,如果没有要求pack(1)字节对齐的话,如果出现奇数地址,报一个addr Aligment Failed的错误,相当于夸了两个四字节的地址访问。

问题如下:

typedef struct test_data_abort_struct{
u8 data_1;
u8 data_2;
u16 data_3;
u32 data_4;
u32 data_5;
}test_data_abort_t;

u32 test_data = 0x12345678;

void test_func()
{
    u8 *ptr = (u8*)&test_data;
    printf("ptr=%p\n",ptr);

    ptr++; /*产生奇数地址*/
    printf("ptr=%p\n",ptr);

    u32 value = *(u32*)ptr;  /*读取一个奇数地址的数据 */
    printf("value =%d ptr=%p\n",value ,ptr);

    test_data_abort_t* test_data_z = (test_data_abort_t*)&ptr;
    test_data_z->data_1 ++; /*访问 byte 读写*/
    test_data_z->data_2 ++; /*访问 byte 读写*/
    test_data_z->data_3 ++; /*访问 two byte 读写  奇数地址*/
    test_data_z->data_4 ++; /*访问 four byte 读写 奇数地址*/
    test_data_z->data_5 ++; /*访问 four byte 读写 奇数地址*/

    print("1=%d 1=%d 1=%d 1=%d 1=%d  addr=%p\n",test_data_z->data_1,
                                                test_data_z->data_2,
                                                test_data_z->data_3,
                                                test_data_z->data_4,
                                                test_data_z->data_5);
}

一般情况下,arm 大多数用在嵌入式设备中,对于性能有一些极致的要求,所以一些数据访问对地址对齐要求,比如双字节(word)或者 四字节 (dword)对齐,这样就可以提高数据访问速度。

这一点和x86 架构有很大区别,x86 本身对于地址对齐没有要求,但是看汇编,压栈出栈也是四字节对齐(可能是为了方便吧,感觉并不是提高速度,而是空间上管理方便),有一点相似性。

接着来说回这个问题,按照之前分分析,下面这条语句正常来说回触发异常,但是确实没有触发。

u32 value = *(u32*)ptr;  /*读取一个奇数地址的数据 */

真让我很郁闷,这不是说好的奇地址访问异常嘛,为什么没产生异常,没办法还得看手册。

本身这个处理器的架构是CortexR5,所以就找了相关手册,然后发现了其中的秘密,手册说明如下:

Instructions in the ARM architecture are aligned as follows:
 - ARM instructions are word-aligned. 
 - Thumb and ThumbEE instructions arehalfword-aligned. 
 - Java bytecodes are byte-aligned.

In the ARMv7 architecture, some load and store instructions support unaligned data accesses, as described in
Unaligned data access.

大体的意思就是 arm指令是四字节地址对齐,thumb指令是两字节地址对齐,java的字节编码单字节地址对齐(没有地址要求),但是在armv7的架构里面,一些load 和 store 指令是支持 非对齐数据访问的,正如下面描述的一样,

An ARMv7 implementation must support unaligned data accesses to Normal memory by some load and store
instructions, as Table A3-1 shows. Software can set the SCTLR.A bit to control whether a misaligned access to
Normal memory by one of these instructions causes an Alignment fault Data Abort exception.

根据上面的描述,可以看到有些指令确实是支持了非对齐访问(比如str、ldr等)。

所以我赶紧去查了汇编代码,发现指令确实落在了支持非对齐访问的指令里面,所以没有对齐也是正常的,


上面ldr r4,0x404AF08,可以从下面看到 0x404AF08 dcd 0x4084834,所以r4= 0x4084834,相当于从ldr r4,[r0] , 而r0=r4,0x404AF08

之后 adds r4,r4,#0x1,r4=0x4084835,如下面打印所示(实际板子运行打印数据)。

最关键的地方,ldr r6,[r4],此时r4为奇地址,但是支持访问,所以没有发生异常。

接着来看,系统控制器 system control register,上面的表格中写到,SCTLR.A 该bit 可以控制将严格控制对齐访问,由于默认是0,禁止严格访问的,所以碰到了笔者刚刚的问题,如果笔者修改该bit为1,则正常应该触发 data abort Aligment Fault。

inline u32 __get_sctlr()
{
    u32 __sctrl;
    __asm
    {
        mrc p15,0,__sctrl,c1,c0,0
    }
    return __sctrl;
}
inline void __set_sctlr(u32 __sctrl)
{
    __asm
    {
        mcr p15,0,__sctrl,c1,c0,0
    }
}

u32 sctrl = __get_sctlr();
printf("sctrl=%x\n",sctrl);
sctrl |=0x02;
printf("sctrl=%x\n",sctrl);

经过笔者这一顿操作,再次运行程序,可以看到程序触发异常。

再来确认一下发生异常的位置,可以看到pc = 0x404abc0,出错的数据地址 =0x4044835,恰好是刚刚r4+1的地址。

通过看汇编,确实是加载数据的时候出错了,说明之前的验证都是正确的。

地址/数据总线理解

文献参考

cortex_r5参考手册
armv7ar技术参考手册
CortexM3-M4权威指南
STM32F4参考手册

版权声明:
作者:ZhangYixi
链接:http://zyixi.xyz/682-2/
来源:一西站点
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
< <上一篇
下一篇>>
文章目录
关闭
目 录