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