The Airsource Blog

Floating Point on BREW

Pretty much any BREW developer knows that you can't use floating point. Or, to be more precise, you can't use floating point without jumping through a few hoops. You essentially have three options

1) Don't use floating point

If you can manage it, this is definitely the best option. ARM processors, almost without exception, have no floating point unit. Any floating point operations need to be done in software, and needless to say, that's SLOW.

2) Use the BREW APIs

A bit of a middleground, this one. If you don't need floating point much, but you do need it, then you can just write everything using the BREW floating point API. This uses constructs like:

      double myResult = FADD(1.0,2.0);

which isn't the most readable code on the planet. It's not portable, you can only uses doubles, not floats, and it's not pretty. But it does work.

3) Use a software floating point library

This is the point where you say 'hey, I thought the compiler came with one of those'. Well, if truth be told, it does. And if you compile up a standard application with something like

      double myResult = 1.0 + 2.0;

then it will compile just fine, right up to the point where you try to link, and you discover that the floating point library shipped with the compiler wasn't compiled with the correct flags for relocatable code. Whoops.

Actually, if you try and compile the code above, and just the code above, it will work fine - because the standard makefile will compile with -O2, which means dead code is optimised straight out. Use the following code in your event loop instead:

      double d = 0.0;
      d += myIntVariable; 
      myIntVariable = (int)d;

This will generate the following errors:

      Error: L6265E: Non-rwpi Section libspace.o(.bss) cannot be
      assigned to PI Exec region 'ER_ZI'.  Error: L6248E:
      libspace.o(.text) in PI region 'ER_RO' cannot have address type
      relocation to __libspace_start in PI region 'ER_ZI'.

As an aside, these error messages aren't terribly helpful. If you go to c:\Apps\ARM\RVCT_BREWv1_2 - or wherever you installed it - and rename Lib to NoLib, then rebuild, you will get much more helpful error messages:

      Error: L6218E: Undefined symbol _dflt (referred from mytest.o)
      Error: L6218E: Undefined symbol _dadd (referred from mytest.o)
      Error: L6218E: Undefined symbol _dfix (referred from mytest.o)

Telling us that we're using floating point operations in mytest.o, which is a lot more helpful than moaning about libspace.o. Don't forget to rename NoLib back to Lib once you've fixed everything...

The obvious solution is to go implement all the relevant symbols that the linker is failing on in a relocatable manner, and then link against those instead of the standard library. This is the approach that Sophia Framework takes. Fortunately, QUALCOMM have released a floating point library (AKA floats.o) that does much the same thing for free (though to be fair, Sophia Framework does a whole lot more besides). Link against this library, and you can do pretty much whatever you want with floating point, without any hacking around with arcanely named macros.

There are, as always, a couple of caveats:

  • It doesn't work with ADS 2.2, because the ABI (Application Binary Interface) changed. Use ADS 2.1 or RVCT
  • It doesn't work with GCC (allegedly, not tried myself)

The inherent danger with this solution is that the freedom to use floats wherever you like means that you are tempted to use them in inappropriate places. Just remember that it's all done in software - and it's SLOW.