Interfacing to IEEE floating point system traps
Printing and scanning IEEE floating point
Your PilotMain() is not the first function called when your app starts. The (normal) entry point is a function start(), which is buried in the object module crt0.o. (This module is automatically put at the beginning of the code section by the linker) start() relocates the data segment and calls some "hooks" (I don't know, what these hooks exactly do, but it seems that you need them).
The PalmOS starts an app by simply jumping to adress 0, where the start() function is put by the linker.
Now here comes the problem: start() is at the very beginning of the code segment, then your code follows and the hooks are at the very end, so to call the hooks from start(), they must be within 32k (the range of the relative branch instructions of the 68000), so normally your code mustbe <32k.
/ | start() |
<32k | your code |
\ | hooks |
When start() is within 32k of myStart() and the hooks are within 32k of start(), you have TWO 32k ranges to put your code. Of course you must ensure (by shuffling your functions and objects) that calls between your functions don't exceed the 32k branch limit.
/ | myStart() |
<32k | your code |
\ / | start() |
<32k | more of your code |
\ | hooks |
MEMORY { coderes : ORIGIN = 0x10000, LENGTH = 65535 datares : ORIGIN = 0x0, LENGTH = 32767 } SECTIONS { .text : { *(.text) . = ALIGN(4); bhook_start = .; *(bhook) bhook_end = .; . = ALIGN(4); ehook_start = .; *(ehook) ehook_end = .; } > coderes .data : { data_start = .; *(.data) } > datares .bss : { bss_start = .; *(.bss) *(COMMON) } > datares end = ALIGN( 4 ); edata = ALIGN( 4 ); }
extern unsigned long start(); unsigned long myStart() { return start(); }
The option -nostartfiles tells the linker not to automatically use crt0.o as the first object.
The following code snippet shows how to access the system traps with GCC.
#define _DONT_USE_FP_TRAPS_ 1 #include <Common.h> #include <System/SysAll.h> #include <SysTraps.h> #include <System/NewFloatMgr.h> void SysTrapFlpLToF(FlpDouble*, Long) SYS_TRAP(sysTrapFlpEmDispatch); /* convert a long to double */ double longToDouble(long l) { FlpCompDouble fcd; asm("moveq.l %0,%%d2" : : "i" (sysFloatEm_d_itod) : "d2"); SysTrapFlpLToF(&fcd.fd, l); return fcd.d; } Long SysTrapFlpFToL(FlpDouble) SYS_TRAP(sysTrapFlpEmDispatch); /* convert a double to long */ long doubleToLong(double d) { FlpCompDouble fcd; fcd.d = d; asm("moveq.l %0,%%d2" : : "i" (sysFloatEm_d_dtoi) : "d2"); return SysTrapFlpFToL(fcd.fd); } void SysTrapBinOp(FlpDouble*, FlpDouble, FlpDouble) SYS_TRAP(sysTrapFlpEmDispatch); /* the same interface is used for all basic arithmetic operations */ double genericDoubleOp(double a, double b, long opcode) { FlpCompDouble fcda, fcdb, fcds; fcda.d = a; fcdb.d = b; asm("move.l %0,%%d2" : : "g" (opcode) : "d2"); SysTrapBinOp(&fcds.fd, fcda.fd, fcdb.fd); return fcds.d; } /* basic arithmetic operations */ #define addDouble(a,b) genericDoubleOp(a,b,sysFloatEm_d_add) #define subDouble(a,b) genericDoubleOp(a,b,sysFloatEm_d_sub) #define mulDouble(a,b) genericDoubleOp(a,b,sysFloatEm_d_mul) #define divDouble(a,b) genericDoubleOp(a,b,sysFloatEm_d_div) SDWord SysTrapCompare(FlpDouble, FlpDouble) SYS_TRAP(sysTrapFlpEmDispatch); /* compare 2 doubles for equality */ Boolean eqDouble(double a, double b) { FlpCompDouble fcda, fcdb; fcda.d = a; fcdb.d = b; asm("moveq.l %0,%%d2" : : "i" (sysFloatEm_d_feq) : "d2"); return SysTrapCompare(fcda.fd, fcdb.fd); } /* compare 2 doubles for less or equal */ Boolean leqDouble(double a, double b) { FlpCompDouble fcda, fcdb; fcda.d = a; fcdb.d = b; asm("moveq.l %0,%%d2" : : "i" (sysFloatEm_d_fle) : "d2"); return SysTrapCompare(fcda.fd, fcdb.fd); }You should get the idea how to extend this for other operations. By the way, you can use floating point constants in your code, they are correctly converted into their IEEE bit pattern by GCC!
Here's my printing function for doubles:
/**********************************************************************/ /* Formatting parameters */ /**********************************************************************/ #define NUM_DIGITS 15 #define MIN_FLOAT 4 #define ROUND_FACTOR 1.0000000000000005 /* NUM_DIGITS zeros */ /**********************************************************************/ /* FP conversion constants */ /**********************************************************************/ static double pow1[] = { 1e256, 1e128, 1e064, 1e032, 1e016, 1e008, 1e004, 1e002, 1e001 }; static double pow2[] = { 1e-256, 1e-128, 1e-064, 1e-032, 1e-016, 1e-008, 1e-004, 1e-002, 1e-001 }; void printDouble(double x, Char* s) { FlpCompDouble fcd; short e,e1,i; double *pd, *pd1; char sign = '\0'; short dec = 0; /*------------------------------------------------------------------*/ /* Round to desired precision */ /* (this doesn't always provide a correct last digit!) */ /*------------------------------------------------------------------*/ x = mulDouble(x, ROUND_FACTOR); /*------------------------------------------------------------------*/ /* check for NAN, +INF, -INF, 0 */ /*------------------------------------------------------------------*/ fcd.d = x; if ((fcd.ul[0] & 0x7ff00000) == 0x7ff00000) if (fcd.fdb.manH == 0 && fcd.fdb.manL == 0) if (fcd.fdb.sign) StrCopy(s, "[-inf]"); else StrCopy(s, "[inf]"); else StrCopy(s, "[nan]"); else if (FlpIsZero(fcd)) StrCopy(s, "0"); else { /*----------------------------------------------------------------*/ /* Make positive and store sign */ /*----------------------------------------------------------------*/ if (FlpGetSign(fcd)) { *s++ = '-'; FlpSetPositive(fcd); } if ((unsigned)fcd.fdb.exp < 0x3ff) /* meaning x < 1.0 */ { /*--------------------------------------------------------------*/ /* Build negative exponent */ /*--------------------------------------------------------------*/ for (e=1,e1=256,pd=pow1,pd1=pow2; e1; e1>>=1, ++pd, ++pd1) if (!leqDouble(*pd1, fcd.d)) { e += e1; fcd.d = mulDouble(fcd.d, *pd); } fcd.d = mulDouble(fcd.d, 10.0); /*--------------------------------------------------------------*/ /* Only print big exponents */ /*--------------------------------------------------------------*/ if (e <= MIN_FLOAT) { *s++ = '0'; *s++ = '.'; dec = -1; while (--e) *s++ = '0'; } else sign = '-'; } else { /*--------------------------------------------------------------*/ /* Build positive exponent */ /*--------------------------------------------------------------*/ for (e=0,e1=256,pd=pow1,pd1=pow2; e1; e1>>=1, ++pd, ++pd1) if (leqDouble(*pd, fcd.d)) { e += e1; fcd.d = mulDouble(fcd.d, *pd1); } if (e < NUM_DIGITS) dec = e; else sign = '+'; } /*----------------------------------------------------------------*/ /* Extract decimal digits of mantissa */ /*----------------------------------------------------------------*/ for (i=0;i<NUM_DIGITS;++i,--dec) { Long d = doubleToLong(fcd.d); *s++ = d + '0'; if (!dec) *s++ = '.'; fcd.d = subDouble(fcd.d, longToDouble(d)); fcd.d = mulDouble(fcd.d, 10.0); } /*----------------------------------------------------------------*/ /* Remove trailing zeros and decimal point */ /*----------------------------------------------------------------*/ while (s[-1] == '0') *--s = '\0'; if (s[-1] == '.') *--s = '\0'; /*----------------------------------------------------------------*/ /* Append exponent */ /*----------------------------------------------------------------*/ if (sign) { *s++ = 'e'; *s++ = sign; StrIToA(s, e); } else *s = '\0'; } }The scanning function is too deeply interwoven with the rest of LispMe's scanner, I'll extract it when I've got more time!