[CM3] Add atomic operation support
Tested with -O0, -O2 and -Os generating correct code with gcc-arm-embedded 2013q2. note -std=c99 or newer needed
This commit is contained in:
parent
17fc71a462
commit
8e96592f55
|
@ -138,11 +138,140 @@ static inline bool cm_mask_faults(bool mask)
|
|||
{
|
||||
register bool old;
|
||||
__asm__ __volatile__ ("MRS %0, FAULTMASK" : "=r" (old));
|
||||
__asm__ __volatile__("" ::: "memory");
|
||||
__asm__ __volatile__ ("" ::: "memory");
|
||||
__asm__ __volatile__ ("MSR FAULTMASK, %0" : : "r" (mask));
|
||||
return old;
|
||||
}
|
||||
}
|
||||
|
||||
/**@}*/
|
||||
/**@}*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/** @defgroup CM3_cortex_atomic_defines Cortex Core Atomic support Defines
|
||||
*
|
||||
* @brief Atomic operation support
|
||||
*
|
||||
* @ingroup CM3_cortex_defines
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
#if !defined(__DOXYGEN__)
|
||||
/* Do not populate this definition outside */
|
||||
static inline bool __cm_atomic_set(bool* val)
|
||||
{
|
||||
return cm_mask_interrupts(*val);
|
||||
}
|
||||
|
||||
#define __CM_SAVER(state) __val = state, \
|
||||
__save __attribute__((__cleanup__(__cm_atomic_set))) = \
|
||||
__cm_atomic_set(&__val)
|
||||
|
||||
#endif /* !defined(__DOXYGEN) */
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Cortex M Atomic Declare block
|
||||
*
|
||||
* This macro disables interrupts for the next command or block of code. The
|
||||
* interrupt mask is automatically restored after exit of the boundary of the
|
||||
* code block. Therefore restore of interrupt is done automatically after call
|
||||
* of return or goto control sentence jumping outside of the block.
|
||||
*
|
||||
* @warning The usage of sentences break or continue is prohibited in the block
|
||||
* due to implementation of this macro!
|
||||
*
|
||||
* @note It is safe to use this block inside normal code and in interrupt
|
||||
* routine.
|
||||
*
|
||||
* @example 1: Basic usage of atomic block
|
||||
*
|
||||
* @code
|
||||
* uint64_t value; // This value is used somewhere in interrupt
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* CM_ATOMIC_BLOCK() { // interrupts are masked in this block
|
||||
* value = value * 1024 + 651; // access value as atomic
|
||||
* } // interrupts is restored automatically
|
||||
* @endcode
|
||||
*
|
||||
* @example 2: Use of return inside block:
|
||||
*
|
||||
* @code
|
||||
* uint64_t value; // This value is used somewhere in interrupt
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* uint64_t allocval(void)
|
||||
* {
|
||||
* CM_ATOMIC_BLOCK() { // interrupts are masked in this block
|
||||
* value = value * 1024 + 651; // do long atomic operation
|
||||
* return value; // interrupts is restored automatically
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
#if defined(__DOXYGEN__)
|
||||
#define CM_ATOMIC_BLOCK()
|
||||
#else /* defined(__DOXYGEN__) */
|
||||
#define CM_ATOMIC_BLOCK() \
|
||||
for (bool ___CM_SAVER(true), __My = true; __My; __My = false)
|
||||
#endif /* defined(__DOXYGEN__) */
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** @brief Cortex M Atomic Declare context
|
||||
*
|
||||
* This macro disables interrupts in the current block of code from the place
|
||||
* where it is defined to the end of the block. The interrupt mask is
|
||||
* automatically restored after exit of the boundary of the code block.
|
||||
* Therefore restore of interrupt is done automatically after call of return,
|
||||
* continue, break, or goto control sentence jumping outside of the block.
|
||||
*
|
||||
* @note This function is intended for use in for- cycles to enable the use of
|
||||
* break and contine sentences inside the block, and for securing the atomic
|
||||
* reader-like functions.
|
||||
*
|
||||
* @note It is safe to use this block inside normal code and in interrupt
|
||||
* routine.
|
||||
*
|
||||
* @example 1: Basic usage of atomic context
|
||||
*
|
||||
* @code
|
||||
* uint64_t value; // This value is used somewhere in interrupt
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* for (int i=0;i < 100; i++) {
|
||||
* CM_ATOMIC_CONTEXT(); // interrupts are masked in this block
|
||||
* value += 100; // access value as atomic
|
||||
* if ((value % 16) == 0) {
|
||||
* break; // restore interrupts and break cycle
|
||||
* }
|
||||
* } // interrupts is restored automatically
|
||||
* @endcode
|
||||
*
|
||||
* @example 2: Usage of atomic context inside atomic reader fcn.
|
||||
*
|
||||
* @code
|
||||
* uint64_t value; // This value is used somewhere in interrupt
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* uint64_t getnextval(void)
|
||||
* {
|
||||
* CM_ATOMIC_CONTEXT(); // interrupts are masked in this block
|
||||
* value = value + 3; // do long atomic operation
|
||||
* return value; // interrupts is restored automatically
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
#if defined(__DOXYGEN__)
|
||||
#define CM_ATOMIC_CONTEXT()
|
||||
#else /* defined(__DOXYGEN__) */
|
||||
#define CM_ATOMIC_CONTEXT() bool __CM_SAVER(true)
|
||||
#endif /* defined(__DOXYGEN__) */
|
||||
|
||||
/**@}*/
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue