v2.0.0
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"
11#include "hardware/address_mapped.h"
12
13#ifdef __riscv
14#include "hardware/hazard3.h"
15#endif
16
17#ifdef __cplusplus
18extern "C" {
19#endif
20
56// PICO_CONFIG: PARAM_ASSERTIONS_ENABLED_HARDWARE_SYNC, Enable/disable assertions in the hardware_sync module, type=bool, default=0, group=hardware_sync
57#ifndef PARAM_ASSERTIONS_ENABLED_HARDWARE_SYNC
58#ifdef PARAM_ASSERTIONS_ENABLED_SYNC // backwards compatibility with SDK < 2.0.0
59#define PARAM_ASSERTIONS_ENABLED_HARDWARE_SYNC PARAM_ASSERTIONS_ENABLED_SYNC
60#else
61#define PARAM_ASSERTIONS_ENABLED_HARDWARE_SYNC 0
62#endif
63#endif
64
71__force_inline static void __nop(void) {
72#if !__ARM_ARCH_6M__
73#ifdef __riscv
74 __asm volatile ("nop");
75#else
76 __asm volatile ("nop.w");
77#endif
78#else
79 __asm volatile ("nop");
80#endif
81}
82
83
89#if !__has_builtin(__sev)
90__force_inline static void __sev(void) {
91#ifdef __riscv
92 __hazard3_unblock();
93#else
94 pico_default_asm_volatile ("sev");
95#endif
96}
97#endif
98
105#if !__has_builtin(__wfe)
106__force_inline static void __wfe(void) {
107#ifdef __riscv
108 __hazard3_block();
109#else
110 pico_default_asm_volatile ("wfe");
111#endif
112}
113#endif
114
120#if !__has_builtin(__wfi)
121__force_inline static void __wfi(void) {
122 pico_default_asm_volatile("wfi");
123}
124#endif
125
132__force_inline static void __dmb(void) {
133#ifdef __riscv
134 __asm volatile ("fence rw, rw" : : : "memory");
135#else
136 pico_default_asm_volatile ("dmb" : : : "memory");
137#endif
138}
139
147__force_inline static void __dsb(void) {
148#ifdef __riscv
149 __asm volatile ("fence rw, rw" : : : "memory");
150#else
151 pico_default_asm_volatile ("dsb" : : : "memory");
152#endif
153}
154
162__force_inline static void __isb(void) {
163#ifdef __riscv
164 __asm volatile ("fence.i" : : : "memory");
165#else
166 pico_default_asm_volatile("isb" ::: "memory");
167#endif
168}
169
173__force_inline static void __mem_fence_acquire(void) {
174 // the original code below makes it hard for us to be included from C++ via a header
175 // which itself is in an extern "C", so just use __dmb instead, which is what
176 // is required on Cortex M0+
177 __dmb();
178//#ifndef __cplusplus
179// atomic_thread_fence(memory_order_acquire);
180//#else
181// std::atomic_thread_fence(std::memory_order_acquire);
182//#endif
183}
184
189__force_inline static void __mem_fence_release(void) {
190 // the original code below makes it hard for us to be included from C++ via a header
191 // which itself is in an extern "C", so just use __dmb instead, which is what
192 // is required on Cortex M0+
193 __dmb();
194//#ifndef __cplusplus
195// atomic_thread_fence(memory_order_release);
196//#else
197// std::atomic_thread_fence(std::memory_order_release);
198//#endif
199}
200
206__force_inline static uint32_t save_and_disable_interrupts(void) {
207 uint32_t status;
208#ifdef __riscv
209 pico_default_asm_volatile (
210 "csrrci %0, mstatus, 0x8\n"
211 : "=r" (status) :: "memory"
212 );
213#else
214 pico_default_asm_volatile (
215 "mrs %0, PRIMASK\n"
216 "cpsid i"
217 : "=r" (status) :: "memory");
218#endif
219 return status;
220}
221
227__force_inline static void restore_interrupts(uint32_t status) {
228#ifdef __riscv
229 __compiler_memory_barrier();
230 if (status & 0x8) {
231 riscv_set_csr(mstatus, 8);
232 } else {
233 riscv_clear_csr(mstatus, 8);
234 }
235 __compiler_memory_barrier();
236#else
237 pico_default_asm_volatile ("msr PRIMASK,%0"::"r" (status) : "memory" );
238#endif
239}
240
249__force_inline static void restore_interrupts_from_disabled(uint32_t status) {
250#ifdef __riscv
251 // on RISC-V this can enable interrupts, but not disable interrupts... which
252 // is the common case and doesn't require a branch
253 __compiler_memory_barrier();
254 riscv_set_csr(mstatus, status & 8);
255 __compiler_memory_barrier();
256#else
257 // on ARM, this behaves the same as restore_interrupts()
258 pico_default_asm_volatile ("msr PRIMASK,%0"::"r" (status) : "memory" );
259#endif
260}
261
262#include "hardware/sync/spin_lock.h"
263
279uint next_striped_spin_lock_num(void);
280
290void spin_lock_claim(uint lock_num);
291
301void spin_lock_claim_mask(uint32_t lock_num_mask);
302
310void spin_lock_unclaim(uint lock_num);
311
318int spin_lock_claim_unused(bool required);
319
328bool spin_lock_is_claimed(uint lock_num);
329
330// no longer use __mem_fence_acquire here, as it is overkill on cortex M0+
331#if PICO_C_COMPILER_IS_GNU
332#define remove_volatile_cast(t, x) (t)(x)
333#define remove_volatile_cast_no_barrier(t, x) (t)(x)
334#else
335#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"); })
336#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"); })
337#endif
338
339#ifdef __cplusplus
340}
341#endif
342
343#endif
address_mapped.h
spin_lock_claim_unused
int spin_lock_claim_unused(bool required)
Claim a free spin lock.
Definition: sync.c:43
save_and_disable_interrupts
static __force_inline uint32_t save_and_disable_interrupts(void)
Save and disable interrupts.
Definition: sync.h:206
spin_lock_unclaim
void spin_lock_unclaim(uint lock_num)
Mark a spin lock as no longer used.
Definition: sync.c:37
__mem_fence_release
static __force_inline void __mem_fence_release(void)
Release a memory fence.
Definition: sync.h:189
spin_lock_claim_mask
void spin_lock_claim_mask(uint32_t lock_num_mask)
Mark multiple spin locks as used.
Definition: sync.c:31
__sev
static __force_inline void __sev(void)
Insert a SEV instruction in to the code path.
Definition: sync.h:90
restore_interrupts_from_disabled
static __force_inline void restore_interrupts_from_disabled(uint32_t status)
Restore interrupts to a specified state with restricted transitions.
Definition: sync.h:249
spin_lock_claim
void spin_lock_claim(uint lock_num)
Mark a spin lock as used.
Definition: sync.c:26
__dmb
static __force_inline void __dmb(void)
Insert a DMB instruction in to the code path.
Definition: sync.h:132
__wfe
static __force_inline void __wfe(void)
Insert a WFE instruction in to the code path.
Definition: sync.h:106
restore_interrupts
static __force_inline void restore_interrupts(uint32_t status)
Restore interrupts to a specified state.
Definition: sync.h:227
next_striped_spin_lock_num
uint next_striped_spin_lock_num(void)
Return a spin lock number from the striped range.
Definition: sync.c:18
__nop
static __force_inline void __nop(void)
Insert a NOP instruction in to the code path.
Definition: sync.h:71
spin_lock_is_claimed
bool spin_lock_is_claimed(uint lock_num)
Determine if a spin lock is claimed.
Definition: sync.c:47
__mem_fence_acquire
static __force_inline void __mem_fence_acquire(void)
Acquire a memory fence.
Definition: sync.h:173
__wfi
static __force_inline void __wfi(void)
Insert a WFI instruction in to the code path.
Definition: sync.h:121
__isb
static __force_inline void __isb(void)
Insert a ISB instruction in to the code path.
Definition: sync.h:162
__dsb
static __force_inline void __dsb(void)
Insert a DSB instruction in to the code path.
Definition: sync.h:147
__force_inline
#define __force_inline
Attribute to force inlining of a function regardless of optimization level.
Definition: compiler.h:125
__compiler_memory_barrier
static __always_inline void __compiler_memory_barrier(void)
Ensure that the compiler does not move memory access across this method call.
Definition: compiler.h:171
hazard3.h
pico.h