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 #ifndef __CTHUNK_H__ 00023 #define __CTHUNK_H__ 00024 00025 #define CTHUNK_ADDRESS 1 00026 00027 #if (defined(__CORTEX_M3) || defined(__CORTEX_M4) || defined(__thumb2__)) && ! defined(__CORTEX_A9) 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) || defined(__CORTEX_A9) 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 #if defined(__CORTEX_A9) 00198 /* Data cache clean */ 00199 /* Cache control */ 00200 { 00201 uint32_t start_addr = (uint32_t)&m_thunk & 0xFFFFFFE0; 00202 uint32_t end_addr = (uint32_t)&m_thunk + sizeof(m_thunk); 00203 uint32_t addr; 00204 00205 /* Data cache clean and invalid */ 00206 for (addr = start_addr; addr < end_addr; addr += 0x20) { 00207 __v7_clean_inv_dcache_mva((void *)addr); 00208 } 00209 /* Instruction cache invalid */ 00210 __v7_inv_icache_all(); 00211 __ca9u_inv_tlb_all(); 00212 __v7_inv_btac(); 00213 } 00214 #endif 00215 __ISB(); 00216 __DSB(); 00217 } 00218 }; 00219 00220 #endif/*__CTHUNK_H__*/
Generated on Tue Jul 12 2022 18:56:14 by
