新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > 嵌入式软件开发之: 基于ARM处理器的嵌入式系统设计

嵌入式软件开发之: 基于ARM处理器的嵌入式系统设计

作者:时间:2013-09-30来源:网络收藏

本文引用地址:http://www.eepw.com.cn/article/257030.htm

本章主要介绍嵌入式应用程序的设计方法。本章中的一些实例程序是以ARM公司的Realview2.2为开发平台。由于目前嵌入式应用环境相差非常大,这里主要是通过这些实例程序来更直接地介绍嵌入式应用系统的开发方法,具体的代码因具体的嵌入式环境不同而有所差异。

13.1 基于设计

ARM系列处理器是RISC(Reducded Instruction Set Computing)处理器。很多基于ARM的高效代码的程序设计策略都源于RISC处理器。和很多RISC处理器一样,ARM系列处理器的内存访问也要求数据对齐,即存取“字(Word)”数据时要求四字节对齐,地址的bits[1:0]=0b00;存取“半字(Halfwords)”时要求两字节对齐,地址的bit[0]=0b0;存取“字节(Byte)”数据时要求该数据按其自然尺寸边界(Natural Size Boundary)定位。

ARM编译程序通常将全局变量对齐到自然尺寸边界上,以便通过使用 LDR和STR指令有效地存取这些变量。

这种内存访问方式与多数CISC(Complex Instruction Set Computing)体系结构不同,在CISC体系结构下,指令直接存取未对齐的数据。因而,当需要将代码从CISC体系结构向 移植时,内存访问的地址对齐问题必须予以注意。在RISC体系结构下,存取未对齐数据无论在代码尺寸或是程序执行效率上,都将付出非常大的代价。

注意

在ARM11处理器上,新增加了支持非内存对齐数据访问的硬件,此结构在本章中不作讨论。

下面将从4个方面详细讨论在ARM体系结构下的程序设计:

· 未对齐指针;

· 结构体中的

· 用于半字存取的Load指令;

· 移植代码并检测非对齐存取。

13.1.1 未对齐的

C和C++编程标准规定,指向某一数据类型的指针,必须和该类型的数据地址对齐方式一致,所以ARM编译器期望程序中的C指针指向存储器中字对齐地址,因为这可使编译器生成更高效的代码。

比如,如果定义一个指向int数据类型的指针,用该指针读取一个字,ARM 编译器将使用LDR指令来完成此操作。如果读取的地址为4的倍数(即在一个字的边界)即能正确读取。但是,如果该地址不是4的倍数,那么,一条LDR指令返回一个循环移位结果,而不是执行真正的未对齐字载入。循环移位结果取决于该地址相对于字的边界的偏移量和系统所使用的端序(Endianness)。例如,如果代码要求从指针指向的地址0x8006载入数据,即要载入0x8006、0x8007、0x8008和0x8009 4个字节的内容。但是,在上,这个存取操作载入了0x8004、0x8005、0x8006和0x8007字节的内容。这就是在未对齐的地址上使用指针存取所得到的循环移位结果。

因而,如果想将指针定义到一个指定地址(该地址为非自然边界对齐),那么在定义该指针时,必须使用__packed限定符来定义指针:

例如:

__packed int *pi; // 指针指向一个非字对其内存地址

使用了__packed限定符限定之后,ARM编译器将产生字节存取命令(LDRB或STRB指令)来存取内存,这样就不必考虑指针对齐问题。所生成的代码是字节存取的一个序列,或者取决于编译选项、跟变量对齐相关的移位和屏蔽。但这会导致系统性能和代码密度的损失。

值得注意的是,不能使用__packed限定的指针来存取存储器映射的外围寄存器,因为ARM编译程序可使用多个存储器存取来获取数据。因而,可以对实际存取地址附近的位置进行存取,而这些附近的位置可能对应于其他外部寄存器。当使用了位字段(Bitfield)时,ARM程序将访问整个结构体,而非指定字段。

13.1.2 结构体中

与全局变量位于其自然尺寸边界相同,结构体(Structure)中的域字段(Filed)也如此。也就是说编译程序经常要在字段间插入填充字节(Padding)来确保域字段对齐。当编译程序插入填充字节时,编译器将产生以下警告信息。

#1301-D: padding inserted in struct mystruct

可以使用-remark编译选项使编译器产生备份信息,或使用-diag_warning选项选择编译器产生的备份信息。

如果不希望编译器产生填充字节,可以使用__packed限定符来创建字段之间没有填充字节的结构,且这些结构需要非对齐存取。

如果ARM编译器能够确定所访问结构体的对齐方式,那么它就可以自动识别所存取结构体中的字段的对齐方式。在这些情况下,编译程序尽可能地采用更有效的对齐字或半字存取方式。否则,编译器将使用多个对齐存储器存取(LDR、STR、LDM和STM)与固定移位和屏蔽相结合来存取存储器中的字节。

对非对齐元素的存取是通过内联还是通过调用一个函数来完成,由编译程序-Ospace(默认,调用一个函数)和-Otime(执行非对齐存取内联)选项来控制。

例如:

创建一个名为foo.c源文件。

__packed struct mystruct {

int aligned_i;

short aligned_s;

int unaligned_i;

};

struct mystruct S1;

int foo (int a, short b)

{

S1.aligned_i=a;

S1.aligned_s=b;

return S1.unaligned_i;

}

使用armcc -c -Otime foo.c编译。所生成的代码为:

MOV r2,r0

LDR r0,|L1.84|

MOV r12,r2,LSR #8

STRB r2,[r0,#0]

STRB r12,[r0,#1]

MOV r12,r2,LSR #16

STRB r12,[r0,#2]

MOV r12,r2,LSR #24

STRB r12,[r0,#3]

MOV r12,r1,LSR #8

STRB r1,[r0,#4]

STRB r12,[r0,#5]

ADD r0,r0,#6

BIC r3,r0,#3

AND r0,r0,#3

LDMIA r3,{r3,r12}

MOV r0,r0,LSL #3

MOV r3,r3,LSR r0

RSB r0,r0,#0x20

ORR r0,r3,r12,LSL r0

BX lr

其中,“|L1.84|”为结构体mystruct在内存中的地址。

c++相关文章:c++教程



上一页 1 2 下一页

评论


相关推荐

技术专区

关闭