#include <stdbool.h>
static inline uint32_t disable(void)
{
uint32_t primask;
__asm__ __volatile__("mrs %0, primask" : "=r"(primask));
__asm__("cpsid i" ::: "memory");
return primask;
}
static inline void restore(uint32_t mask)
{
__asm__("msr primask, %0" : : "r"(mask) : "memory");
}
static inline void barrier_start(int memorder)
{
if ((memorder == __ATOMIC_RELEASE) || (memorder == __ATOMIC_ACQ_REL) ||
(memorder == __ATOMIC_SEQ_CST))
{
__asm__("dmb" ::: "memory");
}
}
static inline void barrier_end(int memorder)
{
if ((memorder == __ATOMIC_CONSUME) || (memorder == __ATOMIC_ACQUIRE) ||
(memorder == __ATOMIC_ACQ_REL) || (memorder == __ATOMIC_SEQ_CST))
{
__asm__("dmb" ::: "memory");
}
}
unsigned char __atomic_exchange_1(volatile void *ptr, unsigned char val,
int memorder)
{
volatile unsigned char *const p = ptr;
const uint32_t mask = disable();
barrier_start(memorder);
const unsigned char old = *p;
*p = val;
barrier_end(memorder);
restore(mask);
return old;
}
unsigned __atomic_exchange_4(volatile void *ptr, unsigned val, int memorder)
{
volatile unsigned *const p = ptr;
const uint32_t mask = disable();
barrier_start(memorder);
const unsigned old = *p;
*p = val;
barrier_end(memorder);
restore(mask);
return old;
}
unsigned __atomic_fetch_add_4(volatile void *ptr, unsigned val, int memorder)
{
volatile unsigned *const p = ptr;
const uint32_t mask = disable();
barrier_start(memorder);
const unsigned old = *p;
*p = old + val;
barrier_end(memorder);
restore(mask);
return old;
}
unsigned __atomic_fetch_sub_4(volatile void *ptr, unsigned val, int memorder)
{
volatile unsigned *const p = ptr;
const uint32_t mask = disable();
barrier_start(memorder);
const unsigned old = *p;
*p = old - val;
barrier_end(memorder);
restore(mask);
return old;
}
unsigned __atomic_fetch_and_4(volatile void *ptr, unsigned val, int memorder)
{
volatile unsigned *const p = ptr;
const uint32_t mask = disable();
barrier_start(memorder);
const unsigned old = *p;
*p = old & val;
barrier_end(memorder);
restore(mask);
return old;
}
unsigned __atomic_fetch_or_4(volatile void *ptr, unsigned val, int memorder)
{
volatile unsigned *const p = ptr;
const uint32_t mask = disable();
barrier_start(memorder);
const unsigned old = *p;
*p = old | val;
barrier_end(memorder);
restore(mask);
return old;
}
bool __atomic_test_and_set(volatile void *ptr, int memorder)
{
volatile bool *const p = ptr;
const uint32_t mask = disable();
barrier_start(memorder);
const bool old = *p;
*p = true;
barrier_end(memorder);
restore(mask);
return old;
}
bool __atomic_compare_exchange_1(volatile void *ptr, void *exp,
unsigned char val, bool weak,
int success_memorder, int fail_memorder)
{
(void)weak;
volatile unsigned char *const p = ptr;
unsigned char *const e = exp;
const uint32_t mask = disable();
barrier_start(success_memorder);
const unsigned char old = *p;
const bool equal = old == *e;
if (equal)
{
*p = val;
barrier_end(success_memorder);
}
else
{
*e = old;
barrier_end(fail_memorder);
}
restore(mask);
return equal;
}
bool __atomic_compare_exchange_4(volatile void *ptr, void *exp, unsigned val,
bool weak, int success_memorder,
int fail_memorder)
{
(void)weak;
volatile unsigned *const p = ptr;
unsigned *const e = exp;
const uint32_t mask = disable();
barrier_start(success_memorder);
const unsigned old = *p;
const bool equal = old == *e;
if (equal)
{
*p = val;
barrier_end(success_memorder);
}
else
{
*e = old;
barrier_end(fail_memorder);
}
restore(mask);
return equal;
}