Ben Katz / mbed-dev_spine

Dependents:   SPIne CH_Communicatuin_Test CH_Communicatuin_Test2 MCP_SPIne ... more

Fork of mbed-dev-f303 by Ben Katz

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers CThunk.h Source File

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