mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			
		
			
				
	
	
		
			252 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			252 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			C++
		
	
	
 | 
						|
/** \addtogroup platform */
 | 
						|
/** @{*/
 | 
						|
/**
 | 
						|
 * \defgroup platform_CThunk CThunk class
 | 
						|
 * @{
 | 
						|
 */
 | 
						|
/* General C++ Object Thunking class
 | 
						|
 *
 | 
						|
 * - allows direct callbacks to non-static C++ class functions
 | 
						|
 * - keeps track for the corresponding class instance
 | 
						|
 * - supports an optional context parameter for the called function
 | 
						|
 * - ideally suited for class object receiving interrupts (NVIC_SetVector)
 | 
						|
 *
 | 
						|
 * Copyright (c) 2014-2015 ARM Limited
 | 
						|
 *
 | 
						|
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
 * you may not use this file except in compliance with the License.
 | 
						|
 * You may obtain a copy of the License at
 | 
						|
 *
 | 
						|
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 *
 | 
						|
 * Unless required by applicable law or agreed to in writing, software
 | 
						|
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
 * See the License for the specific language governing permissions and
 | 
						|
 * limitations under the License.
 | 
						|
 */
 | 
						|
 | 
						|
/* General C++ Object Thunking class
 | 
						|
 *
 | 
						|
 * - allows direct callbacks to non-static C++ class functions
 | 
						|
 * - keeps track for the corresponding class instance
 | 
						|
 * - supports an optional context parameter for the called function
 | 
						|
 * - ideally suited for class object receiving interrupts (NVIC_SetVector)
 | 
						|
 */
 | 
						|
 | 
						|
#ifndef __CTHUNK_H__
 | 
						|
#define __CTHUNK_H__
 | 
						|
 | 
						|
#define CTHUNK_ADDRESS 1
 | 
						|
#define CTHUNK_VARIABLES volatile uint32_t code[2]
 | 
						|
 | 
						|
#if (defined(__CORTEX_M3) || defined(__CORTEX_M4) || defined(__CORTEX_M7) || defined(__CORTEX_A9) \
 | 
						|
    || defined(__CORTEX_M33))
 | 
						|
/**
 | 
						|
* CTHUNK disassembly for Cortex-M3/M4/M7/A9 (thumb2):
 | 
						|
* * adr  r0, #4
 | 
						|
* * ldm  r0, {r0, r1, r2, pc}
 | 
						|
*
 | 
						|
* This instruction loads the arguments for the static thunking function to r0-r2, and
 | 
						|
* branches to that function by loading its address into PC.
 | 
						|
*
 | 
						|
* This is safe for both regular calling and interrupt calling, since it only touches scratch registers
 | 
						|
* which should be saved by the caller, and are automatically saved as part of the IRQ context switch.
 | 
						|
*/
 | 
						|
#define CTHUNK_ASSIGMENT do {                              \
 | 
						|
                             m_thunk.code[0] = 0xE890A001; \
 | 
						|
                             m_thunk.code[1] = 0x00008007; \
 | 
						|
                         } while (0)
 | 
						|
 | 
						|
#elif (defined(__CORTEX_M0PLUS) || defined(__CORTEX_M0) || defined(__CORTEX_M23))
 | 
						|
/*
 | 
						|
* CTHUNK disassembly for Cortex M0/M0+ (thumb):
 | 
						|
* * adr  r0, #4
 | 
						|
* * ldm  r0, {r0, r1, r2, r3}
 | 
						|
* * bx   r3
 | 
						|
*/
 | 
						|
#define CTHUNK_ASSIGMENT do {                              \
 | 
						|
                             m_thunk.code[0] = 0xC80FA001; \
 | 
						|
                             m_thunk.code[1] = 0x00004718; \
 | 
						|
                         } while (0)
 | 
						|
 | 
						|
#else
 | 
						|
#error "Target is not currently suported."
 | 
						|
#endif
 | 
						|
 | 
						|
/* IRQ/Exception compatible thunk entry function */
 | 
						|
typedef void (*CThunkEntry)(void);
 | 
						|
 | 
						|
/**
 | 
						|
 * Class for created a pointer with data bound to it
 | 
						|
 *
 | 
						|
 * @note Synchronization level: Not protected
 | 
						|
 */
 | 
						|
template<class T>
 | 
						|
