atomic_utils_arch.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2020 Otto-von-Guericke-Universität Magdeburg
3  *
4  * This file is subject to the terms and conditions of the GNU Lesser General
5  * Public License v2.1. See the file LICENSE in the top level directory for more
6  * details.
7  */
8 
19 #ifndef ATOMIC_UTILS_ARCH_H
20 #define ATOMIC_UTILS_ARCH_H
21 #ifndef DOXYGEN
22 
23 #include "bit.h"
24 #include "periph_cpu.h"
25 
26 #ifdef __cplusplus
27 extern "C" {
28 #endif
29 
30 /* clang provides no built-in atomic access to regular variables */
31 #ifndef __clang__
32 
33 #define HAS_ATOMIC_LOAD_U8
34 static inline uint8_t atomic_load_u8(const uint8_t *var)
35 {
36  return __atomic_load_1(var, __ATOMIC_SEQ_CST);
37 }
38 
39 #define HAS_ATOMIC_LOAD_U16
40 static inline uint16_t atomic_load_u16(const uint16_t *var)
41 {
42  return __atomic_load_2(var, __ATOMIC_SEQ_CST);
43 }
44 
45 #define HAS_ATOMIC_LOAD_U32
46 static inline uint32_t atomic_load_u32(const uint32_t *var)
47 {
48  return __atomic_load_4(var, __ATOMIC_SEQ_CST);
49 }
50 
51 #define HAS_ATOMIC_STORE_U8
52 static inline void atomic_store_u8(uint8_t *dest, uint8_t val)
53 {
54  __atomic_store_1(dest, val, __ATOMIC_SEQ_CST);
55 }
56 
57 #define HAS_ATOMIC_STORE_U16
58 static inline void atomic_store_u16(uint16_t *dest, uint16_t val)
59 {
60  __atomic_store_2(dest, val, __ATOMIC_SEQ_CST);
61 }
62 
63 #define HAS_ATOMIC_STORE_U32
64 static inline void atomic_store_u32(uint32_t *dest, uint32_t val)
65 {
66  __atomic_store_4(dest, val, __ATOMIC_SEQ_CST);
67 }
68 
69 #endif /* __clang__ */
70 
71 #if CPU_HAS_BITBAND
72 #define HAS_ATOMIC_BIT
73 
74 typedef volatile uint32_t *atomic_bit_u8_t;
75 typedef volatile uint32_t *atomic_bit_u16_t;
76 typedef volatile uint32_t *atomic_bit_u32_t;
77 typedef volatile uint32_t *atomic_bit_u64_t;
78 
79 static inline void __attribute__((always_inline)) _bit_barrier_pre(void)
80 {
81  __asm__ volatile ("" : : : "memory");
82 }
83 
84 static inline void __attribute__((always_inline)) _bit_barrier_post(void)
85 {
86  __asm__ volatile ("" : : : "memory");
87 }
88 
89 static inline bool _is_addr_valid_for_bitbanding(void *_addr)
90 {
91  /* SRAM bit-band region goes from 0x20000000 to 0x200fffff,
92  * peripheral bit-band region goes from 0x40000000 to 0x400fffff */
93  uintptr_t addr = (uintptr_t)_addr;
94  if ((addr < 0x20000000UL) || (addr > 0x400fffffUL)) {
95  return false;
96  }
97 
98  if ((addr >= 0x200fffffUL) && (addr < 0x40000000UL)) {
99  return false;
100  }
101 
102  return true;
103 }
104 
105 static inline atomic_bit_u8_t atomic_bit_u8(uint8_t *dest, uint8_t bit)
106 {
107  assert(_is_addr_valid_for_bitbanding(dest));
108  return bitband_addr(dest, bit);
109 }
110 
111 static inline atomic_bit_u16_t atomic_bit_u16(uint16_t *dest, uint8_t bit)
112 {
113  assert(_is_addr_valid_for_bitbanding(dest));
114  return bitband_addr(dest, bit);
115 }
116 
117 static inline atomic_bit_u32_t atomic_bit_u32(uint32_t *dest, uint8_t bit)
118 {
119  assert(_is_addr_valid_for_bitbanding(dest));
120  return bitband_addr(dest, bit);
121 }
122 
123 static inline atomic_bit_u64_t atomic_bit_u64(uint64_t *dest, uint8_t bit)
124 {
125  assert(_is_addr_valid_for_bitbanding(dest));
126  return bitband_addr(dest, bit);
127 }
128 
129 static inline void atomic_set_bit_u8(atomic_bit_u8_t bit)
130 {
131  _bit_barrier_pre();
132  *bit = 1;
133  _bit_barrier_post();
134 }
135 
136 static inline void atomic_set_bit_u16(atomic_bit_u16_t bit)
137 {
138  _bit_barrier_pre();
139  *bit = 1;
140  _bit_barrier_post();
141 }
142 
143 static inline void atomic_set_bit_u32(atomic_bit_u32_t bit)
144 {
145  _bit_barrier_pre();
146  *bit = 1;
147  _bit_barrier_post();
148 }
149 
150 static inline void atomic_set_bit_u64(atomic_bit_u64_t bit)
151 {
152  _bit_barrier_pre();
153  *bit = 1;
154  _bit_barrier_post();
155 }
156 
157 static inline void atomic_clear_bit_u8(atomic_bit_u8_t bit)
158 {
159  _bit_barrier_pre();
160  *bit = 0;
161  _bit_barrier_post();
162 }
163 static inline void atomic_clear_bit_u16(atomic_bit_u16_t bit)
164 {
165  _bit_barrier_pre();
166  *bit = 0;
167  _bit_barrier_post();
168 }
169 
170 static inline void atomic_clear_bit_u32(atomic_bit_u32_t bit)
171 {
172  _bit_barrier_pre();
173  *bit = 0;
174  _bit_barrier_post();
175 }
176 
177 static inline void atomic_clear_bit_u64(atomic_bit_u64_t bit)
178 {
179  _bit_barrier_pre();
180  *bit = 0;
181  _bit_barrier_post();
182 }
183 
184 
185 #endif /* CPU_HAS_BITBAND */
186 
187 #ifdef __cplusplus
188 }
189 #endif
190 
191 #endif /* DOXYGEN */
192 #endif /* ATOMIC_UTILS_ARCH_H */
193 
atomic_bit_u32
static atomic_bit_u32_t atomic_bit_u32(uint32_t *dest, uint8_t bit)
Create a reference to a bit in an uint32_t
Definition: atomic_utils.h:862
atomic_bit_u64_t
Type specifying a bit in an uint64_t
Definition: atomic_utils.h:200
atomic_bit_u8
static atomic_bit_u8_t atomic_bit_u8(uint8_t *dest, uint8_t bit)
Create a reference to a bit in an uint8_t
Definition: atomic_utils.h:852
atomic_store_u32
static void atomic_store_u32(uint32_t *dest, uint32_t val)
Store an uint32_t atomically.
assert
#define assert(cond)
abort the program if assertion is false
Definition: assert.h:104
bitband_addr
static volatile void * bitband_addr(volatile void *ptr, uintptr_t bit)
Convert bit band region address and bit number to bit band alias address.
Definition: bit.h:54
atomic_clear_bit_u32
static void atomic_clear_bit_u32(atomic_bit_u32_t bit)
Atomic version of *dest &= ~(1 << bit)
Definition: atomic_utils.h:896
atomic_clear_bit_u16
static void atomic_clear_bit_u16(atomic_bit_u16_t bit)
Atomic version of *dest &= ~(1 << bit)
Definition: atomic_utils.h:892
atomic_set_bit_u16
static void atomic_set_bit_u16(atomic_bit_u16_t bit)
Atomic version of *dest |= (1 << bit)
Definition: atomic_utils.h:876
atomic_set_bit_u8
static void atomic_set_bit_u8(atomic_bit_u8_t bit)
Atomic version of *dest |= (1 << bit)
Definition: atomic_utils.h:872
atomic_clear_bit_u64
static void atomic_clear_bit_u64(atomic_bit_u64_t bit)
Atomic version of *dest &= ~(1 << bit)
Definition: atomic_utils.h:900
atomic_clear_bit_u8
static void atomic_clear_bit_u8(atomic_bit_u8_t bit)
Atomic version of *dest &= ~(1 << bit)
Definition: atomic_utils.h:888
atomic_store_u16
static void atomic_store_u16(uint16_t *dest, uint16_t val)
Store an uint16_t atomically.
atomic_load_u16
static uint16_t atomic_load_u16(const uint16_t *var)
Load an uint16_t atomically.
atomic_store_u8
static void atomic_store_u8(uint8_t *dest, uint8_t val)
Store an uint8_t atomically.
atomic_bit_u64
static atomic_bit_u64_t atomic_bit_u64(uint64_t *dest, uint8_t bit)
Create a reference to a bit in an uint64_t
Definition: atomic_utils.h:867
atomic_bit_u16_t
Type specifying a bit in an uint16_t
Definition: atomic_utils.h:180
atomic_bit_u16
static atomic_bit_u16_t atomic_bit_u16(uint16_t *dest, uint8_t bit)
Create a reference to a bit in an uint16_t
Definition: atomic_utils.h:857
atomic_load_u32
static uint32_t atomic_load_u32(const uint32_t *var)
Load an uint32_t atomically.
atomic_bit_u8_t
Type specifying a bit in an uint8_t
Definition: atomic_utils.h:170
bit.h
Bit access macros for Cortex-M based CPUs.
atomic_bit_u32_t
Type specifying a bit in an uint32_t
Definition: atomic_utils.h:190
atomic_load_u8
static uint8_t atomic_load_u8(const uint8_t *var)
Load an uint8_t atomically.
atomic_set_bit_u32
static void atomic_set_bit_u32(atomic_bit_u32_t bit)
Atomic version of *dest |= (1 << bit)
Definition: atomic_utils.h:880
atomic_set_bit_u64
static void atomic_set_bit_u64(atomic_bit_u64_t bit)
Atomic version of *dest |= (1 << bit)
Definition: atomic_utils.h:884