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