软件工程

本类阅读TOP10

·PHP4 + MYSQL + APACHE 在 WIN 系统下的安装、配置
·Linux 入门常用命令(1)
·Linux 入门常用命令(2)
·使用 DCPROMO/FORCEREMOVAL 命令强制将 Active Directory 域控制器降级
·DirectShow学习(八): CBaseRender类及相应Pin类的源代码分析
·基于ICE方式SIP信令穿透Symmetric NAT技术研究
·Windows 2003网络负载均衡的实现
·一网打尽Win十四种系统故障解决方法
·数百种 Windows 软件的免费替代品列表
·收藏---行百里半九十

分类导航
VC语言Delphi
VB语言ASP
PerlJava
Script数据库
其他语言游戏开发
文件格式网站制作
软件工程.NET开发
GCC programming tricks for the PalmPilot

作者:未知 来源:月光软件站 加入时间:2005-2-28 月光软件站

All code snippets presented here are public domain, feel free to use them in your own Pilot programs!

Having more than 32k code

Interfacing to IEEE floating point system traps

Printing and scanning IEEE floating point

Having more than 32k code

It has often been said, that this is not possible, but this is wrong. In fact, there're two ways to overcome the 32k limit. The first one is using shared libraries, which has some problems (e.g. accessing global data) and the second one is described here.

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
Now the trick is to put start() in the middle of your objects and provide an entry function myStart() at adress 0, which simply calls start().

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
That's the theory, to make this work you have to do the following:
  1. Increase the coderes size in the file pilot.ld. Here's mine:
    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 );
    }
    
  2. Compile the following file (start.c):
    extern unsigned long start();
    unsigned long myStart()
    {
      return start();
    }
    
  3. Link with a command like this:
    $(CC) $(LDFLAGS) -nostartfiles start.o some objects $(CRT0) more objects $(LIBS) -oyourprog

    The option -nostartfiles tells the linker not to automatically use crt0.o as the first object.

Interfacing to IEEE floating point system traps

GCC doesn't handle NewFloatMgr.h correctly (in version 0.5.0). On the other hand, using arithmetic operators like + in a C program use the emulated operations from the C runtime library, not the Pilot system traps, which creates bloated PRC files.

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!

Printing and scanning IEEE floating point

Though you could use SysTrapFlpFToA or SysTrapFlpAToF, I don't recommend so, as the ROM routines
  • provide only 9 digits of accuracy
  • can't handle exponents >99
  • don't provide error checking
Unfortunately, not even the otherwise excellent MathLib supports floating point IO, so I had to write my own for LispMe.

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!


相关文章

相关软件