Preliminary main mbed library for nexpaq development

Committer:
nexpaq
Date:
Fri Nov 04 20:54:50 2016 +0000
Revision:
1:d96dbedaebdb
Parent:
0:6c56fb4bc5f0
Removed extra directories for other platforms

Who changed what in which revision?

UserRevisionLine numberNew contents of line
nexpaq 0:6c56fb4bc5f0 1 /* General C++ Object Thunking class
nexpaq 0:6c56fb4bc5f0 2 *
nexpaq 0:6c56fb4bc5f0 3 * - allows direct callbacks to non-static C++ class functions
nexpaq 0:6c56fb4bc5f0 4 * - keeps track for the corresponding class instance
nexpaq 0:6c56fb4bc5f0 5 * - supports an optional context parameter for the called function
nexpaq 0:6c56fb4bc5f0 6 * - ideally suited for class object receiving interrupts (NVIC_SetVector)
nexpaq 0:6c56fb4bc5f0 7 *
nexpaq 0:6c56fb4bc5f0 8 * Copyright (c) 2014-2015 ARM Limited
nexpaq 0:6c56fb4bc5f0 9 *
nexpaq 0:6c56fb4bc5f0 10 * Licensed under the Apache License, Version 2.0 (the "License");
nexpaq 0:6c56fb4bc5f0 11 * you may not use this file except in compliance with the License.
nexpaq 0:6c56fb4bc5f0 12 * You may obtain a copy of the License at
nexpaq 0:6c56fb4bc5f0 13 *
nexpaq 0:6c56fb4bc5f0 14 * http://www.apache.org/licenses/LICENSE-2.0
nexpaq 0:6c56fb4bc5f0 15 *
nexpaq 0:6c56fb4bc5f0 16 * Unless required by applicable law or agreed to in writing, software
nexpaq 0:6c56fb4bc5f0 17 * distributed under the License is distributed on an "AS IS" BASIS,
nexpaq 0:6c56fb4bc5f0 18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
nexpaq 0:6c56fb4bc5f0 19 * See the License for the specific language governing permissions and
nexpaq 0:6c56fb4bc5f0 20 * limitations under the License.
nexpaq 0:6c56fb4bc5f0 21 */
nexpaq 0:6c56fb4bc5f0 22
nexpaq 0:6c56fb4bc5f0 23 /* General C++ Object Thunking class
nexpaq 0:6c56fb4bc5f0 24 *
nexpaq 0:6c56fb4bc5f0 25 * - allows direct callbacks to non-static C++ class functions
nexpaq 0:6c56fb4bc5f0 26 * - keeps track for the corresponding class instance
nexpaq 0:6c56fb4bc5f0 27 * - supports an optional context parameter for the called function
nexpaq 0:6c56fb4bc5f0 28 * - ideally suited for class object receiving interrupts (NVIC_SetVector)
nexpaq 0:6c56fb4bc5f0 29 */
nexpaq 0:6c56fb4bc5f0 30
nexpaq 0:6c56fb4bc5f0 31 #ifndef __CTHUNK_H__
nexpaq 0:6c56fb4bc5f0 32 #define __CTHUNK_H__
nexpaq 0:6c56fb4bc5f0 33
nexpaq 0:6c56fb4bc5f0 34 #define CTHUNK_ADDRESS 1
nexpaq 0:6c56fb4bc5f0 35
nexpaq 0:6c56fb4bc5f0 36 #if (defined(__CORTEX_M3) || defined(__CORTEX_M4) || defined(__thumb2__)) && ! defined(__CORTEX_A9)
nexpaq 0:6c56fb4bc5f0 37 #define CTHUNK_VARIABLES volatile uint32_t code[1]
nexpaq 0:6c56fb4bc5f0 38 /**
nexpaq 0:6c56fb4bc5f0 39 * CTHUNK disassembly for Cortex-M3/M4 (thumb2):
nexpaq 0:6c56fb4bc5f0 40 * * ldm.w pc,{r0,r1,r2,pc}
nexpaq 0:6c56fb4bc5f0 41 *
nexpaq 0:6c56fb4bc5f0 42 * This instruction loads the arguments for the static thunking function to r0-r2, and
nexpaq 0:6c56fb4bc5f0 43 * branches to that function by loading its address into PC.
nexpaq 0:6c56fb4bc5f0 44 *
nexpaq 0:6c56fb4bc5f0 45 * This is safe for both regular calling and interrupt calling, since it only touches scratch registers
nexpaq 0:6c56fb4bc5f0 46 * which should be saved by the caller, and are automatically saved as part of the IRQ context switch.
nexpaq 0:6c56fb4bc5f0 47 */
nexpaq 0:6c56fb4bc5f0 48 #define CTHUNK_ASSIGMENT m_thunk.code[0] = 0x8007E89F
nexpaq 0:6c56fb4bc5f0 49
nexpaq 0:6c56fb4bc5f0 50 #elif defined(__CORTEX_M0PLUS) || defined(__CORTEX_M0) || defined(__CORTEX_A9)
nexpaq 0:6c56fb4bc5f0 51 /*
nexpaq 0:6c56fb4bc5f0 52 * CTHUNK disassembly for Cortex M0 (thumb):
nexpaq 0:6c56fb4bc5f0 53 * * push {r0,r1,r2,r3,r4,lr} save touched registers and return address
nexpaq 0:6c56fb4bc5f0 54 * * movs r4,#4 set up address to load arguments from (immediately following this code block) (1)
nexpaq 0:6c56fb4bc5f0 55 * * add r4,pc set up address to load arguments from (immediately following this code block) (2)
nexpaq 0:6c56fb4bc5f0 56 * * ldm r4!,{r0,r1,r2,r3} load arguments for static thunk function
nexpaq 0:6c56fb4bc5f0 57 * * blx r3 call static thunk function
nexpaq 0:6c56fb4bc5f0 58 * * pop {r0,r1,r2,r3,r4,pc} restore scratch registers and return from function
nexpaq 0:6c56fb4bc5f0 59 */
nexpaq 0:6c56fb4bc5f0 60 #define CTHUNK_VARIABLES volatile uint32_t code[3]
nexpaq 0:6c56fb4bc5f0 61 #define CTHUNK_ASSIGMENT do { \
nexpaq 0:6c56fb4bc5f0 62 m_thunk.code[0] = 0x2404B51F; \
nexpaq 0:6c56fb4bc5f0 63 m_thunk.code[1] = 0xCC0F447C; \
nexpaq 0:6c56fb4bc5f0 64 m_thunk.code[2] = 0xBD1F4798; \
nexpaq 0:6c56fb4bc5f0 65 } while (0)
nexpaq 0:6c56fb4bc5f0 66
nexpaq 0:6c56fb4bc5f0 67 #else
nexpaq 0:6c56fb4bc5f0 68 #error "Target is not currently suported."
nexpaq 0:6c56fb4bc5f0 69 #endif
nexpaq 0:6c56fb4bc5f0 70
nexpaq 0:6c56fb4bc5f0 71 /* IRQ/Exception compatible thunk entry function */
nexpaq 0:6c56fb4bc5f0 72 typedef void (*CThunkEntry)(void);
nexpaq 0:6c56fb4bc5f0 73
nexpaq 0:6c56fb4bc5f0 74 /**
nexpaq 0:6c56fb4bc5f0 75 * Class for created a pointer with data bound to it
nexpaq 0:6c56fb4bc5f0 76 *
nexpaq 0:6c56fb4bc5f0 77 * @Note Synchronization level: Not protected
nexpaq 0:6c56fb4bc5f0 78 */
nexpaq 0:6c56fb4bc5f0 79 template<class T>
nexpaq 0:6c56fb4bc5f0 80 class CThunk
nexpaq 0:6c56fb4bc5f0 81 {
nexpaq 0:6c56fb4bc5f0 82 public:
nexpaq 0:6c56fb4bc5f0 83 typedef void (T::*CCallbackSimple)(void);
nexpaq 0:6c56fb4bc5f0 84 typedef void (T::*CCallback)(void* context);
nexpaq 0:6c56fb4bc5f0 85
nexpaq 0:6c56fb4bc5f0 86 inline CThunk(T *instance)
nexpaq 0:6c56fb4bc5f0 87 {
nexpaq 0:6c56fb4bc5f0 88 init(instance, NULL, NULL);
nexpaq 0:6c56fb4bc5f0 89 }
nexpaq 0:6c56fb4bc5f0 90
nexpaq 0:6c56fb4bc5f0 91 inline CThunk(T *instance, CCallback callback)
nexpaq 0:6c56fb4bc5f0 92 {
nexpaq 0:6c56fb4bc5f0 93 init(instance, callback, NULL);
nexpaq 0:6c56fb4bc5f0 94 }
nexpaq 0:6c56fb4bc5f0 95
nexpaq 0:6c56fb4bc5f0 96 ~CThunk() {
nexpaq 0:6c56fb4bc5f0 97
nexpaq 0:6c56fb4bc5f0 98 }
nexpaq 0:6c56fb4bc5f0 99
nexpaq 0:6c56fb4bc5f0 100 inline CThunk(T *instance, CCallbackSimple callback)
nexpaq 0:6c56fb4bc5f0 101 {
nexpaq 0:6c56fb4bc5f0 102 init(instance, (CCallback)callback, NULL);
nexpaq 0:6c56fb4bc5f0 103 }
nexpaq 0:6c56fb4bc5f0 104
nexpaq 0:6c56fb4bc5f0 105 inline CThunk(T &instance, CCallback callback)
nexpaq 0:6c56fb4bc5f0 106 {
nexpaq 0:6c56fb4bc5f0 107 init(instance, callback, NULL);
nexpaq 0:6c56fb4bc5f0 108 }
nexpaq 0:6c56fb4bc5f0 109
nexpaq 0:6c56fb4bc5f0 110 inline CThunk(T &instance, CCallbackSimple callback)
nexpaq 0:6c56fb4bc5f0 111 {
nexpaq 0:6c56fb4bc5f0 112 init(instance, (CCallback)callback, NULL);
nexpaq 0:6c56fb4bc5f0 113 }
nexpaq 0:6c56fb4bc5f0 114
nexpaq 0:6c56fb4bc5f0 115 inline CThunk(T &instance, CCallback callback, void* context)
nexpaq 0:6c56fb4bc5f0 116 {
nexpaq 0:6c56fb4bc5f0 117 init(instance, callback, context);
nexpaq 0:6c56fb4bc5f0 118 }
nexpaq 0:6c56fb4bc5f0 119
nexpaq 0:6c56fb4bc5f0 120 inline void callback(CCallback callback)
nexpaq 0:6c56fb4bc5f0 121 {
nexpaq 0:6c56fb4bc5f0 122 m_callback = callback;
nexpaq 0:6c56fb4bc5f0 123 }
nexpaq 0:6c56fb4bc5f0 124
nexpaq 0:6c56fb4bc5f0 125 inline void callback(CCallbackSimple callback)
nexpaq 0:6c56fb4bc5f0 126 {
nexpaq 0:6c56fb4bc5f0 127 m_callback = (CCallback)callback;
nexpaq 0:6c56fb4bc5f0 128 }
nexpaq 0:6c56fb4bc5f0 129
nexpaq 0:6c56fb4bc5f0 130 inline void context(void* context)
nexpaq 0:6c56fb4bc5f0 131 {
nexpaq 0:6c56fb4bc5f0 132 m_thunk.context = (uint32_t)context;
nexpaq 0:6c56fb4bc5f0 133 }
nexpaq 0:6c56fb4bc5f0 134
nexpaq 0:6c56fb4bc5f0 135 inline void context(uint32_t context)
nexpaq 0:6c56fb4bc5f0 136 {
nexpaq 0:6c56fb4bc5f0 137 m_thunk.context = context;
nexpaq 0:6c56fb4bc5f0 138 }
nexpaq 0:6c56fb4bc5f0 139
nexpaq 0:6c56fb4bc5f0 140 inline uint32_t entry(void)
nexpaq 0:6c56fb4bc5f0 141 {
nexpaq 0:6c56fb4bc5f0 142 return (((uint32_t)&m_thunk)|CTHUNK_ADDRESS);
nexpaq 0:6c56fb4bc5f0 143 }
nexpaq 0:6c56fb4bc5f0 144
nexpaq 0:6c56fb4bc5f0 145 /* get thunk entry point for connecting rhunk to an IRQ table */
nexpaq 0:6c56fb4bc5f0 146 inline operator CThunkEntry(void)
nexpaq 0:6c56fb4bc5f0 147 {
nexpaq 0:6c56fb4bc5f0 148 return (CThunkEntry)entry();
nexpaq 0:6c56fb4bc5f0 149 }
nexpaq 0:6c56fb4bc5f0 150
nexpaq 0:6c56fb4bc5f0 151 /* get thunk entry point for connecting rhunk to an IRQ table */
nexpaq 0:6c56fb4bc5f0 152 inline operator uint32_t(void)
nexpaq 0:6c56fb4bc5f0 153 {
nexpaq 0:6c56fb4bc5f0 154 return entry();
nexpaq 0:6c56fb4bc5f0 155 }
nexpaq 0:6c56fb4bc5f0 156
nexpaq 0:6c56fb4bc5f0 157 /* simple test function */
nexpaq 0:6c56fb4bc5f0 158 inline void call(void)
nexpaq 0:6c56fb4bc5f0 159 {
nexpaq 0:6c56fb4bc5f0 160 (((CThunkEntry)(entry()))());
nexpaq 0:6c56fb4bc5f0 161 }
nexpaq 0:6c56fb4bc5f0 162
nexpaq 0:6c56fb4bc5f0 163 private:
nexpaq 0:6c56fb4bc5f0 164 T* m_instance;
nexpaq 0:6c56fb4bc5f0 165 volatile CCallback m_callback;
nexpaq 0:6c56fb4bc5f0 166
nexpaq 0:6c56fb4bc5f0 167 // TODO: this needs proper fix, to refactor toolchain header file and all its use
nexpaq 0:6c56fb4bc5f0 168 // PACKED there is not defined properly for IAR
nexpaq 0:6c56fb4bc5f0 169 #if defined (__ICCARM__)
nexpaq 0:6c56fb4bc5f0 170 typedef __packed struct
nexpaq 0:6c56fb4bc5f0 171 {
nexpaq 0:6c56fb4bc5f0 172 CTHUNK_VARIABLES;
nexpaq 0:6c56fb4bc5f0 173 volatile uint32_t instance;
nexpaq 0:6c56fb4bc5f0 174 volatile uint32_t context;
nexpaq 0:6c56fb4bc5f0 175 volatile uint32_t callback;
nexpaq 0:6c56fb4bc5f0 176 volatile uint32_t trampoline;
nexpaq 0:6c56fb4bc5f0 177 } CThunkTrampoline;
nexpaq 0:6c56fb4bc5f0 178 #else
nexpaq 0:6c56fb4bc5f0 179 typedef struct
nexpaq 0:6c56fb4bc5f0 180 {
nexpaq 0:6c56fb4bc5f0 181 CTHUNK_VARIABLES;
nexpaq 0:6c56fb4bc5f0 182 volatile uint32_t instance;
nexpaq 0:6c56fb4bc5f0 183 volatile uint32_t context;
nexpaq 0:6c56fb4bc5f0 184 volatile uint32_t callback;
nexpaq 0:6c56fb4bc5f0 185 volatile uint32_t trampoline;
nexpaq 0:6c56fb4bc5f0 186 } __attribute__((__packed__)) CThunkTrampoline;
nexpaq 0:6c56fb4bc5f0 187 #endif
nexpaq 0:6c56fb4bc5f0 188
nexpaq 0:6c56fb4bc5f0 189 static void trampoline(T* instance, void* context, CCallback* callback)
nexpaq 0:6c56fb4bc5f0 190 {
nexpaq 0:6c56fb4bc5f0 191 if(instance && *callback) {
nexpaq 0:6c56fb4bc5f0 192 (static_cast<T*>(instance)->**callback)(context);
nexpaq 0:6c56fb4bc5f0 193 }
nexpaq 0:6c56fb4bc5f0 194 }
nexpaq 0:6c56fb4bc5f0 195
nexpaq 0:6c56fb4bc5f0 196 volatile CThunkTrampoline m_thunk;
nexpaq 0:6c56fb4bc5f0 197
nexpaq 0:6c56fb4bc5f0 198 inline void init(T *instance, CCallback callback, void* context)
nexpaq 0:6c56fb4bc5f0 199 {
nexpaq 0:6c56fb4bc5f0 200 /* remember callback - need to add this level of redirection
nexpaq 0:6c56fb4bc5f0 201 as pointer size for member functions differs between platforms */
nexpaq 0:6c56fb4bc5f0 202 m_callback = callback;
nexpaq 0:6c56fb4bc5f0 203
nexpaq 0:6c56fb4bc5f0 204 /* populate thunking trampoline */
nexpaq 0:6c56fb4bc5f0 205 CTHUNK_ASSIGMENT;
nexpaq 0:6c56fb4bc5f0 206 m_thunk.context = (uint32_t)context;
nexpaq 0:6c56fb4bc5f0 207 m_thunk.instance = (uint32_t)instance;
nexpaq 0:6c56fb4bc5f0 208 m_thunk.callback = (uint32_t)&m_callback;
nexpaq 0:6c56fb4bc5f0 209 m_thunk.trampoline = (uint32_t)&trampoline;
nexpaq 0:6c56fb4bc5f0 210
nexpaq 0:6c56fb4bc5f0 211 #if defined(__CORTEX_A9)
nexpaq 0:6c56fb4bc5f0 212 /* Data cache clean */
nexpaq 0:6c56fb4bc5f0 213 /* Cache control */
nexpaq 0:6c56fb4bc5f0 214 {
nexpaq 0:6c56fb4bc5f0 215 uint32_t start_addr = (uint32_t)&m_thunk & 0xFFFFFFE0;
nexpaq 0:6c56fb4bc5f0 216 uint32_t end_addr = (uint32_t)&m_thunk + sizeof(m_thunk);
nexpaq 0:6c56fb4bc5f0 217 uint32_t addr;
nexpaq 0:6c56fb4bc5f0 218
nexpaq 0:6c56fb4bc5f0 219 /* Data cache clean and invalid */
nexpaq 0:6c56fb4bc5f0 220 for (addr = start_addr; addr < end_addr; addr += 0x20) {
nexpaq 0:6c56fb4bc5f0 221 __v7_clean_inv_dcache_mva((void *)addr);
nexpaq 0:6c56fb4bc5f0 222 }
nexpaq 0:6c56fb4bc5f0 223 /* Instruction cache invalid */
nexpaq 0:6c56fb4bc5f0 224 __v7_inv_icache_all();
nexpaq 0:6c56fb4bc5f0 225 __ca9u_inv_tlb_all();
nexpaq 0:6c56fb4bc5f0 226 __v7_inv_btac();
nexpaq 0:6c56fb4bc5f0 227 }
nexpaq 0:6c56fb4bc5f0 228 #endif
nexpaq 0:6c56fb4bc5f0 229 __ISB();
nexpaq 0:6c56fb4bc5f0 230 __DSB();
nexpaq 0:6c56fb4bc5f0 231 }
nexpaq 0:6c56fb4bc5f0 232 };
nexpaq 0:6c56fb4bc5f0 233
nexpaq 0:6c56fb4bc5f0 234 #endif/*__CTHUNK_H__*/