Documentation  |   Table of Contents   |  < Previous   |  Next >  

1    68K Application Compatibility

Porting Applications to Palm OS® Cobalt

Exploring Palm OS®

The Palm Application Compatibility Environment, or PACE, is a 68K emulator that supports execution of well-behaved 68K-based Palm OS applications on devices that use an ARM processor.

PACE allows the majority of existing 68K-based Palm OS applications to run on devices that use an ARM processor. Users can beam an application from a 68K device to an ARM-based device and run the application. The Palm Application Compatibility Environment helps provide a migration path for developers. The developer can continue to use existing 68K-based tools to build their application.

Design Objectives ^TOP^

The Palm Application Compatibility Environment is designed to allow well-behaved 68K applications to run at 68K speeds or faster on an ARM-based device, with minimum code and memory overhead. A well-behaved application is one that:

  • only uses documented Palm OS APIs
  • does not access hardware directly
  • does not access the display memory directly
  • does not access low memory globals
  • does not access the fields of Palm OS structures directly
  • runs on Palm OS Emulator with a debug Palm OS Garnet ROM without encountering any errors

Performance ^TOP^

Performance of a 68K application varies greatly depending on how much time it spends executing 68K instructions compared to the time it spends calling Palm OS functions.

Code that consists only of 68K instructions, such as a prime number generator, will run slower than an ARM-native version of the same code since the 68K instructions are emulated. For reference, the time it takes to execute emulated 68K instructions on a 70 MHz ARM device is roughly the same as the time it takes to execute the same instructions on a Palm Vx device. Most applications spend a great deal of time inside operating system calls, however, and those calls execute at the full speed of the ARM processor (note that there may be additional overhead for some Palm OS functions, depending on how close the native function's API is to the 68K API). Thus most 68K applications running under PACE will actually run much faster than they would on a device with a 68K processor.

Developer SDK ^TOP^

Because an application that runs under PACE is like any other 68K application, when writing applications to run under PACE you continue to use the tools and headers available for 68K-based Palm OS application development.

Applications are no longer allowed access to many internal, publicly-defined structures (such as the ControlType structure). To make up for this, some accessor functions were added in Palm OS 4.0, and additional accessor functions were added to the Palm OS glue library shipped with the Palm OS Garnet SDK.

The 68K Palm debugger and other tools which depend on the 68K debugger APIs (such as the Metrowerks debugger) are supported by the Palm Application Compatibility Environment.

API Restrictions ^TOP^

Most well-behaved applications run under the Palm OS Garnet version of PACE with no problems. Due to differences in the underlying operating system in Palm OS Cobalt, however, PACE is somewhat more restricting on Palm OS Cobalt devices. The following sections detail those restrictions.

Deprecated APIs ^TOP^

Very few deprecated APIs (such as CategoryEditV20()) are supported for native ARM applications. The Palm Application Compatibility Environment still supports these deprecated APIs, unless they are listed in Table 1.1.

Unsupported APIs ^TOP^

A number of Palm OS APIs are not supported by PACE. These are APIs that either are documented as private, are internal-only APIs (yet appear in public header files), or are APIs that developer support has advised developers to not use. A list of unsupported APIs can be found under "Unsupported Palm OS Functions."

Card Number Argument ^TOP^

The native ARM version of Palm OS no longer has the concept of memory cards. For this reason, the card number concept is faked for emulated 68K applications. If an application calls MemNumCards(), a value of 1 is always returned. If an application calls any function that takes cardNum as an argument and the value for cardNum is not zero, an error is returned to the application.

Record Unique IDs ^TOP^

In previous versions of Palm OS, only 24 bits of a record's unique ID were stored in the record header. In Palm OS Cobalt, however, all 32 bits are unique. The function that returns a record's unique ID returns a 32-bit value; to ensure the greatest degree of compatiblity an application should save all 32 bits of the record's unique ID, and not truncate the result to 24 bits.

Effect of Calling an Unsupported or Deprecated Palm OS Function ^TOP^

If a 68K application calls an unsupported or deprecated Palm OS function, an alert is displayed and the application is terminated. The alert contains the message "An error occurred in the application you are using. Note the error code and contact the developer of this application" followed by an error number in parentheses. When the user presses the OK button, the application is forced to exit. The debug version of this error alert has two more numbers displayed (to help you pinpoint the problem) and a Cancel button. If you tap the Cancel button, PACE tries to connect to the 68K Palm Debugger so you can determine why and where the error is occurring.

Unsupported Palm OS Functions ^TOP^

Table 1.1 is a list of Palm OS functions that are not supported by PACE in Palm OS Cobalt. The following are the reasons why these functions are not supported.

Documented as "System Use Only"
These functions are documented as "System Use Only" in the Palm OS Programmer's API Reference and thus should never have been called by applications.
Should have been documented as "system use only"
These functions were intended for internal PalmSource use only but were documented.
Obsolete
These functions are not implemented because they have long been obsolete. Current Palm OS applications should no longer be using them.
Implemented as a "NOP" function
Typically, these are functions that should not have been called by applications. Because some applications may call them, however, PACE supports them. However, they do nothing and simply return.
Rarely-used function
Functions that are only used internally by Palm OS, by serial drivers, or by OEM extensions. They are not functions that an application would use. PACE does not implement these functions.
Unimplemented in Palm OS Cobalt
Functions that were supported by PACE in Palm OS Garnet but are no longer supported by PACE in Palm OS Cobalt. The vast majority of these are intended for system use only, and the remaining few are very rarely used by applications.

Table 1.1  Unsupported Palm OS functions 

Function

Unsupported because...

AlmAlarmCallback()

Documented as "System Use Only"

AlmCancelAll()

Documented as "System Use Only"

AlmDisplayAlarm()

Documented as "System Use Only"

AlmTimeChange()

Documented as "System Use Only"

ConGetS()

Rarely-used function

ConPutS()

Rarely-used function

DayDrawDays()

Rarely-used function

DayDrawDaySelector()

Rarely-used function

DayHandleEvent()

Should have been documented as "System Use Only"

DbgCommSettings()

Rarely-used function

DbgGetMessage()

Rarely-used function

DlkControl()

Rarely-used function

DlkDispatchRequest()

Rarely-used function

DlkStartServer()

Rarely-used function

DmInit()

Documented as "System Use Only"

EvtDequeueKeyEvent()

Documented as "System Use Only"

EvtEnqueuePenPoint()

Was documented as "System Use Only." In Palm OS Cobalt, returns sysErrNotAllowed. On debug ROMs, displays a fatal alert.

EvtGetPenBtnList()

Rarely-used function

EvtGetSilkscreenAreaList()

Rarely-used function

EvtGetSysEvent()

Documented as "System Use Only"

EvtKeyQueueSize()

In Palm OS Cobalt, returns sysErrNotAllowed. On debug ROMs, displays a fatal alert.

EvtPenQueueSize()

In Palm OS Cobalt, returns sysErrNotAllowed. On debug ROMs, displays a fatal alert.

EvtProcessSoftKeyStroke()

In Palm OS Cobalt, returns sysErrNotAllowed. On debug ROMs, displays a fatal alert.

EvtSetKeyQueuePtr()

Documented as "System Use Only"

EvtSetPenQueuePtr()

Documented as "System Use Only"

EvtSysInit()

Documented as "System Use Only"

ExpCardGetSerialPort()

Unimplemented in Palm OS Cobalt

ExpCardInserted()

Documented as "System Use Only"

ExpCardRemoved()

Documented as "System Use Only"

ExpSlotDriverInstall()

Unimplemented in Palm OS Cobalt

ExpSlotDriverRemove()

Unimplemented in Palm OS Cobalt

ExpSlotLibFind()

Unimplemented in Palm OS Cobalt

ExpSlotRegister()

Documented as "System Use Only"

ExpSlotUnregister()

Documented as "System Use Only"

FplAdd()

Obsolete

FplAToF()

Obsolete

FplBase10Info()

Obsolete

FplDiv()

Obsolete

FplFloatToLong()

Obsolete

FplFloatToULong()

Obsolete

FplFree()

Implemented as a "NOP" function

FplFToA()

Obsolete

FplInit()

Implemented as a "NOP" function

FplLongToFloat()

Obsolete

FplMul()

Obsolete

FplSub()

Obsolete

FrmAddSpaceForObject()

Documented as "System Use Only"

FtrInit()

Documented as "System Use Only"

GrfFree()

Documented as "System Use Only"

GrfInit()

Documented as "System Use Only"

InsPtCheckBlink()

Documented as "System Use Only"

InsPtEnable()

Implemented as a "NOP" function

InsPtEnabled()

Implemented as a "NOP" function

InsPtGetHeight()

Implemented as a "NOP" function

InsPtGetLocation()

Implemented as a "NOP" function

InsPtInitialize()

Documented as "System Use Only"

InsPtSetHeight()

Implemented as a "NOP" function

InsPtSetLocation()

Implemented as a "NOP" function

KbdDraw()

Documented as "System Use Only"

KbdErase()

Documented as "System Use Only"

KbdGetLayout()

Documented as "System Use Only"

KbdGetPosition()

Documented as "System Use Only"

KbdGetShiftState()

Documented as "System Use Only"

KbdHandleEvent()

Documented as "System Use Only"

KbdSetLayout()

Documented as "System Use Only"

KbdSetPosition()

Documented as "System Use Only"

KbdSetShiftState()

Documented as "System Use Only"

KeyboardStatusFree()

Documented as "System Use Only"

KeyboardStatusNew()

Documented as "System Use Only"

MemCardFormat()

Documented as "System Use Only"

MemHandleFlags()

Documented as "System Use Only"

MemHandleOwner()

Documented as "System Use Only"

MemHandleResetLock()

Documented as "System Use Only"

MemHeapFreeByOwnerID()

Documented as "System Use Only"

MemHeapInit()

Documented as "System Use Only"

MemInit()

Documented as "System Use Only"

MemInitHeapTable()

Documented as "System Use Only"

MemKernelInit()

Documented as "System Use Only"

MemPtrFlags()

Documented as "System Use Only"

MemPtrOwner()

Documented as "System Use Only"

MemPtrResetLock()

Documented as "System Use Only"

MemSemaphoreRelease()

Documented as "System Use Only"

MemSemaphoreReserve()

Documented as "System Use Only"

MemStoreSetInfo()

Documented as "System Use Only"

OmGetIndexedLocale()

Unimplemented in Palm OS Cobalt

OmGetNextSystemLocale()

Unimplemented in Palm OS Cobalt

OmSetSystemLocale()

Unimplemented in Palm OS Cobalt

PenCalibrate()

Implemented as a "NOP" function

PenClose()

Documented as "System Use Only"

PenGetRawPen()

Documented as "System Use Only"

PenOpen()

Documented as "System Use Only"

PenRawToScreen()

Was documented as "System Use Only." In Palm OS Cobalt, returns sysErrNotAllowed. On debug ROMs, displays a fatal alert.

PenResetCalibration()

Implemented as a "NOP" function

PenScreenToRaw()

Was documented as "System Use Only." In Palm OS Cobalt, returns sysErrNotAllowed. On debug ROMs, displays a fatal alert.

PenSleep()

Was documented as "System Use Only." In Palm OS Cobalt this is implemented as a "NOP" function.

PenWake()

Was documented as "System Use Only." In Palm OS Cobalt this is implemented as a "NOP" function.

ResLoadForm()

Rarely-used function

SerReceiveISP()

Implemented as a "NOP" function

SlkProcessRPC()

Documented as "System Use Only"

SlkSetSocketListener()

Rarely-used function

SlkSysPktDefaultResponse()

Documented as "System Use Only"

SndInit()

Documented as "System Use Only"

SndInterruptSmfIrregardless()

Rarely-used function

SndPlaySmfIrregardless()

Rarely-used function

SndPlaySmfResourceIrregardless()

Rarely-used function

SrmOpenBackground()

Rarely-used function

SrmSleep()

Implemented as a "NOP" function

SrmWake()

Implemented as a "NOP" function

SysBatteryDialog()

Documented as "System Use Only"

SysColdBoot()

Documented as "System Use Only"

SysDisableInts()

Was documented as "System Use Only." In Palm OS Cobalt this is implemented as a "NOP" function.

SysDoze()

Documented as "System Use Only"

SysFatalAlertInit()

Undocumented "system use only"function.

SysInit()

Documented as "System Use Only"

SysLaunchConsole()

Documented as "System Use Only"

SysNewOwnerID()

Documented as "System Use Only"

SysNotifyBroadcastFromInterrupt()

Rarely-used function

SysRestoreStatus()

Was documented as "System Use Only." In Palm OS Cobalt this is implemented as a "NOP" function.

SysSemaphoreSet()

Documented as "System Use Only"

SysSetTrapAddress()

Rarely-used function

SysUILaunch()

Documented as "System Use Only"

SysUnimplemented()

Documented as "System Use Only"

TimInit()

Documented as "System Use Only"

VFSInstallFSLib()

Unimplemented in Palm OS Cobalt

VFSRemoveFSLib()

Unimplemented in Palm OS Cobalt

WinAddWindow()

Documented as "System Use Only"

WinDisableWindow()

Was documented as "System Use Only." In Palm OS Cobalt this is implemented as a "NOP" function.

WinEnableWindow()

Was documented as "System Use Only." In Palm OS Cobalt this is implemented as a "NOP" function.

WinGetFirstWindow()

Rarely-used function

WinInitializeWindow()

Was documented as "System Use Only." In Palm OS Cobalt this is implemented as a "NOP" function.

WinMoveWindowAddr()

Documented as "System Use Only"

WinRemoveWindow()

Documented as "System Use Only"

WinScreenInit()

Documented as "System Use Only"

Accessing the PIM Application Databases ^TOP^

Some 68K applications access the PIM application databases. In Palm OS Cobalt the PIM applications are ARM-native applications, and those applications now use Schema databases to hold application data. Although the "classic" PIM application databases are no longer present, PACE does what it can to "do the right thing" when it detects that a 68K application is attempting to access a PIM application database.


NOTE: The PIM database access solution described here depends entirely on the presence of the ARM-native PIM applications. As well, those applications must correctly support the sysAppLaunchCmdImportRecord, sysAppLaunchCmdExportRecord and sysAppLaunchCmdDeleteRecord launch commands. PACE further assumes that the database names, database schema names, and field IDs haven't changed (additional fields may be present, however, and the field order can be changed).

When an application tries to access a 68K PIM application database—either to open or to find it—PACE creates the 68K database, opens it, initializes its application info block (using category names from the corresponding native PIM app) and creates a cache of all records in the corresponding ARM-native PIM application database. Each cache entry contains the following information:

  • the unique ID of the native record
  • handle to the 68K record
  • index of the 68K record
  • category that the record belongs to
  • attribute flags (dirty and deleted)

Each entry is initialized with the unique ID and category information. All other fields are cleared.

When the application then tries to read a record (for example, by calling DmQueryRecord() or DmGetRecord()), PACE sends a sysAppLaunchCmdExportRecord request to the native application. In response, the native application returns the record in vcard format. PACE converts the vcard information into a 68K PIM application record and stores that record into the 68K PIM application database that was created when the database was opened. The index and record handle of this record are stored in the cache; any further requests for the record will return the record handle from the cache.

If the application creates a new record, PACE creates a record in the 68K PIM application database, adds an entry to the cache, and initializes the cache entry's unique ID to NULL.

When the application writes to the new record, PACE marks the record in the cache as "dirty" so that it will be written back to the ARM-native PIM application database when the database is flushed. At that time, PACE converts the 68K record to its vcard representation and then sends a sysAppLaunchCmdImportRecord request to the native application. Records are flushed:

  • when a database is closed
  • whenever another record is created
  • before a unique ID is returned to an application (in response to a call to DmGetRecordInfo()).

When an application deletes a PIM database record, PACE marks the record in the cache as "deleted" and sends a sysAppLaunchCmdDeleteRecord request to the native application.

Once the 68K application closes the PIM application database, PACE flushes any dirty records that have yet to be written, frees up memory allocated for the cache, and closes and deletes the 68K PIM application database.

The two functions DmFindDatabase() and DmGetNextDatabaseByTypeCreator() have the side effect of leaving the 68K PIM application database around. To clean up these stray databases, PACE deletes any existing 68K PIM application databases whenever a 68K application exits. Note that if you call DmOpenDatabase() after locating a database with either of these two functions, and later call DmCloseDatabase(), the database will be deleted when the close function is called.

Although DmFindDatabase() leaves the 68K PIM application database around, other Data Manager calls may cause PACE to delete it. Because of this, if you are going to open a PIM application database by calling DmFindDatabase() followed by DmOpenDatabase() (as opposed to the more common method of using DmOpenDatabaseByTypeCreator()), avoid making other Data Manager calls on the PIM application database between the call to DmFindDatabase() and DmOpenDatabase().

Limitations ^TOP^

The PIM application database access solution provided by PACE has a number of limitations. For one, not all database access functions are supported. Here is a list of the known limitations:

  • It can be slow. The ARM-native PIM applications are sub-launched for each PIM database read, write, or delete.
  • Category changes are not reflected back to the native PIM application. Category information should be treated as read-only.
  • All three "varieties" of record delete—DmDeleteRecord(), DmRemoveRecord() and DmArchiveRecord()—become requests for the native PIM application to delete the record.
  • Some things in the application info blocks are "hard-coded." For example, the ToDo sort order is always priority/due date and the Address Book labels are hard-coded to English text labels.
  • The totalBytes and dataBytes sizes returned from DmDatabaseSize() come from the 68K database and thus are usually wrong. They would only be correct if every record has been read in from the ARM-native PIM application database.
  • Some database record access functions are not supported, including DmRemoveSecretRecords(), DmMoveCategory() and DmDeleteCategory().
  • There are some limitations with private records. Private records will be masked or hidden when a 68K PIM application is run, but changing the "maskedness" or "hiddenness" has no effect while running the 68K PIM application.
  • Because records are not immediately written to the ARM-native PIM application databases, some data may be lost while running a 68K PIM application replacement if the system is reset while the application is running.

Summary of PIM Database Access APIs ^TOP^

Table 1.2 lists those functions for which PACE checks to see if a PIM application database is being accessed. If so, PACE acts as described in the second column.

Table 1.2  Functions that PACE monitors for PIM database access 

Function

How treated by PACE 

CategoryCreateList()

Calls through to the native OS.

CategoryEdit()

Calls through to the native OS.

CategoryFind()

Calls through to the native OS.

CategoryFreeList()

Calls through to the native OS.

CategoryGetName()

Calls through to the native OS.

CategoryGetNext()

Calls through to the native OS.

CategorySelect()

Calls through to the native OS.

CategorySetName()

Calls through to the native OS.

DmArchiveRecord()

PACE handles calls to this function.

DmAttachRecord()

PACE handles calls to this function.

DmCloseDatabase()

PACE handles calls to this function.

DmDatabaseInfo()

Calls through to the native OS.

DmDatabaseProtect()

Calls through to the native OS. Note that applications are not expected to call this function with a PIM database.

DmDatabaseSize()

PACE handles calls to this function.

DmDeleteCategory()

Not supported when accessing a PIM database. sysErrNotAllowed is returned.

DmDeleteDatabase()

Calls through to the native OS. Note that applications are not expected to call this function with a PIM database.

DmDeleteRecord()

PACE handles calls to this function.

DmDetachRecord()

PACE handles calls to this function.

DmFindDatabase()

PACE handles calls to this function.

DmFindRecordByID()

PACE handles calls to this function.

DmFindRecordByOffsetInCategory()

PACE handles calls to this function.

DmFindSortPosition()

PACE handles calls to this function.

DmGetAppInfoID()

Calls through to the native OS.

DmGetDatabaseLockState()

Calls through to the native OS. Note that applications rarely call this function with a PIM database.

DmGetNextDatabaseByTypeCreator()

PACE handles calls to this function.

DmGetPositionInCategory()

PACE handles calls to this function.

DmGetRecord()

PACE handles calls to this function.

DmInsertionSort()

PACE handles calls to this function.

DmMoveCategory()

Not supported when accessing a PIM database. sysErrNotAllowed is returned.

DmMoveRecord()

PACE handles calls to this function.

DmNewHandle()

PACE handles calls to this function.

DmNewRecord()

PACE handles calls to this function.

DmNextOpenDatabase()

Calls through to the native OS. Note that applications rarely call this function with a PIM database.

DmNumRecords()

PACE handles calls to this function.

DmNumRecordsInCategory()

PACE handles calls to this function.

DmOpenDatabase()

PACE handles calls to this function.

DmOpenDatabaseByTypeCreator()

PACE handles calls to this function.

DmOpenDatabaseInfo()

Calls through to the native OS.

DmOpenDBNoOverlay()

PACE handles calls to this function.

DmQueryNextInCategory()

PACE handles calls to this function.

DmQueryRecord()

PACE handles calls to this function.

DmQuickSort()

PACE handles calls to this function.

DmRecordInfo()

PACE handles calls to this function.

DmReleaseRecord()

PACE handles calls to this function.

DmRemoveRecord()

PACE handles calls to this function.

DmRemoveSecretRecords()

Not supported when accessing a PIM database. sysErrNotAllowed is returned.

DmResetRecordStates()

Calls through to the native OS. Note that applications rarely call this function with a PIM database.

DmResizeRecord()

PACE handles calls to this function.

DmSetDatabaseInfo()

Calls through to the native OS.

DmSetRecordInfo()

PACE handles calls to this function.