class CThunk {
 | 
						|
public:
 | 
						|
    typedef void (T::*CCallbackSimple)(void);
 | 
						|
    typedef void (T::*CCallback)(void *context);
 | 
						|
 | 
						|
    inline CThunk(T *instance)
 | 
						|
    {
 | 
						|
        init(instance, NULL, NULL);
 | 
						|
    }
 | 
						|
 | 
						|
    inline CThunk(T *instance, CCallback callback)
 | 
						|
    {
 | 
						|
        init(instance, callback, NULL);
 | 
						|
    }
 | 
						|
 | 
						|
    ~CThunk()
 | 
						|
    {
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    inline CThunk(T *instance, CCallbackSimple callback)
 | 
						|
    {
 | 
						|
        init(instance, (CCallback)callback, NULL);
 | 
						|
    }
 | 
						|
 | 
						|
    inline CThunk(T &instance, CCallback callback)
 | 
						|
    {
 | 
						|
        init(instance, callback, NULL);
 | 
						|
    }
 | 
						|
 | 
						|
    inline CThunk(T &instance, CCallbackSimple callback)
 | 
						|
    {
 | 
						|
        init(instance, (CCallback)callback, NULL);
 | 
						|
    }
 | 
						|
 | 
						|
    inline CThunk(T &instance, CCallback callback, void *context)
 | 
						|
    {
 | 
						|
        init(instance, callback, context);
 | 
						|
    }
 | 
						|
 | 
						|
    inline void callback(CCallback callback)
 | 
						|
    {
 | 
						|
        m_callback = callback;
 | 
						|
    }
 | 
						|
 | 
						|
    inline void callback(CCallbackSimple callback)
 | 
						|
    {
 | 
						|
        m_callback = (CCallback)callback;
 | 
						|
    }
 | 
						|
 | 
						|
    inline void context(void *context)
 | 
						|
    {
 | 
						|
        m_thunk.context = (uint32_t)context;
 | 
						|
    }
 | 
						|
 | 
						|
    inline void context(uint32_t context)
 | 
						|
    {
 | 
						|
        m_thunk.context = context;
 | 
						|
    }
 | 
						|
 | 
						|
    inline uint32_t entry(void)
 | 
						|
    {
 | 
						|
        return (((uint32_t)&m_thunk) | CTHUNK_ADDRESS);
 | 
						|
    }
 | 
						|
 | 
						|
    /* get thunk entry point for connecting rhunk to an IRQ table */
 | 
						|
    inline operator CThunkEntry(void)
 | 
						|
    {
 | 
						|
        return (CThunkEntry)entry();
 | 
						|
    }
 | 
						|
 | 
						|
    /* get thunk entry point for connecting rhunk to an IRQ table */
 | 
						|
    inline operator uint32_t(void)
 | 
						|
    {
 | 
						|
        return entry();
 | 
						|
    }
 | 
						|
 | 
						|
    /* simple test function */
 | 
						|
    inline void call(void)
 | 
						|
    {
 | 
						|
        (((CThunkEntry)(entry()))());
 | 
						|
    }
 | 
						|
 | 
						|
private:
 | 
						|
    T *m_instance;
 | 
						|
    volatile CCallback m_callback;
 | 
						|
 | 
						|
// TODO: this needs proper fix, to refactor toolchain header file and all its use
 | 
						|
// PACKED there is not defined properly for IAR
 | 
						|
#if defined (__ICCARM__)
 | 
						|
    typedef __packed struct {
 | 
						|
        CTHUNK_VARIABLES;
 | 
						|
        volatile uint32_t instance;
 | 
						|
        volatile uint32_t context;
 | 
						|
        volatile uint32_t callback;
 | 
						|
        volatile uint32_t trampoline;
 | 
						|
    }  CThunkTrampoline;
 | 
						|
#else
 | 
						|
    typedef struct {
 | 
						|
        CTHUNK_VARIABLES;
 | 
						|
        volatile uint32_t instance;
 | 
						|
        volatile uint32_t context;
 | 
						|
        volatile uint32_t callback;
 | 
						|
        volatile uint32_t trampoline;
 | 
						|
    } __attribute__((__packed__)) CThunkTrampoline;
 | 
						|
#endif
 | 
						|
 | 
						|
    static void trampoline(T *instance, void *context, CCallback *callback)
 | 
						|
    {
 | 
						|
        if (instance && *callback) {
 | 
						|
            (static_cast<T *>(instance)->**callback)(context);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    volatile CThunkTrampoline m_thunk;
 | 
						|
 | 
						|
    inline void init(T *instance, CCallback callback, void *context)
 | 
						|
    {
 | 
						|
        /* remember callback - need to add this level of redirection
 | 
						|
           as pointer size for member functions differs between platforms */
 | 
						|
        m_callback = callback;
 | 
						|
 | 
						|
        /* populate thunking trampoline */
 | 
						|
        CTHUNK_ASSIGMENT;
 | 
						|
        m_thunk.context = (uint32_t)context;
 | 
						|
        m_thunk.instance = (uint32_t)instance;
 | 
						|
        m_thunk.callback = (uint32_t)&m_callback;
 | 
						|
        m_thunk.trampoline = (uint32_t)&trampoline;
 | 
						|
 | 
						|
#if defined(__CORTEX_A9)
 | 
						|
        /* Data cache clean */
 | 
						|
        /* Cache control */
 | 
						|
        {
 | 
						|
            uint32_t start_addr = (uint32_t)&m_thunk & 0xFFFFFFE0;
 | 
						|
            uint32_t end_addr   = (uint32_t)&m_thunk + sizeof(m_thunk);
 | 
						|
            uint32_t addr;
 | 
						|
 | 
						|
            /* Data cache clean and invalid */
 | 
						|
            for (addr = start_addr; addr < end_addr; addr += 0x20) {
 | 
						|
                L1C_CleanInvalidateDCacheMVA((void *)addr);
 | 
						|
            }
 | 
						|
            /* Instruction cache invalid */
 | 
						|
            L1C_InvalidateICacheAll();
 | 
						|
            MMU_InvalidateTLB();
 | 
						|
            L1C_InvalidateBTAC();
 | 
						|
        }
 | 
						|
#endif
 | 
						|
#if defined(__CORTEX_M7)
 | 
						|
        /* Data cache clean and invalid */
 | 
						|
        SCB_CleanInvalidateDCache();
 | 
						|
 | 
						|
        /* Instruction cache invalid */
 | 
						|
        SCB_InvalidateICache();
 | 
						|
#endif
 | 
						|
        __ISB();
 | 
						|
        __DSB();
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
/**@}*/
 | 
						|
 | 
						|
/**@}*/
 | 
						|
 | 
						|
#endif/*__CTHUNK_H__*/
 | 
						|
 |