1 /* 2 * Copyright (c) 2018, 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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