前言:ARM编译的时候有很多编译选项和浮点功能相关,要真正理解这些编译选项的选择,不仅仅要了解ARM的体系构建的基础知识,可能还需要了解一下ARM的历史。之后,真对这些再考虑到ARM编译选项就比较好理解和记忆了。
1 ARM 的发展历史
1.1 Acorn RISC Machine(简称ARM)
1978 年12月5日,物理学家Hermann Hauser和工程师Chris Curry,在英国剑桥创办了CPU公司(Cambridge Processing Unit),主要业务是为当地市场供应电子设备。1979年,CPU公司改名为Acorn计算机公司。80年代中期,Acorn的一个小团队要为他们的下一代计算机挑选合适的处理器,根据他们提供的技术需求,在当时的市场上无法找到合适的处理器,于是Acorn决定自己设计一个处理器。一个小团队仅仅用了18个月就完成了从设计到实现的全过程,这是一台RISC指令集的计算机,叫做Acorn RISC Machine(简称ARM)。后来Acorn公司没落了,而处理器设计部门被分了出来,组成了一家新公司。ARM公司主要设计ARM系列AISC处理器内核,它不生产芯片,只提供 IP 核。1985年第一个基于RISC指令集的ARM芯片是在1985年开始设计的,采用的是典型的32位RISC体系结构,其指令拥有4位的寄存器地址域,可以访问R0-R15这16个寄存器。而其他的寄存器只有在特殊的情况下才可以访问到。
ARM将其技术授权给世界上许多著名的半导体、软件和OEM厂商,每个厂商得到的都是一套独一无二的ARM相关技术及服务。利用这种合伙关系,ARM很快成为许多全球性RISC标准的缔造者。
1.2 ARM(Advanced RISC Machines)
In the late 1980s Apple Computer and VLSI Technology started working with Acorn on newer versions of the ARM core. In 1990, Acorn spun off the design team into a new company named Advanced RISC Machines Ltd.
1990年,ARM公司成立了。在ARM7中,将ARM体系结构完全扩展到32位(原来的ARM处理器只有26位的地址空间),并将主频提升到40MHz,另外还集成了一个8KB的Cache。比较有趣的是,ARM7可以支持一种称为"Thumb"的模式,可以运行新的16位指令。通过引入Thumb模式,只需要付出很少的硬件代价,就可以将代码的密度提升大约25%-35%,并使得应用的运行更为迅速。
1996年,StrongARM SA-110问世了,并成为嵌入式微处理器设计的一个里程碑。StrongARM SA-110可以工作在200MHz,而能耗不到1瓦。在体系结构上,
StrongARM将原来ARM中的三级流水线扩展到五级,在器件工艺上,大量采用了最新的体系结构和器件技术,大大降低了芯片工作时的能耗。1997年,Intel接管了StrongARM
ARM9EJ是ARM9E在Java支持上的增强版本。它采用了类似Thumb的机制,通过很少的硬件代价,使大多数Java虚拟机字节码可以加速执行,更为复杂的Java虚拟机字节码可以通过软件的方式执行。这样,使得Java虚拟机字节码的执行速度提升了大约8倍左右。这对于嵌入式场合的Java应用无疑是极其有效的。
2 ARM架构分类
3 ARM的命名规则
ARM命名规则:
第一个数字:系列名称:eg.ARM7、ARM9
第二个数字:Memory system
2:带有MMU
4:带有MPU
6:无MMU与MPU
第三个数字:Memory size
0:标准Cache(4-128k)
2:减小的Cache
6:可变的Cache
第四个字符:T:表示支持Thumb指令集
D:表示支持片上调试(Debug)
M:表示内嵌硬件乘法器(Multiplier)
I :支持片上断点和调试点
E:表示支持增强型DSP功能
5 NEON 简介
4 浮点数编译选项和ARM的版本
4.1 浮点的主要应用场景
VFP Applications
- Automotive control applications
- Powertrain
- ABS, Traction control & active suspension
- 3D Graphics
- Digital consumer products
- Set-top boxes, games consoles
- Imaging
- Laser printers, still digital cameras, digital video cameras
- Industrial control systems
- Motion controls
4.2 VFP的架构版本
- VFPv1 is obsolete. Details are available on request from ARM.
- VFPv2 is an optional extension to the ARM instruction set in the ARMv5TE, ARMv5TEJ and ARMv6 architectures.
- VFPv3 is an optional extension to the ARM, Thumb® and ThumbEE instruction sets in the ARMv7-A and ARMv7-R profiles. VFPv3 implementation is with either thirty-two or sixteen double word registers. The terms VFPv3-D32 and VFPv3-D16 distinguish between these two implementation options. Extending VFPv3 uses the half-precision extensions that provide conversion functions in both directions between half-precision floating-point and single-precision floating-point.
5 浮点编译选项汇总讨论
1 浮点类型-mfloat-abi
1.1 选项
-mfloat-abi=soft/softfp/hard支持3种类型,各类型含义如下:
soft
不使用硬件浮点单元,gcc使用软浮点库来完成浮点运算。适用于不含FPU的CPU。
softfp
使用硬浮点单元,会生成硬浮点指令,生成何种类型的硬浮点指令由-mfpu选项指定。调用接口的规则和soft选项一致。
hard
使用硬浮点单元,生成硬浮点指令。与softfp的区别在于调用接口的规则不同。
1.2 示例
1.2.1 示例代码float mul(float a, float b)
{
return a*b;
}
1.2.2 soft选项
编译及反汇编命令
arm-linux-gcc -Wall -march=armv7-a -mcpu=cortex-a9 -mfloat-abi=soft -c test.c
arm-linux-objdump -D test.o | less
生成的汇编指令
00000000 <mul>:
0: e92d4800 push {fp, lr}
4: e28db004 add fp, sp, #4
8: e24dd008 sub sp, sp, #8
c: e50b0008 str r0, [fp, #-8]
10: e50b100c str r1, [fp, #-12]
14: e51b0008 ldr r0, [fp, #-8]
18: e51b100c ldr r1, [fp, #-12]
1c: ebfffffe bl 0 <__aeabi_fmul>
20: e1a03000 mov r3, r0
24: e1a00003 mov r0, r3
28: e24bd004 sub sp, fp, #4
2c: e8bd8800 pop {fp, pc}
可以看出是调用__aeabi_fmul接口来进行浮点运算。
1.2.3 softfp选项
编译命令
arm-linux-gcc -Wall -march=armv7-a -mcpu=cortex-a9 -mfloat-abi=softfp -mfpu=vfpv3-d16 -c test.c
生成的汇编指令
00000000 <mul>:
0: e52db004 push {fp} ; (str fp, [sp, #-4]!)
4: e28db000 add fp, sp, #0
8: e24dd00c sub sp, sp, #12
c: e50b0008 str r0, [fp, #-8]
10: e50b100c str r1, [fp, #-12]
14: ed1b7a02 vldr s14, [fp, #-8]
18: ed5b7a03 vldr s15, [fp, #-12]
1c: ee677a27 vmul.f32 s15, s14, s15
20: ee173a90 vmov r3, s15
24: e1a00003 mov r0, r3
28: e28bd000 add sp, fp, #0
2c: e49db004 pop {fp} ; (ldr fp, [sp], #4)
30: e12fff1e bx lr
生成了vxxx的硬浮点指令。并且可以看出和soft一样,都是用r0,r1来传递形参。
1.2.4 hard
编译命令
arm-linux-gcc -Wall -march=armv7-a -mcpu=cortex-a9 -mfloat-abi=hard -mfpu=vfpv3-d16 -c test.c
生成的汇编指令
00000000 <mul>:
0: e52db004 push {fp} ; (str fp, [sp, #-4]!)
4: e28db000 add fp, sp, #0
8: e24dd00c sub sp, sp, #12
c: ed0b0a02 vstr s0, [fp, #-8]
10: ed4b0a03 vstr s1, [fp, #-12]
14: ed1b7a02 vldr s14, [fp, #-8]
18: ed5b7a03 vldr s15, [fp, #-12]
1c: ee677a27 vmul.f32 s15, s14, s15
20: eeb00a67 vmov.f32 s0, s15
24: e28bd000 add sp, fp, #0
28: e49db004 pop {fp} ; (ldr fp, [sp], #4)
2c: e12fff1e bx lr
同样生成了硬浮点指令,与softfp的区别在于,这里使用FPU的寄存器s0、s1来传递形参。
2 使用NEON
2.1 选项
-O3 -mfloat-abi=softfp -mfpu=neon -ftree-vectorizeneon可以做浮点运算,有了neon,可以不使用vfp。
为了提升生成的代码性能,应该使用neon intrinsics的方式来写代码。
2.2 示例
普通代码
void NeonTest(int * x, int * y, int * z)
{
int i;
for(i=0;i<200;i++) {
z[i] = x[i] + y[i];
}
}
neon intrinsics格式的代码
#include <arm_neon.h>
void intrinsics(uint32_t *x, uint32_t *y, uint32_t *z)
{
int i;
uint32x4_t x4,y4; // These 128 bit registers will contain 4 values from the x array and 4 values from the y array
uint32x4_t z4; // This 128 bit register will contain the 4 results from the add intrinsic
uint32_t *ptra = x; // pointer to the x array data
uint32_t *ptrb = y; // pointer to the y array data
uint32_t *ptrz = z; // pointer to the z array data
for(i=0; i < 200/4; i++)
{
x4 = vld1q_u32(ptra); // intrinsic to load x4 with 4 values from x
y4 = vld1q_u32(ptrb); // intrinsic to load y4
z4=vaddq_u32(x4,y4); // intrinsic to add z4=x4+y4
vst1q_u32(ptrz, z4); // store the 4 results to z
ptra+=4; // increment pointers
ptrb+=4;
ptrz+=4;
}
}
REF:
1 ARM GCC浮点编译选项
http://blog.youkuaiyun.com/jijiagang/article/details/12952681
2 Floating Point
http://www.arm.com/products/processors/technologies/vector-floating-point.php
3 ARM的发展史以及架构解析
http://www.elecfans.com/emb/arm/20160422415359.html
4 ARM简介
http://www.xuebuyuan.com/1444525.html
5 ARM_architecture
https://en.wikipedia.org/wiki/ARM_architecture
转自:http://blog.youkuaiyun.com/yellow_hill/article/details/52608989