SHIO

Fork of mbed-stm32l0/l1-src by lzbp li

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers CThunk.h Source File

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__)
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)
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             __ISB();
00198             __DSB();
00199         }
00200 };
00201 
00202 #endif/*__CTHUNK_H__*/