Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
CThunk.h
00001 00002 /** \addtogroup platform */ 00003 /** @{*/ 00004 /* General C++ Object Thunking class 00005 * 00006 * - allows direct callbacks to non-static C++ class functions 00007 * - keeps track for the corresponding class instance 00008 * - supports an optional context parameter for the called function 00009 * - ideally suited for class object receiving interrupts (NVIC_SetVector) 00010 * 00011 * Copyright (c) 2014-2015 ARM Limited 00012 * 00013 * Licensed under the Apache License, Version 2.0 (the "License"); 00014 * you may not use this file except in compliance with the License. 00015 * You may obtain a copy of the License at 00016 * 00017 * http://www.apache.org/licenses/LICENSE-2.0 00018 * 00019 * Unless required by applicable law or agreed to in writing, software 00020 * distributed under the License is distributed on an "AS IS" BASIS, 00021 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00022 * See the License for the specific language governing permissions and 00023 * limitations under the License. 00024 */ 00025 00026 /* General C++ Object Thunking class 00027 * 00028 * - allows direct callbacks to non-static C++ class functions 00029 * - keeps track for the corresponding class instance 00030 * - supports an optional context parameter for the called function 00031 * - ideally suited for class object receiving interrupts (NVIC_SetVector) 00032 */ 00033 00034 #ifndef __CTHUNK_H__ 00035 #define __CTHUNK_H__ 00036 00037 #define CTHUNK_ADDRESS 1 00038 #define CTHUNK_VARIABLES volatile uint32_t code[2] 00039 00040 #if (defined(__CORTEX_M3) || defined(__CORTEX_M4) || defined(__CORTEX_M7) || defined(__CORTEX_A9) \ 00041 || defined(__CORTEX_M23) || defined(__CORTEX_M33)) 00042 /** 00043 * CTHUNK disassembly for Cortex-M3/M4/M7/A9 (thumb2): 00044 * * adr r0, #4 00045 * * ldm r0, {r0, r1, r2, pc} 00046 * 00047 * This instruction loads the arguments for the static thunking function to r0-r2, and 00048 * branches to that function by loading its address into PC. 00049 * 00050 * This is safe for both regular calling and interrupt calling, since it only touches scratch registers 00051 * which should be saved by the caller, and are automatically saved as part of the IRQ context switch. 00052 */ 00053 #define CTHUNK_ASSIGMENT do { \ 00054 m_thunk.code[0] = 0xE890A001; \ 00055 m_thunk.code[1] = 0x00008007; \ 00056 } while (0) 00057 00058 #elif (defined(__CORTEX_M0PLUS) || defined(__CORTEX_M0)) 00059 /* 00060 * CTHUNK disassembly for Cortex M0/M0+ (thumb): 00061 * * adr r0, #4 00062 * * ldm r0, {r0, r1, r2, r3} 00063 * * bx r3 00064 */ 00065 #define CTHUNK_ASSIGMENT do { \ 00066 m_thunk.code[0] = 0xC80FA001; \ 00067 m_thunk.code[1] = 0x00004718; \ 00068 } while (0) 00069 00070 #else 00071 #error "Target is not currently suported." 00072 #endif 00073 00074 /* IRQ/Exception compatible thunk entry function */ 00075 typedef void (*CThunkEntry)(void); 00076 /** @}*/ 00077 00078 /** 00079 * Class for created a pointer with data bound to it 00080 * 00081 * @note Synchronization level: Not protected 00082 * @ingroup platform 00083 */ 00084 template<class T> 00085 class CThunk 00086 { 00087 public: 00088 typedef void (T::*CCallbackSimple)(void); 00089 typedef void (T::*CCallback)(void* context); 00090 00091 inline CThunk(T *instance) 00092 { 00093 init(instance, NULL, NULL); 00094 } 00095 00096 inline CThunk(T *instance, CCallback callback) 00097 { 00098 init(instance, callback, NULL); 00099 } 00100 00101 ~CThunk() { 00102 00103 } 00104 00105 inline CThunk(T *instance, CCallbackSimple callback) 00106 { 00107 init(instance, (CCallback)callback, NULL); 00108 } 00109 00110 inline CThunk(T &instance, CCallback callback) 00111 { 00112 init(instance, callback, NULL); 00113 } 00114 00115 inline CThunk(T &instance, CCallbackSimple callback) 00116 { 00117 init(instance, (CCallback)callback, NULL); 00118 } 00119 00120 inline CThunk(T &instance, CCallback callback, void* context) 00121 { 00122 init(instance, callback, context); 00123 } 00124 00125 inline void callback(CCallback callback) 00126 { 00127 m_callback = callback; 00128 } 00129 00130 inline void callback(CCallbackSimple callback) 00131 { 00132 m_callback = (CCallback)callback; 00133 } 00134 00135 inline void context(void* context) 00136 { 00137 m_thunk.context = (uint32_t)context; 00138 } 00139 00140 inline void context(uint32_t context) 00141 { 00142 m_thunk.context = context; 00143 } 00144 00145 inline uint32_t entry(void) 00146 { 00147 return (((uint32_t)&m_thunk)|CTHUNK_ADDRESS); 00148 } 00149 00150 /* get thunk entry point for connecting rhunk to an IRQ table */ 00151 inline operator CThunkEntry(void) 00152 { 00153 return (CThunkEntry)entry(); 00154 } 00155 00156 /* get thunk entry point for connecting rhunk to an IRQ table */ 00157 inline operator uint32_t(void) 00158 { 00159 return entry(); 00160 } 00161 00162 /* simple test function */ 00163 inline void call(void) 00164 { 00165 (((CThunkEntry)(entry()))()); 00166 } 00167 00168 private: 00169 T* m_instance; 00170 volatile CCallback m_callback; 00171 00172 // TODO: this needs proper fix, to refactor toolchain header file and all its use 00173 // PACKED there is not defined properly for IAR 00174 #if defined (__ICCARM__) 00175 typedef __packed struct 00176 { 00177 CTHUNK_VARIABLES; 00178 volatile uint32_t instance; 00179 volatile uint32_t context; 00180 volatile uint32_t callback; 00181 volatile uint32_t trampoline; 00182 } CThunkTrampoline; 00183 #else 00184 typedef struct 00185 { 00186 CTHUNK_VARIABLES; 00187 volatile uint32_t instance; 00188 volatile uint32_t context; 00189 volatile uint32_t callback; 00190 volatile uint32_t trampoline; 00191 } __attribute__((__packed__)) CThunkTrampoline; 00192 #endif 00193 00194 static void trampoline(T* instance, void* context, CCallback* callback) 00195 { 00196 if(instance && *callback) { 00197 (static_cast<T*>(instance)->**callback)(context); 00198 } 00199 } 00200 00201 volatile CThunkTrampoline m_thunk; 00202 00203 inline void init(T *instance, CCallback callback, void* context) 00204 { 00205 /* remember callback - need to add this level of redirection 00206 as pointer size for member functions differs between platforms */ 00207 m_callback = callback; 00208 00209 /* populate thunking trampoline */ 00210 CTHUNK_ASSIGMENT; 00211 m_thunk.context = (uint32_t)context; 00212 m_thunk.instance = (uint32_t)instance; 00213 m_thunk.callback = (uint32_t)&m_callback; 00214 m_thunk.trampoline = (uint32_t)&trampoline; 00215 00216 #if defined(__CORTEX_A9) 00217 /* Data cache clean */ 00218 /* Cache control */ 00219 { 00220 uint32_t start_addr = (uint32_t)&m_thunk & 0xFFFFFFE0; 00221 uint32_t end_addr = (uint32_t)&m_thunk + sizeof(m_thunk); 00222 uint32_t addr; 00223 00224 /* Data cache clean and invalid */ 00225 for (addr = start_addr; addr < end_addr; addr += 0x20) { 00226 __v7_clean_inv_dcache_mva((void *)addr); 00227 } 00228 /* Instruction cache invalid */ 00229 __v7_inv_icache_all(); 00230 __ca9u_inv_tlb_all(); 00231 __v7_inv_btac(); 00232 } 00233 #endif 00234 #if defined(__CORTEX_M7) 00235 /* Data cache clean and invalid */ 00236 SCB_CleanInvalidateDCache(); 00237 00238 /* Instruction cache invalid */ 00239 SCB_InvalidateICache(); 00240 #endif 00241 __ISB(); 00242 __DSB(); 00243 } 00244 }; 00245 00246 #endif/*__CTHUNK_H__*/ 00247
Generated on Tue Jul 12 2022 20:03:15 by
