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