Case
Standard floating point operations cannot be executed on BREW enabled devices. BREW helper functions must be substituted for floating-point operations.
To make things worst, BREW does not support the float type, only double, and most mathematical functions are not available either.
Cause
When compiling BREW SoftFP operations, the ARM compiler will convert all floating point operations to ARM compiler functions.
These ARM compiler functions will link to other libraries, some of them using static variables. However, BREW does not allow static variables.
And, since BREW applications do not have main() functions, initialization for the standard library will not be done automatically
Goal
The goal is to use standard floating point operations with BREW.
float a = 1.0; float b = 2.0; float c; int i; c = sin(a) + cos(b); i = c * 100.05;
Solution
The ARM compiler will replace floating point operations by the following ARM compiler functions defined in its attached rt_fp.h header file.
/* * Single-precision arithmetic routines. */ extern __softfp float _fadd(float, float); extern __softfp float _fsub(float, float); extern __softfp float _fmul(float, float); extern __softfp float _fdiv(float, float); ...etc.
To use these ARM compiler functions, _fp_init() needs to be called from inside AEEMod_Load() which boots up the application.
/* * Since BREW has no main function, * fplib must be initialized manually with _fp_init() */ extern void _fp_init(void);
After calling the _fp_init() function, several ARM compiler functions can be linked. But BREW is not capable of using all these functions. Specifically, functions with static variables and SWI instructions can not be used in BREW.
<rt_misc.h> /* * The library's signal handling process must be customized for BREW. * __raise(), which traps error signals, cannot be called in BREW. * So the functions that calls it, __rt_raise() is re-targeted. */ void __rt_raise(int /*sig*/, int /*type*/); <errno.h> extern __pure volatile int *__rt_errno_addr(void); <rt_fp.h> /* * This returns a pointer to the FP status word, when it's stored * in memory. */ extern unsigned *__rt_fp_status_addr(void);
There are two ways to replace these incompatible functions, by using C or by using assembler. ( The C method is recommended )
The address of the handset's variable pool must be returned to the two functions above. The method of implementation will change according to the position of the variable pool.
Re-Targeting the __rt_raise Function with C language
In this method, the variable pool is reserved in the AEEApplet structure, and the function is implemented to return that address.
When that function is called, the GETAPPINSTANCE() helper function is called to aquire the address of the AEEApplet structure.
#if defined __arm #include <rt_misc.h > #include <errno.h > #include <rt_fp.h > #endif #if defined __arm #pragma import(__use_no_semihosting_swi) #endif typedef struct SoftFPApplet { AEEApplet aee; #if defined __arm signed int volatile _errno; unsigned int _fpstatus; #endif } SoftFPApplet; #if defined __arm void __rt_raise(signed int signal, signed int type) { return; } signed int volatile* __rt_errno_addr(void) { SoftFPApplet* ap = (SoftFPApplet*)GETAPPINSTANCE(); return(&ap->_errno); } unsigned int* __rt_fp_status_addr(void) { SoftFPApplet* ap = (SoftFPApplet*)GETAPPINSTANCE(); return(&ap->_fpstatus); } #endif int AEEClsCreateInstance(AEECLSID ClsId, IShell * pIShell,IModule * po,void ** ppObj) { *ppObj = NULL; if (ClsId == AEECLSID_SOFTFP) { if (AEEApplet_New(sizeof(SoftFPApplet), ClsId, pIShell, po, (IApplet**)ppObj, (AEEHANDLER)SoftFP_HandleEvent, NULL) == TRUE) { #if defined __arm _fp_init(); #endif // Add your code here ..... return(AEE_SUCCESS); } } return(EFAILED); }
Re-Targeting the __rt_raise Function By Assembler
In the assembler method, the variable pool uses a particle of the application module itself as the static variable area. The problem with this method is that basic BREW applications are ROPI (Read Only Position Independent). If the application is embedded in the ROM memory, this method will no longer be valid.
This method may not be applicable in some BREW enabled handsets.
AREA ||i.__rt_raise||, CODE, READONLY EXPORT __rt_raise __rt_raise BX lr AREA ||i.__rt_errno_addr||, CODE, READONLY EXPORT __rt_errno_addr __rt_errno_addr LDR r0, table_errno_addr ADD r0, pc, r0 BX lr table_errno_addr DCD errno_addr - {PC} AREA ||i.__rt_fp_status_addr||, CODE, READONLY EXPORT __rt_fp_status_addr __rt_fp_status_addr LDR r0, table_status_addr ADD r0, pc, r0 BX lr table_status_addr DCD status_addr - {PC} AREA ||.constdata||, DATA, READONLY errno_addr DCD 0x00000000 status_addr DCD 0x00000000 END
By implementing these methods,standard floating point operations can be used with BREW.
SophiaFramework comes equipped with standard floating-point operations by default.