Changes to support running on smaller memory LPC device LPC1764

Fork of mbed-dev by mbed official

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