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