joey shelton / LED_Demo

Dependencies:   MAX44000 PWM_Tone_Library nexpaq_mdk

Fork of LED_Demo by Maxim nexpaq

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 
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__*/