API Guide Home (Online version only) |

# FarCall.h

Go to the documentation of this file.

    00001 /******************************************************************************
    00002  *   Copyright :
    00003  *    This is free software; you can redistribute it and/or modify
    00004  *    it as you like.
    00005  *
    00006  *    This program is distributed in the hope that it will be useful,
    00007  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
    00008  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00009  ***************************************************************************/
    00010
    00011 /**
    00012  * file     FarCall.h
    00013  * @version 1.0
    00014  * @date    06/06/2000
    00015  *
    00016  * Macros for declaring a function that will be located more than
    00017  * 32K away from its caller.  This is trickier than it sounds, since
    00018  * the branch instructions in the 68K don't support greater than 16-bit
    00019  * jumps.
    00020  *
    00021  *  History:
    00022  *  22-feb-2000  dia  Initial version
    00023  *   08-mar-2000  dia  Fixed off-by-two error (don't know why it worked
    00024  *                     before).
    00025  *   06-Apr-2000  BP   Added support for gcc 2.95 and new callseq attribute
    00026  *   11-Apr-2000  BP   Added FAR_PTR for function pointers
    00027  *   06-jun-2000  dia  Fixed FAR_PTR--it wasn't loading right.
    00028
    00029  * <hr>
    00030  */
    00031
    00032 #ifndef __FAR_CALL_H__
    00033 #define __FAR_CALL_H__
    00034
    00035         // The following macro can be used to declare a function as a
    00036         // FAR_CALL to another, normal function.
    00037         //
    00038         // Sample usage:
    00039         //     Err AddrGetDatabase (DmOpenRef *addrPP, UInt16 mode);
    00040         //     Err FarAddrGetDatabase (DmOpenRef *addrPP, UInt16 mode)
    00041         //       FAR_CALL (AddrGetDatabase);
    00042         //
    00043         // Preferred usage (saves typing and enforces naming):
    00044         //     typedef Err AddrGetDatabaseFnType (DmOpenRef *addrPP,
    00045         //                                        UInt16 mode);
    00046         //     FAR_DECLARE (AddrGetDatabase);
    00047         //
    00048         //
    00049         // The way the code works is as follows:
    00050         // 1. LEA     (funcName - .).L, A0
    00051         //    Load the distance from the current PC to the function
    00052         //    into A0.  This works because LEA allows you to specify a
    00053         //    full 32-bit address.
    00054         //    ...note that in order to force this to work as absolute
    00055         //    and not as PC-relative, we can't use a standard LEA, so
    00056         //    we need to hand-assemble the correct LEA and then use a
    00057         //    DC.L to get the address.  Also note that the DC.Led
    00058         //    address is 2 further than it would be if we just had
    00059         //    an instruction (since the "." is the next instruction).
    00060         // 2. JSR     -6(PC, A0.L)    ; aka -4(PC, A0.L) if your
    00061         //                            ; assembler thinks differently.
    00062         //    Do the actual jump. Note that the -6 is needed because
    00063         //    the "." in instruction #1 is 6 bytes before the current
    00064         //    PC in this instruction (remember, the PC to start the
    00065         //    jump at is 2 bytes past the current instruction's start).
    00066         //
    00067         // This can also be looked at in assembly as:
    00068         // 1. DC.W 0x41F9; DC.L (funcName - .)
    00069         // 2. DC.W 0x4EBB; DC.W 0x88FA
    00070
    00071     #if (defined __GNUC__) && (EMULATION_LEVEL == EMULATION_NONE)
    00072       #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
    00073
    00074         #define FAR_CALL(funcName)                        \
    00075             __attribute__ (( __callseq__ (                \
    00076                     "DC.W 0x41F9; "                       \
    00077                     "DC.L " #funcName " - .; "            \
    00078                     "JSR -6(%%PC, %%A0.L)") ))
    00079
    00080       #else         // GNUC < 2.95
    00081
    00082         #define FAR_CALL(funcName)                                       \
    00083             __attribute__ (( inline (0x41F9, "DC.L " #funcName " - .",   \
    00084                                      "JSR    -6(%%PC, %%A0.L)"     ) ))
    00085
    00086       #endif        // GNUC < 2.95
    00087
    00088       #define FAR_DECLARE(funcName)                               \
    00089           funcName##FnType funcName;                              \
    00090           funcName##FnType Far##funcName FAR_CALL (funcName)
    00091
    00092       // FAR_PTR:
    00093       //   This macro can be used to reference a function
    00094       //   pointer greater than 32k away from the current code.
    00095       //   The assembly code is functionally similar to FAR_CALL.
    00096       //
    00097       // Sample Usage:
    00098       //       void* far_start;
    00099       //       FAR_PTR (&far_start, start);
    00100       //
    00101       //   where start() is a function within the current scope.
    00102       //
    00103       #define FAR_PTR(outPtr, funcPtr)               \
    00104                   asm ("DC.W 0x41F9;"                \
    00105                        "DC.L " #funcPtr " - .;"      \
    00106                        "LEA -6(%%PC, %%A0.L), %0"    \
    00107                          : "=a" (*(outPtr))          \
    00108                          :                           \
    00109                          : "a0" );
    00110
    00111     #else       // not GCC
    00112
    00113         // UNTESTED:
    00114
    00115         // In Metrowerks, just make it so that the macro evaluates to nothing
    00116         // this will simply declare the far function but not do anything...
    00117         #define FAR_CALL(funcName)
    00118
    00119         // UNTESTED:
    00120
    00121         // Declare the function, and make the far version just a #define...
    00122         #define FAR_DECLARE(funcName)                               \
    00123             funcName##FnType funcName;                              \
    00124             static funcName##FnType * const Far##funcName = funcName                       \
    00125             // blank line to absorb ";"
    00126
    00127         #define FAR_PTR(outPtr, funcPtr) \
    00128             do { *(outPtr) = (funcPtr); } while (0)
    00129
    00130     #endif      // not GCC
    00131
    00132 #endif  // __FAR_CALL_H__

Top | Palm Developer Network © 2004-2008, Palm, Inc. All rights reserved. Generated on Fri Jun 13 10:06:52 2008 for Palm API Guide