在学习正点原子I.MX6ull芯片开发板的时候,有两个裸机实验(串口和spi)涉及到了除法运算以及浮点运算,
先声明,除法运算(定点和浮点,浮点除法是浮点运算的一种)和浮点运算是两个东西:
1.除法分为定点除法和浮点除法,arm中定点除法例如32位无符号整形除法,是没有直接的汇编指令的,需要借助软件库来实现;
2.浮点数的除法可以调用软件库来进行软件模拟,也可以借助硬件进行浮点数运算(协处理器,cp15指令开启硬件浮点运算)。
一、定点数除法指令需要链接gcc库:
使用定点数除法运算的时候编译提示错误 (可以看出来uidiv uldiv,这些函数是针对int 和long 这些定点数进行除法运算的函数):
bsp_uart.c:(.text+0xd4):对‘__aeabi_uidivmod’未定义的引用
bsp_uart.c:(.text+0xe2):对‘__aeabi_uidiv’未定义的引用
bsp_uart.c:(.text+0xec):对‘__aeabi_uidiv’未定义的引用
bsp_uart.c:(.text+0x156):对‘__aeabi_uldivmod’未定义的引用
bsp_uart.c:(.text+0x166):对‘__aeabi_uidiv’未定义的引用
bsp_uart.c:(.text+0x17a):对‘__aeabi_uidiv’未定义的引用
bsp_uart.c:(.text+0x186):对‘__aeabi_uldivmod’未定义的引用
bsp_uart.c:(.text+0x1e2):对‘__aeabi_uidiv’未定义的引用
bsp_uart.c:(.text+0x236):对‘__aeabi_uidiv’未定义的引用
bsp_uart.c:(.text+0x240):对‘__aeabi_uidiv’未定义的引用
原因是ARM,没有定点数的除法指令。libgcc库包含除法指令的代码,于是加上链接库gcc:
-lgcc -L /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/lib/gcc/arm-linux-gnueabihf/4.9.4/
参考:https://blog.csdn.net/xgbing/article/details/7803846
另外定义函数:
void raise(int sig_nr){
}
应对除零异常的情况。
二、gcc编译器默认将浮点数除法指令直接翻译成汇编指令(例如vdiv.f32)供协处理器可以直接运行,裸机例程中需要我们手动设置cp15寄存器,来打开硬件浮点数除法(使用如下函数):
void imx6ul_hardfpu_enable(void)
{
uint32_t cpacr;
uint32_t fpexc;
/* 使能NEON和FPU */
cpacr = __get_CPACR();
cpacr = (cpacr & ~(CPACR_ASEDIS_Msk | CPACR_D32DIS_Msk))
| (3UL << CPACR_cp10_Pos) | (3UL << CPACR_cp11_Pos);
__set_CPACR(cpacr);
fpexc = __get_FPEXC();
fpexc |= 0x40000000UL;
__set_FPEXC(fpexc);
}
(注:我说的gcc默认是指现在的版本,可能更古老的gcc默认通过调用浮点数的软件除法库,来完成浮点数的除法)
另外,gcc编译硬件浮点运算最好给gcc传递如下参数来完成,经测试不指定好像默认也是硬件浮点运算
$(COBJS) : obj/%.o : %.c
$(CC) -Wall -march=armv7-a -mfpu=neon-vfpv4 -mfloat-abi=hard -Wa,-mimplicit-it=thumb -nostdlib -fno-builtin -c -O2 $(INCLUDE) -o $@ $<