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 /** 00042 * CTHUNK disassembly for Cortex-M3/M4/M7/A9 (thumb2): 00043 * * adr r0, #4 00044 * * ldm r0, {r0, r1, r2, pc} 00045 * 00046 * This instruction loads the arguments for the static thunking function to r0-r2, and 00047 * branches to that function by loading its address into PC. 00048 * 00049 * This is safe for both regular calling and interrupt calling, since it only touches scratch registers 00050 * which should be saved by the caller, and are automatically saved as part of the IRQ context switch. 00051 */ 00052 #define CTHUNK_ASSIGMENT do { \ 00053 m_thunk.code[0] = 0xE890A001; \ 00054 m_thunk.code[1] = 0x00008007; \ 00055 } while (0) 00056 00057 #elif (defined(__CORTEX_M0PLUS) || defined(__CORTEX_M0)) 00058 /* 00059 * CTHUNK disassembly for Cortex M0/M0+ (thumb): 00060 * * adr r0, #4 00061 * * ldm r0, {r0, r1, r2, r3} 00062 * * bx r3 00063 */ 00064 #define CTHUNK_ASSIGMENT do { \ 00065 m_thunk.code[0] = 0xC80FA001; \ 00066 m_thunk.code[1] = 0x00004718; \ 00067 } while (0) 00068 00069 #else 00070 #error "Target is not currently suported." 00071 #endif 00072 00073 /* IRQ/Exception compatible thunk entry function */ 00074 typedef void (*CThunkEntry)(void); 00075 00076 /** 00077 * Class for created a pointer with data bound to it 00078 * 00079 * @Note Synchronization level: Not protected 00080 */ 00081 template<class T> 00082 class CThunk 00083 { 00084 public: 00085 typedef void (T::*CCallbackSimple)(void); 00086 typedef void (T::*CCallback)(void* context); 00087 00088 inline CThunk(T *instance) 00089 { 00090 init(instance, NULL, NULL); 00091 } 00092 00093 inline CThunk(T *instance, CCallback callback) 00094 { 00095 init(instance, callback, NULL); 00096 } 00097 00098 ~CThunk() { 00099 00100 } 00101 00102 inline CThunk(T *instance, CCallbackSimple callback) 00103 { 00104 init(instance, (CCallback)callback, NULL); 00105 } 00106 00107 inline CThunk(T &instance, CCallback callback) 00108 { 00109 init(instance, callback, NULL); 00110 } 00111 00112 inline CThunk(T &instance, CCallbackSimple callback) 00113 { 00114 init(instance, (CCallback)callback, NULL); 00115 } 00116 00117 inline CThunk(T &instance, CCallback callback, void* context) 00118 { 00119 init(instance, callback, context); 00120 } 00121 00122 inline void callback(CCallback callback) 00123 { 00124 m_callback = callback; 00125 } 00126 00127 inline void callback(CCallbackSimple callback) 00128 { 00129 m_callback = (CCallback)callback; 00130 } 00131 00132 inline void context(void* context) 00133 { 00134 m_thunk.context = (uint32_t)context; 00135 } 00136 00137 inline void context(uint32_t context) 00138 { 00139 m_thunk.context = context; 00140 } 00141 00142 inline uint32_t entry(void) 00143 { 00144 return (((uint32_t)&m_thunk)|CTHUNK_ADDRESS); 00145 } 00146 00147 /* get thunk entry point for connecting rhunk to an IRQ table */ 00148 inline operator CThunkEntry(void) 00149 { 00150 return (CThunkEntry)entry(); 00151 } 00152 00153 /* get thunk entry point for connecting rhunk to an IRQ table */ 00154 inline operator uint32_t(void) 00155 { 00156 return entry(); 00157 } 00158 00159 /* simple test function */ 00160 inline void call(void) 00161 { 00162 (((CThunkEntry)(entry()))()); 00163 } 00164 00165 private: 00166 T* m_instance; 00167 volatile CCallback m_callback; 00168 00169 // TODO: this needs proper fix, to refactor toolchain header file and all its use 00170 // PACKED there is not defined properly for IAR 00171 #if defined (__ICCARM__) 00172 typedef __packed struct 00173 { 00174 CTHUNK_VARIABLES; 00175 volatile uint32_t instance; 00176 volatile uint32_t context; 00177 volatile uint32_t callback; 00178 volatile uint32_t trampoline; 00179 } CThunkTrampoline; 00180 #else 00181 typedef struct 00182 { 00183 CTHUNK_VARIABLES; 00184 volatile uint32_t instance; 00185 volatile uint32_t context; 00186 volatile uint32_t callback; 00187 volatile uint32_t trampoline; 00188 } __attribute__((__packed__)) CThunkTrampoline; 00189 #endif 00190 00191 static void trampoline(T* instance, void* context, CCallback* callback) 00192 { 00193 if(instance && *callback) { 00194 (static_cast<T*>(instance)->**callback)(context); 00195 } 00196 } 00197 00198 volatile CThunkTrampoline m_thunk; 00199 00200 inline void init(T *instance, CCallback callback, void* context) 00201 { 00202 /* remember callback - need to add this level of redirection 00203 as pointer size for member functions differs between platforms */ 00204 m_callback = callback; 00205 00206 /* populate thunking trampoline */ 00207 CTHUNK_ASSIGMENT; 00208 m_thunk.context = (uint32_t)context; 00209 m_thunk.instance = (uint32_t)instance; 00210 m_thunk.callback = (uint32_t)&m_callback; 00211 m_thunk.trampoline = (uint32_t)&trampoline; 00212 00213 #if defined(__CORTEX_A9) 00214 /* Data cache clean */ 00215 /* Cache control */ 00216 { 00217 uint32_t start_addr = (uint32_t)&m_thunk & 0xFFFFFFE0; 00218 uint32_t end_addr = (uint32_t)&m_thunk + sizeof(m_thunk); 00219 uint32_t addr; 00220 00221 /* Data cache clean and invalid */ 00222 for (addr = start_addr; addr < end_addr; addr += 0x20) { 00223 __v7_clean_inv_dcache_mva((void *)addr); 00224 } 00225 /* Instruction cache invalid */ 00226 __v7_inv_icache_all(); 00227 __ca9u_inv_tlb_all(); 00228 __v7_inv_btac(); 00229 } 00230 #endif 00231 #if defined(__CORTEX_M7) 00232 /* Data cache clean and invalid */ 00233 SCB_CleanInvalidateDCache(); 00234 00235 /* Instruction cache invalid */ 00236 SCB_InvalidateICache(); 00237 #endif 00238 __ISB(); 00239 __DSB(); 00240 } 00241 }; 00242 00243 #endif/*__CTHUNK_H__*/ 00244 00245 /** @}*/
Generated on Tue Jul 12 2022 18:10:40 by
