[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:
Frantisek Burian 2013-09-12 00:56:02 -07:00 committed by Piotr Esden-Tempski
parent 17fc71a462
commit 8e96592f55
1 changed files with 132 additions and 3 deletions

View File

@ -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