|
API Guide Home (Online version only) |
![]() |
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 |