Should be no changes
Fork of mbed-dev-bin by
Embed:
(wiki syntax)
Show/hide line numbers
CThunk.h
00001 /* General C++ Object Thunking class 00002 * 00003 * - allows direct callbacks to non-static C++ class functions 00004 * - keeps track for the corresponding class instance 00005 * - supports an optional context parameter for the called function 00006 * - ideally suited for class object receiving interrupts (NVIC_SetVector) 00007 * 00008 * Copyright (c) 2014-2015 ARM Limited 00009 * 00010 * Licensed under the Apache License, Version 2.0 (the "License"); 00011 * you may not use this file except in compliance with the License. 00012 * You may obtain a copy of the License at 00013 * 00014 * http://www.apache.org/licenses/LICENSE-2.0 00015 * 00016 * Unless required by applicable law or agreed to in writing, software 00017 * distributed under the License is distributed on an "AS IS" BASIS, 00018 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00019 * See the License for the specific language governing permissions and 00020 * limitations under the License. 00021 */ 00022 #ifndef __CTHUNK_H__ 00023 #define __CTHUNK_H__ 00024 00025 #define CTHUNK_ADDRESS 1 00026 00027 #if defined(__CORTEX_M3) || defined(__CORTEX_M4) || defined(__thumb2__) 00028 #define CTHUNK_VARIABLES volatile uint32_t code[1] 00029 /** 00030 * CTHUNK disassembly for Cortex-M3/M4 (thumb2): 00031 * * ldm.w pc,{r0,r1,r2,pc} 00032 * 00033 * This instruction loads the arguments for the static thunking function to r0-r2, and 00034 * branches to that function by loading its address into PC. 00035 * 00036 * This is safe for both regular calling and interrupt calling, since it only touches scratch registers 00037 * which should be saved by the caller, and are automatically saved as part of the IRQ context switch. 00038 */ 00039 #define CTHUNK_ASSIGMENT m_thunk.code[0] = 0x8007E89F 00040 00041 #elif defined(__CORTEX_M0PLUS) || defined(__CORTEX_M0) 00042 /* 00043 * CTHUNK disassembly for Cortex M0 (thumb): 00044 * * push {r0,r1,r2,r3,r4,lr} save touched registers and return address 00045 * * movs r4,#4 set up address to load arguments from (immediately following this code block) (1) 00046 * * add r4,pc set up address to load arguments from (immediately following this code block) (2) 00047 * * ldm r4!,{r0,r1,r2,r3} load arguments for static thunk function 00048 * * blx r3 call static thunk function 00049 * * pop {r0,r1,r2,r3,r4,pc} restore scratch registers and return from function 00050 */ 00051 #define CTHUNK_VARIABLES volatile uint32_t code[3] 00052 #define CTHUNK_ASSIGMENT do { \ 00053 m_thunk.code[0] = 0x2404B51F; \ 00054 m_thunk.code[1] = 0xCC0F447C; \ 00055 m_thunk.code[2] = 0xBD1F4798; \ 00056 } while (0) 00057 00058 #else 00059 #error "Target is not currently suported." 00060 #endif 00061 00062 /* IRQ/Exception compatible thunk entry function */ 00063 typedef void (*CThunkEntry)(void); 00064 00065 template<class T> 00066 class CThunk 00067 { 00068 public: 00069 typedef void (T::*CCallbackSimple)(void); 00070 typedef void (T::*CCallback)(void* context); 00071 00072 inline CThunk(T *instance) 00073 { 00074 init(instance, NULL, NULL); 00075 } 00076 00077 inline CThunk(T *instance, CCallback callback) 00078 { 00079 init(instance, callback, NULL); 00080 } 00081 00082 ~CThunk() { 00083 00084 } 00085 00086 inline CThunk(T *instance, CCallbackSimple callback) 00087 { 00088 init(instance, (CCallback)callback, NULL); 00089 } 00090 00091 inline CThunk(T &instance, CCallback callback) 00092 { 00093 init(instance, callback, NULL); 00094 } 00095 00096 inline CThunk(T &instance, CCallbackSimple callback) 00097 { 00098 init(instance, (CCallback)callback, NULL); 00099 } 00100 00101 inline CThunk(T &instance, CCallback callback, void* context) 00102 { 00103 init(instance, callback, context); 00104 } 00105 00106 inline void callback(CCallback callback) 00107 { 00108 m_callback = callback; 00109 } 00110 00111 inline void callback(CCallbackSimple callback) 00112 { 00113 m_callback = (CCallback)callback; 00114 } 00115 00116 inline void context(void* context) 00117 { 00118 m_thunk.context = (uint32_t)context; 00119 } 00120 00121 inline void context(uint32_t context) 00122 { 00123 m_thunk.context = context; 00124 } 00125 00126 inline uint32_t entry(void) 00127 { 00128 return (((uint32_t)&m_thunk)|CTHUNK_ADDRESS); 00129 } 00130 00131 /* get thunk entry point for connecting rhunk to an IRQ table */ 00132 inline operator CThunkEntry(void) 00133 { 00134 return (CThunkEntry)entry(); 00135 } 00136 00137 /* get thunk entry point for connecting rhunk to an IRQ table */ 00138 inline operator uint32_t(void) 00139 { 00140 return entry(); 00141 } 00142 00143 /* simple test function */ 00144 inline void call(void) 00145 { 00146 (((CThunkEntry)(entry()))()); 00147 } 00148 00149 private: 00150 T* m_instance; 00151 volatile CCallback m_callback; 00152 00153 // TODO: this needs proper fix, to refactor toolchain header file and all its use 00154 // PACKED there is not defined properly for IAR 00155 #if defined (__ICCARM__) 00156 typedef __packed struct 00157 { 00158 CTHUNK_VARIABLES; 00159 volatile uint32_t instance; 00160 volatile uint32_t context; 00161 volatile uint32_t callback; 00162 volatile uint32_t trampoline; 00163 } CThunkTrampoline; 00164 #else 00165 typedef struct 00166 { 00167 CTHUNK_VARIABLES; 00168 volatile uint32_t instance; 00169 volatile uint32_t context; 00170 volatile uint32_t callback; 00171 volatile uint32_t trampoline; 00172 } __attribute__((__packed__)) CThunkTrampoline; 00173 #endif 00174 00175 static void trampoline(T* instance, void* context, CCallback* callback) 00176 { 00177 if(instance && *callback) { 00178 (static_cast<T*>(instance)->**callback)(context); 00179 } 00180 } 00181 00182 volatile CThunkTrampoline m_thunk; 00183 00184 inline void init(T *instance, CCallback callback, void* context) 00185 { 00186 /* remember callback - need to add this level of redirection 00187 as pointer size for member functions differs between platforms */ 00188 m_callback = callback; 00189 00190 /* populate thunking trampoline */ 00191 CTHUNK_ASSIGMENT; 00192 m_thunk.context = (uint32_t)context; 00193 m_thunk.instance = (uint32_t)instance; 00194 m_thunk.callback = (uint32_t)&m_callback; 00195 m_thunk.trampoline = (uint32_t)&trampoline; 00196 00197 __ISB(); 00198 __DSB(); 00199 } 00200 }; 00201 00202 #endif/*__CTHUNK_H__*/
Generated on Tue Jul 12 2022 19:13:19 by 1.7.2