ARM 浮點(diǎn)運(yùn)算詳解
早期的ARM沒有協(xié)處理器,所以浮點(diǎn)運(yùn)算是由CPU來模擬的,即所需浮點(diǎn)運(yùn)算均在浮點(diǎn)運(yùn)算模擬器(float math emulation)上進(jìn)行,需要的浮點(diǎn)運(yùn)算,常要耗費(fèi)數(shù)千個(gè)循環(huán)才能執(zhí)行完畢,因此特別緩慢。
本文引用地址:http://m.butianyuan.cn/article/201611/318754.htm直到今天,在ARM Kernel配置時(shí),都有如下選項(xiàng):
Floating point emulation --->
[ ] NWFPE math emulation
[ ] FastFPE math emulation (EXPERIMENTAL)
在這里,可以配置ARM 浮點(diǎn)模擬器。
浮點(diǎn)模擬器 模擬浮點(diǎn)是利用了undefined instrction handler,在運(yùn)算過程中遇到浮點(diǎn)計(jì)算是產(chǎn)生異常中斷,這么做帶來的后果是帶來極頻繁的exception,大大增加中斷延遲,降低系統(tǒng)實(shí)時(shí)性。
二:軟浮點(diǎn)技術(shù):
軟浮點(diǎn)支持是由交叉工具鏈提供的功能,與Linux內(nèi)核無(wú)關(guān)。當(dāng)使用軟浮點(diǎn)工具鏈編譯浮點(diǎn)操作時(shí),編譯器會(huì)用內(nèi)聯(lián)的浮點(diǎn)庫(kù)替換掉浮點(diǎn)操作,使得生成的機(jī)器碼完全不含浮點(diǎn)指令,但是又能夠完成正確的浮點(diǎn)操作。
三:浮點(diǎn)協(xié)處理器:
在較新版本的ARM中,可以添加協(xié)處理器。 一些ARM CPU為了更好的處理浮點(diǎn)計(jì)算的需要,添加了浮點(diǎn)協(xié)處理器。
并定義了浮點(diǎn)指令集。 如果不存在實(shí)際的硬件,則這些指令被截獲并由浮點(diǎn)模擬器模塊(FPEmulator)來執(zhí)行。
四: 硬件浮點(diǎn)協(xié)處理器以及對(duì)應(yīng)指令集的使用:
想要使用硬件浮點(diǎn)協(xié)處理器來幫助運(yùn)算Application中的浮點(diǎn)運(yùn)算。需要以下幾個(gè)前提條件:
1. Kernel中設(shè)置支持硬件協(xié)處理器。
2. 編譯器支持將浮點(diǎn)運(yùn)算翻譯成硬件浮點(diǎn)運(yùn)算指令,或者在需要浮點(diǎn)運(yùn)算的時(shí)候手動(dòng)調(diào)用相應(yīng)的浮點(diǎn)運(yùn)算指令。
1. Kernle的支持:
如果Kernel不支持浮點(diǎn)協(xié)處理器,則因?yàn)閰f(xié)處理器寄存器等使用權(quán)限等問題,協(xié)處理器對(duì)應(yīng)指令無(wú)法運(yùn)行。
網(wǎng)絡(luò)上有位高手指出:
CP15 c1 協(xié)處理器訪問控制寄存器,這個(gè)寄存器規(guī)定了用戶模式和特權(quán)對(duì)協(xié)處理器的訪問權(quán)限。我們要使用VFP當(dāng)然要運(yùn)行用戶模式訪問CP10和CP11。
另外一個(gè)寄存器是VFP的FPEXC Bit30這是VFP功能的使用位。
其實(shí)操作系統(tǒng)在做了這兩件事情之后,用戶程序就可以使用VFP了。當(dāng)然,Kernel 除了這2件事外,還處理了其他一些事情。
Floating point emulation --->
[*]VFP-format floating point maths
Include VFP support code in the kernel. This is needed IF your hardware includes a VFP unit.
2. 編譯器指定浮點(diǎn)指令:
編譯器可以顯式指定將浮點(diǎn)運(yùn)算翻譯成何種浮點(diǎn)指令。
如果編譯器支持軟浮點(diǎn),則其可能會(huì)將浮點(diǎn)運(yùn)算翻譯成編譯器中自帶的浮點(diǎn)庫(kù)。則不會(huì)有真正的浮點(diǎn)運(yùn)算。
否則,可以翻譯成FPA(FloatingPointAccelerator)指令。 FPA指令再去查看是否有浮點(diǎn)模擬器。
還可以將浮點(diǎn)運(yùn)算指定為VFP(vectorfloating point)指令或者neon向量浮點(diǎn)指令。
五. 編譯器指定編譯硬浮點(diǎn)指令:
測(cè)試浮點(diǎn)加減乘除等運(yùn)算的時(shí)間長(zhǎng)度:
float src_mem_32[1024] = {1.024};
float dst_mem_32[1024] = {0.933};
for(j = 0; j < 1024; j++)
{
for(i = 0; i < 1024; i++)
{
src_32 = src_mem_32[i] + dst_mem_32[i];
}
}
通過printf 計(jì)算前后毫秒數(shù)的差值來看計(jì)算能力。
編譯:
arm-hisiv200-linux-gcc -c -Wall fcpu.c -o fcpu.o
arm-hisiv200-linux-gcc fcpu.o -o FCPU -L./
運(yùn)行,則得到32位浮點(diǎn)數(shù)加1024次所需要時(shí)間。
如果要使用VFP呢?
arm-hisiv200-linux-gcc -c -Wall -mfpu=vfp -mfloat-abi=softfp fcpu.c -o fcpu.o
arm-hisiv200-linux-gcc -Wall -mfpu=vfp -mfloat-abi=softfp fcpu.o -o FCPU -L./
則運(yùn)行后發(fā)現(xiàn),所需要時(shí)間幾乎減小了一半。 說明還是非常有效果的。
關(guān)于-mfpu -mfloat-abi講解:見附錄2。
另外,如何才能在直觀的檢查出是否使用VFP呢?
可以通過察看編譯出的ASM程序得到結(jié)論。
#arm-hisiv200-linux-objdump -d fcpu.o
00000000
0: e52db004 push {fp} ; (str fp, [sp, #-4]!)
4: e28db000 add fp, sp, #0
8: e24dd00c sub sp, sp, #12
c: e3a03000 mov r3, #0
10: e50b300c str r3, [fp, #-12]
14: e3a03000 mov r3, #0
18: e50b3008 str r3, [fp, #-8]
1c: e3a03000 mov r3, #0
20: e50b3008 str r3, [fp, #-8]
24: ea000017 b 88
28: e3a03000 mov r3, #0
2c: e50b300c str r3, [fp, #-12]
30: ea00000d b 6c
34: e51b200c ldr r2, [fp, #-12]
38: e59f3064 ldr r3, [pc, #100] ; a4
3c: e0831102 add r1, r3, r2, lsl #2
40: ed917a00vldr s14, [r1]
44: e51b200c ldr r2, [fp, #-12]
48: e59f3058 ldr r3, [pc, #88] ; a8
4c: e0831102 add r1, r3, r2, lsl #2
50: edd17a00vldr s15, [r1]
54: ee777a27vadd.f32 s15, s14, s15
58: e59f304c ldr r3, [pc, #76] ; ac
5c: edc37a00vstr s15, [r3]
60: e51b300c ldr r3, [fp, #-12]
64: e2833001 add r3, r3, #1
68: e50b300c str r3, [fp, #-12]
6c: e51b200c ldr r2, [fp, #-12]
70: e59f3038 ldr r3, [pc, #56] ; b0
74: e1520003 cmp r2, r3
78: daffffed ble 34
7c: e51b3008 ldr r3, [fp, #-8]
80: e2833001 add r3, r3, #1
84: e50b3008 str r3, [fp, #-8]
88: e51b2008 ldr r2, [fp, #-8]
8c: e59f301c ldr r3, [pc, #28] ; b0
90: e1520003 cmp r2, r3
94: daffffe3 ble 28
98: e28bd000 add sp, fp, #0
9c: e49db004 pop {fp} ; (ldr fp, [sp], #4)
a0: e12fff1e bx lr
這里明顯包含vfp指令。 所以是使用vfp指令的:
arm-hisiv200-linux-gcc -c -Wall -mfpu=vfp -mfloat-abi=softfp fcpu.c -o fcpu.o
注意:VFP 指令指令在附錄1中。
如果使用:
arm-hisiv200-linux-gcc -c -Wall fcpu.c -o fcpu.o
#arm-hisiv200-linux-objdump -d fcpu.o
00000000
0: e92d4800 push {fp, lr}
4: e28db004 add fp, sp, #4
8: e24dd008 sub sp, sp, #8
c: e3a03000 mov r3, #0
10: e50b300c str r3, [fp, #-12]
14: e3a03000 mov r3, #0
18: e50b3008 str r3, [fp, #-8]
1c: e3a03000 mov r3, #0
20: e50b3008 str r3, [fp, #-8]
24: ea000019 b 90
28: e3a03000 mov r3, #0
2c: e50b300c str r3, [fp, #-12]
30: ea00000f b 74
34: e51b200c ldr r2, [fp, #-12]
38: e59f3068 ldr r3, [pc, #104] ; a8
3c: e7932102 ldr r2, [r3, r2, lsl #2]
40: e51b100c ldr r1, [fp, #-12]
44: e59f3060 ldr r3, [pc, #96] ; ac
48: e7933101 ldr r3, [r3, r1, lsl #2]
4c: e1a00002 mov r0, r2
50: e1a01003 mov r1, r3
54: ebfffffebl 0 <__aeabi_fadd>
58: e1a03000 mov r3, r0
5c: e1a02003 mov r2, r3
60: e59f3048 ldr r3, [pc, #72] ; b0
64: e5832000 str r2, [r3]
68: e51b300c ldr r3, [fp, #-12]
6c: e2833001 add r3, r3, #1
70: e50b300c str r3, [fp, #-12]
74: e51b200c ldr r2, [fp, #-12]
78: e59f3034 ldr r3, [pc, #52] ; b4
7c: e1520003 cmp r2, r3
80: daffffeb ble 34
84: e51b3008 ldr r3, [fp, #-8]
88: e2833001 add r3, r3, #1
8c: e50b3008 str r3, [fp, #-8]
90: e51b2008 ldr r2, [fp, #-8]
94: e59f3018 ldr r3, [pc, #24] ; b4
98: e1520003 cmp r2, r3
9c: daffffe1 ble 28
a0: e24bd004 sub sp, fp, #4
a4: e8bd8800 pop {fp, pc}
則不包含VFP指令。
且去調(diào)用 __aeabi_fadd
附錄1 :VFP 指令
可以查看arm的realView文檔。
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0204ic/Bcffbdga.html
附錄2:
-mfpu=name
-mfpe=number
-mfp=number
This specifies what floating point hardware (or hardware emulation) is available on the target. Permissible names are: fpa, fpe2, fpe3, maverick, vfp. -mfp and -mfpe are synonyms for -mfpu=fpenumber, for compatibility with older versions of GCC.
-mfloat-abi=name
Specifies which ABI to use for floating point values. Permissible values are: soft, softfp and hard.
soft and hard are equivalent to -msoft-float and -mhard-float respectively. softfp allows the generation of floating point instructions, but still uses the soft-float calling conventions.
評(píng)論