工作的时候用mips的芯片,由于没接触过,所以写代码的过程中出了很多问题,其中就有一个关于mips处理浮点运算的问题。 有一个模块用了浮点运算,编译过了,放芯片上运行,ecos的内核报异常:Co-processor unusable exception.协处理器无法使用。通过google,大致猜测是因为浮点运算用到某个协处理器来完成,这个协处理器不存在。后来发现如下文章:
原文地址:http://blog.sina.com.cn/s/blog_67b113a10100zxx3.html
===========================================
在嵌入式领域,为了节省成本和减少功耗,很多芯片都是没有浮点运算模块的,一般该模块做FPU(float process unit)。这种情况下,linux内核有一个模块叫math-emu的软件模块,就是用整数运算模拟浮点数运算,一般位于arch/mips/目录下。 那么在应用空间的程序是怎么跑到该内核空间的模块呢。简单说就是,用工具链编译含有浮点运算的文件时,编译器并不知道目标板上没有FPU,所以遇到浮点运 算的时候还是将其编译成浮点运算指令。但是,编译生成的执行文件最终在执行到浮点运算指令的时候就有问题了。因为芯片没有FPU,所以浮点指令对于芯片来 说是属于不认识或者叫不支持的指令,那么他就会产生一个异常。内核在初始化的时候为这个异常设置了异常处理函数,当内核捕捉到这个异常后进入异常处理函数 执行。而这个异常处理函数就是内核浮点模拟运算模块的入口。内核将运算的结果再通过寄存器返回给系统空间,这样在应用空间来看的话就好像普通运算一样,没有什么区别。
但是,事实上并非如此。应用空间使用内核实现的浮点运算模块进行浮点运算,效率不是很高。这主要是基于两个方面,一个是因为需要反复的产生异常从而进行应 用空间和内核空间的切换。另一个是因为,内核的浮点模拟模块效率并不高,因为异常处理时并不知道产生异常的指令到底是加减乘除指令,还是浮点比较等指令。 所以,他需要先用switch确定一下该指令到底需要什么运算然后再进行模拟,最后返回运算结果。
另外一种浮点运算的解决方案就是使用软浮点库。方法就是在编译的时候使用编译选项-msoft-float,然后在链接的时候加上软浮点库。软浮点库的源文件在网上应该找的到。这样加上该编译选项后,编译器在编译浮点运算时,并不将浮点运算翻译成浮点运算指令而是,将其在编译阶段就转化成整形数,然后调用相应的软浮点运算库中浮点运算指令模拟函数,这样一条浮点运算指令在同软浮点运算库链接完成后就成了一堆整形数运算。这样的可执行文件能够充分的利用芯片 的流水线,而且避免了应用空间和系统空间的切换,并且运算指令的类别判定放在了编译阶段,提高了运行阶段的效率。通常情况下,用软浮点和用内核浮点模拟模块相比,运算效率快一个数量级,相当的可观!
需要注意的几个问题:
内核浮点和软浮点不能混用。什么意思呢?比如一个工程中A库里面有函数的参数是浮点类型的,B库调用A库的这个函数,那么不能B库编译的时候带 -msoft-float,而编译A库的时候却不带(直接使用内核浮点)。或者是A库带 -msoft-float,而B库不带。通常网上很多文章说使用软浮点时,一定要使用支持软浮点的工具链,我想应该是因为使用软浮点时,工具链中很多系统 库必须是 -msoft-float选项下编译出来的,典型的就是数学库libm.a ,不然调用到该库中的函数时就可能计算错误。所以存在调用关系时,必须调用者和被调者在是否带-msoft-float选项上保持一致。
阅读(7168) | 评论(0) | 转发(0) |