1 /*
2 * Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31 #include "nrfx_atomic.h"
32
33 #ifndef NRFX_ATOMIC_USE_BUILT_IN
34 #define NRFX_ATOMIC_USE_BUILT_IN 0
35 #endif // NRFX_ATOMIC_USE_BUILT_IN
36
37 #if ((__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U))
38 #define NRFX_ATOMIC_STREX_LDREX_PRESENT
39 #endif
40
41 #if (NRFX_ATOMIC_USE_BUILT_IN == 0) && defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
42 #include "nrfx_atomic_internal.h"
43 #endif
44
nrfx_atomic_u32_fetch_store(nrfx_atomic_u32_t * p_data,uint32_t value)45 uint32_t nrfx_atomic_u32_fetch_store(nrfx_atomic_u32_t * p_data, uint32_t value)
46 {
47 #if NRFX_ATOMIC_USE_BUILT_IN
48 return __atomic_exchange_n(p_data, value, __ATOMIC_SEQ_CST);
49 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
50 uint32_t old_val;
51 uint32_t new_val;
52 NRFX_ATOMIC_OP(mov, old_val, new_val, p_data, value);
53 (void) new_val;
54 return old_val;
55 #else
56 NRFX_CRITICAL_SECTION_ENTER();
57 uint32_t old_val = *p_data;
58 *p_data = value;
59 NRFX_CRITICAL_SECTION_EXIT();
60 return old_val;
61 #endif // NRFX_ATOMIC_USE_BUILT_IN
62 }
63
nrfx_atomic_u32_store(nrfx_atomic_u32_t * p_data,uint32_t value)64 uint32_t nrfx_atomic_u32_store(nrfx_atomic_u32_t * p_data, uint32_t value)
65 {
66 #if NRFX_ATOMIC_USE_BUILT_IN
67 __atomic_store_n(p_data, value, __ATOMIC_SEQ_CST);
68 return value;
69 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
70 uint32_t old_val;
71 uint32_t new_val;
72 NRFX_ATOMIC_OP(mov, old_val, new_val, p_data, value);
73 (void) old_val;
74 return new_val;
75 #else
76 NRFX_CRITICAL_SECTION_ENTER();
77 *p_data = value;
78 NRFX_CRITICAL_SECTION_EXIT();
79 return value;
80 #endif //NRFX_ATOMIC_USE_BUILT_IN
81 }
82
nrfx_atomic_u32_fetch_or(nrfx_atomic_u32_t * p_data,uint32_t value)83 uint32_t nrfx_atomic_u32_fetch_or(nrfx_atomic_u32_t * p_data, uint32_t value)
84 {
85 #if NRFX_ATOMIC_USE_BUILT_IN
86 return __atomic_fetch_or(p_data, value, __ATOMIC_SEQ_CST);
87 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
88 uint32_t old_val;
89 uint32_t new_val;
90 NRFX_ATOMIC_OP(orr, old_val, new_val, p_data, value);
91 (void) new_val;
92 return old_val;
93 #else
94 NRFX_CRITICAL_SECTION_ENTER();
95 uint32_t old_val = *p_data;
96 *p_data |= value;
97 NRFX_CRITICAL_SECTION_EXIT();
98 return old_val;
99 #endif //NRFX_ATOMIC_USE_BUILT_IN
100 }
101
nrfx_atomic_u32_or(nrfx_atomic_u32_t * p_data,uint32_t value)102 uint32_t nrfx_atomic_u32_or(nrfx_atomic_u32_t * p_data, uint32_t value)
103 {
104 #if NRFX_ATOMIC_USE_BUILT_IN
105 return __atomic_or_fetch(p_data, value, __ATOMIC_SEQ_CST);
106 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
107 uint32_t old_val;
108 uint32_t new_val;
109 NRFX_ATOMIC_OP(orr, old_val, new_val, p_data, value);
110 (void) old_val;
111 return new_val;
112 #else
113 NRFX_CRITICAL_SECTION_ENTER();
114 *p_data |= value;
115 uint32_t new_value = *p_data;
116 NRFX_CRITICAL_SECTION_EXIT();
117 return new_value;
118 #endif //NRFX_ATOMIC_USE_BUILT_IN
119 }
120
nrfx_atomic_u32_fetch_and(nrfx_atomic_u32_t * p_data,uint32_t value)121 uint32_t nrfx_atomic_u32_fetch_and(nrfx_atomic_u32_t * p_data, uint32_t value)
122 {
123 #if NRFX_ATOMIC_USE_BUILT_IN
124 return __atomic_fetch_and(p_data, value, __ATOMIC_SEQ_CST);
125 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
126 uint32_t old_val;
127 uint32_t new_val;
128 NRFX_ATOMIC_OP(and, old_val, new_val, p_data, value);
129 (void) new_val;
130 return old_val;
131 #else
132 NRFX_CRITICAL_SECTION_ENTER();
133 uint32_t old_val = *p_data;
134 *p_data &= value;
135 NRFX_CRITICAL_SECTION_EXIT();
136 return old_val;
137 #endif //NRFX_ATOMIC_USE_BUILT_IN
138 }
139
nrfx_atomic_u32_and(nrfx_atomic_u32_t * p_data,uint32_t value)140 uint32_t nrfx_atomic_u32_and(nrfx_atomic_u32_t * p_data, uint32_t value)
141 {
142 #if NRFX_ATOMIC_USE_BUILT_IN
143 return __atomic_and_fetch(p_data, value, __ATOMIC_SEQ_CST);
144 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
145 uint32_t old_val;
146 uint32_t new_val;
147 NRFX_ATOMIC_OP(and, old_val, new_val, p_data, value);
148 (void) old_val;
149 return new_val;
150 #else
151 NRFX_CRITICAL_SECTION_ENTER();
152 *p_data &= value;
153 uint32_t new_value = *p_data;
154 NRFX_CRITICAL_SECTION_EXIT();
155 return new_value;
156 #endif //NRFX_ATOMIC_USE_BUILT_IN
157 }
158
nrfx_atomic_u32_fetch_xor(nrfx_atomic_u32_t * p_data,uint32_t value)159 uint32_t nrfx_atomic_u32_fetch_xor(nrfx_atomic_u32_t * p_data, uint32_t value)
160 {
161 #if NRFX_ATOMIC_USE_BUILT_IN
162 return __atomic_fetch_xor(p_data, value, __ATOMIC_SEQ_CST);
163 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
164 uint32_t old_val;
165 uint32_t new_val;
166 NRFX_ATOMIC_OP(eor, old_val, new_val, p_data, value);
167 (void) new_val;
168 return old_val;
169 #else
170 NRFX_CRITICAL_SECTION_ENTER();
171 uint32_t old_val = *p_data;
172 *p_data ^= value;
173 NRFX_CRITICAL_SECTION_EXIT();
174 return old_val;
175 #endif //NRFX_ATOMIC_USE_BUILT_IN
176 }
177
nrfx_atomic_u32_xor(nrfx_atomic_u32_t * p_data,uint32_t value)178 uint32_t nrfx_atomic_u32_xor(nrfx_atomic_u32_t * p_data, uint32_t value)
179 {
180 #if NRFX_ATOMIC_USE_BUILT_IN
181 return __atomic_xor_fetch(p_data, value, __ATOMIC_SEQ_CST);
182 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
183 uint32_t old_val;
184 uint32_t new_val;
185 NRFX_ATOMIC_OP(eor, old_val, new_val, p_data, value);
186 (void) old_val;
187 return new_val;
188 #else
189 NRFX_CRITICAL_SECTION_ENTER();
190 *p_data ^= value;
191 uint32_t new_value = *p_data;
192 NRFX_CRITICAL_SECTION_EXIT();
193 return new_value;
194 #endif //NRFX_ATOMIC_USE_BUILT_IN
195 }
196
nrfx_atomic_u32_fetch_add(nrfx_atomic_u32_t * p_data,uint32_t value)197 uint32_t nrfx_atomic_u32_fetch_add(nrfx_atomic_u32_t * p_data, uint32_t value)
198 {
199 #if NRFX_ATOMIC_USE_BUILT_IN
200 return __atomic_fetch_add(p_data, value, __ATOMIC_SEQ_CST);
201 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
202 uint32_t old_val;
203 uint32_t new_val;
204 NRFX_ATOMIC_OP(add, old_val, new_val, p_data, value);
205 (void) new_val;
206 return old_val;
207 #else
208 NRFX_CRITICAL_SECTION_ENTER();
209 uint32_t old_val = *p_data;
210 *p_data += value;
211 NRFX_CRITICAL_SECTION_EXIT();
212 return old_val;
213 #endif //NRFX_ATOMIC_USE_BUILT_IN
214 }
215
nrfx_atomic_u32_add(nrfx_atomic_u32_t * p_data,uint32_t value)216 uint32_t nrfx_atomic_u32_add(nrfx_atomic_u32_t * p_data, uint32_t value)
217 {
218 #if NRFX_ATOMIC_USE_BUILT_IN
219 return __atomic_add_fetch(p_data, value, __ATOMIC_SEQ_CST);
220 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
221 uint32_t old_val;
222 uint32_t new_val;
223 NRFX_ATOMIC_OP(add, old_val, new_val, p_data, value);
224 (void) old_val;
225 return new_val;
226 #else
227 NRFX_CRITICAL_SECTION_ENTER();
228 *p_data += value;
229 uint32_t new_value = *p_data;
230 NRFX_CRITICAL_SECTION_EXIT();
231 return new_value;
232 #endif //NRFX_ATOMIC_USE_BUILT_IN
233 }
234
nrfx_atomic_u32_fetch_sub(nrfx_atomic_u32_t * p_data,uint32_t value)235 uint32_t nrfx_atomic_u32_fetch_sub(nrfx_atomic_u32_t * p_data, uint32_t value)
236 {
237 #if NRFX_ATOMIC_USE_BUILT_IN
238 return __atomic_fetch_sub(p_data, value, __ATOMIC_SEQ_CST);
239 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
240 uint32_t old_val;
241 uint32_t new_val;
242 NRFX_ATOMIC_OP(sub, old_val, new_val, p_data, value);
243 (void) new_val;
244 return old_val;
245 #else
246 NRFX_CRITICAL_SECTION_ENTER();
247 uint32_t old_val = *p_data;
248 *p_data -= value;
249 NRFX_CRITICAL_SECTION_EXIT();
250 return old_val;
251 #endif //NRFX_ATOMIC_USE_BUILT_IN
252 }
253
nrfx_atomic_u32_sub(nrfx_atomic_u32_t * p_data,uint32_t value)254 uint32_t nrfx_atomic_u32_sub(nrfx_atomic_u32_t * p_data, uint32_t value)
255 {
256 #if NRFX_ATOMIC_USE_BUILT_IN
257 return __atomic_sub_fetch(p_data, value, __ATOMIC_SEQ_CST);
258 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
259 uint32_t old_val;
260 uint32_t new_val;
261 NRFX_ATOMIC_OP(sub, old_val, new_val, p_data, value);
262 (void) old_val;
263 return new_val;
264 #else
265 NRFX_CRITICAL_SECTION_ENTER();
266 *p_data -= value;
267 uint32_t new_value = *p_data;
268 NRFX_CRITICAL_SECTION_EXIT();
269 return new_value;
270 #endif //NRFX_ATOMIC_USE_BUILT_IN
271 }
272
nrfx_atomic_u32_cmp_exch(nrfx_atomic_u32_t * p_data,uint32_t * p_expected,uint32_t desired)273 bool nrfx_atomic_u32_cmp_exch(nrfx_atomic_u32_t * p_data,
274 uint32_t * p_expected,
275 uint32_t desired)
276 {
277 #if NRFX_ATOMIC_USE_BUILT_IN
278 return __atomic_compare_exchange(p_data,
279 p_expected,
280 &desired,
281 1,
282 __ATOMIC_SEQ_CST,
283 __ATOMIC_SEQ_CST);
284 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
285 return nrfx_atomic_internal_cmp_exch(p_data, p_expected, desired);
286 #else
287 bool result;
288 NRFX_CRITICAL_SECTION_ENTER();
289 if (*p_data == *p_expected)
290 {
291 *p_data = desired;
292 result = true;
293 }
294 else
295 {
296 *p_expected = *p_data;
297 result = false;
298 }
299 NRFX_CRITICAL_SECTION_EXIT();
300 return result;
301 #endif
302 }
303
nrfx_atomic_u32_fetch_sub_hs(nrfx_atomic_u32_t * p_data,uint32_t value)304 uint32_t nrfx_atomic_u32_fetch_sub_hs(nrfx_atomic_u32_t * p_data, uint32_t value)
305 {
306 #if NRFX_ATOMIC_USE_BUILT_IN
307 uint32_t expected = *p_data;
308 uint32_t new_val;
309 do {
310 if (expected >= value)
311 {
312 new_val = expected - value;
313 }
314 else
315 {
316 new_val = expected;
317 }
318 } while (!__atomic_compare_exchange(p_data, &expected, &new_val,
319 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST));
320 return expected;
321 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
322 uint32_t old_val;
323 uint32_t new_val;
324 NRFX_ATOMIC_OP(sub_hs, old_val, new_val, p_data, value);
325 (void) new_val;
326 return old_val;
327 #else
328 NRFX_CRITICAL_SECTION_ENTER();
329 uint32_t old_val = *p_data;
330 *p_data -= value;
331 NRFX_CRITICAL_SECTION_EXIT();
332 return old_val;
333 #endif //NRFX_ATOMIC_USE_BUILT_IN
334 }
335
nrfx_atomic_u32_sub_hs(nrfx_atomic_u32_t * p_data,uint32_t value)336 uint32_t nrfx_atomic_u32_sub_hs(nrfx_atomic_u32_t * p_data, uint32_t value)
337 {
338 #if NRFX_ATOMIC_USE_BUILT_IN
339 uint32_t expected = *p_data;
340 uint32_t new_val;
341 do {
342 if (expected >= value)
343 {
344 new_val = expected - value;
345 }
346 else
347 {
348 new_val = expected;
349 }
350 } while (!__atomic_compare_exchange(p_data, &expected, &new_val,
351 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST));
352 return new_val;
353 #elif defined(NRFX_ATOMIC_STREX_LDREX_PRESENT)
354 uint32_t old_val;
355 uint32_t new_val;
356 NRFX_ATOMIC_OP(sub_hs, old_val, new_val, p_data, value);
357 (void) old_val;
358 return new_val;
359 #else
360 NRFX_CRITICAL_SECTION_ENTER();
361 *p_data -= value;
362 uint32_t new_value = *p_data;
363 NRFX_CRITICAL_SECTION_EXIT();
364 return new_value;
365 #endif //NRFX_ATOMIC_USE_BUILT_IN
366 }
367
nrfx_atomic_flag_set_fetch(nrfx_atomic_flag_t * p_data)368 uint32_t nrfx_atomic_flag_set_fetch(nrfx_atomic_flag_t * p_data)
369 {
370 return nrfx_atomic_u32_fetch_or(p_data, 1);
371 }
372
nrfx_atomic_flag_set(nrfx_atomic_flag_t * p_data)373 uint32_t nrfx_atomic_flag_set(nrfx_atomic_flag_t * p_data)
374 {
375 return nrfx_atomic_u32_or(p_data, 1);
376 }
377
nrfx_atomic_flag_clear_fetch(nrfx_atomic_flag_t * p_data)378 uint32_t nrfx_atomic_flag_clear_fetch(nrfx_atomic_flag_t * p_data)
379 {
380 return nrfx_atomic_u32_fetch_and(p_data, 0);
381 }
382
nrfx_atomic_flag_clear(nrfx_atomic_flag_t * p_data)383 uint32_t nrfx_atomic_flag_clear(nrfx_atomic_flag_t * p_data)
384 {
385 return nrfx_atomic_u32_and(p_data, 0);
386 }
387