Loading...
Searching...
No Matches
sync.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef _HARDWARE_SYNC_H
8#define _HARDWARE_SYNC_H
9
10#include "pico.h"
12
13#ifdef __riscv
14#include "hardware/hazard3.h"
15#endif
16
17#ifdef __cplusplus
18extern "C" {
19#endif
20
61
62// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_HARDWARE_SYNC, Enable/disable assertions in the hardware_sync module, type=bool, default=0, group=hardware_sync
63#ifndef PARAM_ASSERTIONS_ENABLED_HARDWARE_SYNC
64#ifdef PARAM_ASSERTIONS_ENABLED_SYNC // backwards compatibility with SDK < 2.0.0
65#define PARAM_ASSERTIONS_ENABLED_HARDWARE_SYNC PARAM_ASSERTIONS_ENABLED_SYNC
66#else
67#define PARAM_ASSERTIONS_ENABLED_HARDWARE_SYNC 0
68#endif
69#endif
70
77__force_inline static void __nop(void) {
78#if !__ARM_ARCH_6M__
79#ifdef __riscv
80 __asm volatile ("nop");
81#else
82 __asm volatile ("nop.w");
83#endif
84#else
85 __asm volatile ("nop");
86#endif
87}
88
89
95#if !__has_builtin(__sev)
96__force_inline static void __sev(void) {
97#ifdef __riscv
98 __hazard3_unblock();
99#else
100 pico_default_asm_volatile ("sev");
101#endif
102}
103#else
104// Forward declare so we don't have to #include <arm_acle.h>.
105void __sev(void);
106#endif
107
114#if !__has_builtin(__wfe)
115__force_inline static void __wfe(void) {
116#ifdef __riscv
117 __hazard3_block();
118#else
119 pico_default_asm_volatile ("wfe");
120#endif
121}
122#else
123// Forward declare so we don't have to #include <arm_acle.h>.
124void __wfe(void);
125#endif
126
132#if !__has_builtin(__wfi)
133__force_inline static void __wfi(void) {
134 pico_default_asm_volatile("wfi");
135}
136#else
137// Forward declare so we don't have to #include <arm_acle.h>.
138void __wfi(void);
139#endif
140
147__force_inline static void __dmb(void) {
148#ifdef __riscv
149 __asm volatile ("fence rw, rw" : : : "memory");
150#else
151 pico_default_asm_volatile ("dmb" : : : "memory");
152#endif
153}
154
162__force_inline static void __dsb(void) {
163#ifdef __riscv
164 __asm volatile ("fence rw, rw" : : : "memory");
165#else
166 pico_default_asm_volatile ("dsb" : : : "memory");
167#endif
168}
169
177__force_inline static void __isb(void) {
178#ifdef __riscv
179 __asm volatile ("fence.i" : : : "memory");
180#else
181 pico_default_asm_volatile("isb" ::: "memory");
182#endif
183}
184
189 // the original code below makes it hard for us to be included from C++ via a header
190 // which itself is in an extern "C", so just use __dmb instead, which is what
191 // is required on Cortex M0+
192 __dmb();
193//#ifndef __cplusplus
194// atomic_thread_fence(memory_order_acquire);
195//#else
196// std::atomic_thread_fence(std::memory_order_acquire);
197//#endif
198}
199
205 // the original code below makes it hard for us to be included from C++ via a header
206 // which itself is in an extern "C", so just use __dmb instead, which is what
207 // is required on Cortex M0+
208 __dmb();
209//#ifndef __cplusplus
210// atomic_thread_fence(memory_order_release);
211//#else
212// std::atomic_thread_fence(std::memory_order_release);
213//#endif
214}
215
220#ifdef __riscv
222 riscv_clear_csr(mstatus, 8);
224#else
225 pico_default_asm_volatile ( "cpsid i" : : : "memory");
226#endif
227}
228
233#ifdef __riscv
235 riscv_set_csr(mstatus, 8);
237#else
238 pico_default_asm_volatile ( "cpsie i" : : : "memory");
239#endif
240}
241
253 uint32_t status;
254#ifdef __riscv
255 pico_default_asm_volatile (
256 "csrrci %0, mstatus, 0x8\n"
257 : "=r" (status) :: "memory"
258 );
259#else
260 pico_default_asm_volatile (
261 "mrs %0, PRIMASK\n"
262 "cpsid i"
263 : "=r" (status) :: "memory");
264#endif
265 return status;
266}
267
273__force_inline static void restore_interrupts(uint32_t status) {
274#ifdef __riscv
276 if (status & 0x8) {
277 riscv_set_csr(mstatus, 8);
278 } else {
279 riscv_clear_csr(mstatus, 8);
280 }
282#else
283 pico_default_asm_volatile ("msr PRIMASK,%0"::"r" (status) : "memory" );
284#endif
285}
286
296#ifdef __riscv
297 // on RISC-V this can enable interrupts, but not disable interrupts... which
298 // is the common case and doesn't require a branch
300 riscv_set_csr(mstatus, status & 8);
302#else
303 // on ARM, this behaves the same as restore_interrupts()
304 pico_default_asm_volatile ("msr PRIMASK,%0"::"r" (status) : "memory" );
305#endif
306}
307
308#include "hardware/sync/spin_lock.h"
309
326
336void spin_lock_claim(uint lock_num);
337
347void spin_lock_claim_mask(uint32_t lock_num_mask);
348
356void spin_lock_unclaim(uint lock_num);
357
364int spin_lock_claim_unused(bool required);
365
374bool spin_lock_is_claimed(uint lock_num);
375
376// no longer use __mem_fence_acquire here, as it is overkill on cortex M0+
377#if PICO_C_COMPILER_IS_GNU
378#define remove_volatile_cast(t, x) (t)(x)
379#define remove_volatile_cast_no_barrier(t, x) (t)(x)
380#else
381#define remove_volatile_cast(t, x) (__compiler_memory_barrier(), Clang_Pragma("clang diagnostic push") Clang_Pragma("clang diagnostic ignored \"-Wcast-qual\"") (t)(x) Clang_Pragma("clang diagnostic pop"))
382#define remove_volatile_cast_no_barrier(t, x) Clang_Pragma("clang diagnostic push") Clang_Pragma("clang diagnostic ignored \"-Wcast-qual\"") (t)(x) Clang_Pragma("clang diagnostic pop")
383#endif
384
385#ifdef __cplusplus
386}
387#endif
388
389#endif
static __force_inline void disable_interrupts(void)
Explicitly disable interrupts on the calling core.
Definition sync.h:219
int spin_lock_claim_unused(bool required)
Claim a free spin lock.
Definition sync.c:43
static __force_inline uint32_t save_and_disable_interrupts(void)
Disable interrupts on the calling core, returning the previous interrupt state.
Definition sync.h:252
void spin_lock_unclaim(uint lock_num)
Mark a spin lock as no longer used.
Definition sync.c:37
static __force_inline void __mem_fence_release(void)
Release a memory fence.
Definition sync.h:204
void spin_lock_claim_mask(uint32_t lock_num_mask)
Mark multiple spin locks as used.
Definition sync.c:31
static __force_inline void __sev(void)
Insert a SEV instruction in to the code path.
Definition sync.h:96
static __force_inline void restore_interrupts_from_disabled(uint32_t status)
Restore interrupts to a specified state on the calling core with restricted transitions.
Definition sync.h:295
void spin_lock_claim(uint lock_num)
Mark a spin lock as used.
Definition sync.c:26
static __force_inline void __dmb(void)
Insert a DMB instruction in to the code path.
Definition sync.h:147
static __force_inline void enable_interrupts(void)
Explicitly enable interrupts on the calling core.
Definition sync.h:232
static __force_inline void __wfe(void)
Insert a WFE instruction in to the code path.
Definition sync.h:115
static __force_inline void restore_interrupts(uint32_t status)
Restore interrupts to a specified state on the calling core.
Definition sync.h:273
uint next_striped_spin_lock_num(void)
Return a spin lock number from the striped range.
Definition sync.c:18
static __force_inline void __nop(void)
Insert a NOP instruction in to the code path.
Definition sync.h:77
bool spin_lock_is_claimed(uint lock_num)
Determine if a spin lock is claimed.
Definition sync.c:47
static __force_inline void __mem_fence_acquire(void)
Acquire a memory fence.
Definition sync.h:188
static __force_inline void __wfi(void)
Insert a WFI instruction in to the code path.
Definition sync.h:133
static __force_inline void __isb(void)
Insert a ISB instruction in to the code path.
Definition sync.h:177
static __force_inline void __dsb(void)
Insert a DSB instruction in to the code path.
Definition sync.h:162
#define __force_inline
Attribute to force inlining of a function regardless of optimization level.
Definition compiler.h:128
static __always_inline void __compiler_memory_barrier(void)
Ensure that the compiler does not move memory access across this method call.
Definition compiler.h:176