|
16 | 16 |
|
17 | 17 | namespace modm::platform::multicore
|
18 | 18 | {
|
19 |
| - /** |
20 |
| - * The RP2040 contains two FIFOs for passing data, messages or ordered events between the two cores. Each FIFO is 32 bits |
21 |
| - * wide, and 8 entries deep. One of the FIFOs can only be written by core 0, and read by core 1. The other can only be written |
22 |
| - * by core 1, and read by core 0. |
23 |
| - * @ingroup modm_platform_multicore |
24 |
| - */ |
25 |
| - struct Mailbox |
26 |
| - { |
27 |
| - static inline bool canRead() |
28 |
| - { |
29 |
| - return sio_hw->fifo_st & SIO_FIFO_ST_VLD_BITS; |
30 |
| - } |
31 |
| - static inline bool canWrite() |
32 |
| - { |
33 |
| - return sio_hw->fifo_st & SIO_FIFO_ST_RDY_BITS; |
34 |
| - } |
35 |
| - static inline bool push(uint32_t msg) |
36 |
| - { |
37 |
| - if (!canWrite()) return false; |
38 |
| - sio_hw->fifo_wr = msg; |
39 |
| - __SEV(); |
40 |
| - return true; |
41 |
| - } |
42 |
| - static inline bool pop(uint32_t& msg) |
43 |
| - { |
44 |
| - if (!canRead()) return false; |
45 |
| - msg = sio_hw->fifo_rd; |
46 |
| - return true; |
47 |
| - } |
48 |
| - static inline void pushBlocked(uint32_t msg) |
49 |
| - { |
50 |
| - while (!canWrite()) __NOP(); |
51 |
| - sio_hw->fifo_wr = msg; |
52 |
| - __SEV(); |
53 |
| - } |
54 |
| - static inline uint32_t popBlocked() |
55 |
| - { |
56 |
| - while (!canRead()) __WFE(); |
57 |
| - return sio_hw->fifo_rd; |
58 |
| - } |
59 |
| - static inline void drain() |
60 |
| - { |
61 |
| - while (canRead()) |
62 |
| - (void) sio_hw->fifo_rd; |
63 |
| - } |
64 |
| - }; |
65 |
| - |
66 |
| - /** |
67 |
| - * The RP2040 provides 32 hardware spin locks, which can be used to manage mutually-exclusive access to shared software |
68 |
| - * and hardware resources. |
69 |
| - * |
70 |
| - * Instance 0 allocated for modm usage. |
71 |
| - * |
72 |
| - * Acquire a spin lock without disabling interrupts (hence unsafe) |
73 |
| - * @ingroup modm_platform_multicore |
74 |
| - */ |
75 |
| - template <uint8_t instance> |
76 |
| - class SpinLockUnsafe |
77 |
| - { |
78 |
| - static_assert(instance < 32); |
79 |
| - using LockType = volatile uint32_t; |
80 |
| - |
81 |
| - private: |
82 |
| - static inline LockType* getInstance() |
83 |
| - { |
84 |
| - return (LockType *) (SIO_BASE + SIO_SPINLOCK0_OFFSET + instance * 4); |
85 |
| - } |
86 | 19 |
|
87 |
| - public: |
88 |
| - static void init() |
89 |
| - { |
90 |
| - unlock(); |
91 |
| - } |
92 |
| - static inline void lock() |
93 |
| - { |
94 |
| - auto l = getInstance(); |
95 |
| - while (*l == 0); |
96 |
| - std::atomic_thread_fence(std::memory_order_acquire); |
97 |
| - } |
98 |
| - static inline void unlock() |
99 |
| - { |
100 |
| - auto l = getInstance(); |
101 |
| - std::atomic_thread_fence(std::memory_order_release); |
102 |
| - *l = 0; |
103 |
| - } |
104 |
| - }; |
| 20 | +/** |
| 21 | + * The RP2040 contains two FIFOs for passing data, messages or ordered events between the two cores. Each FIFO is 32 bits |
| 22 | + * wide, and 8 entries deep. One of the FIFOs can only be written by core 0, and read by core 1. The other can only be written |
| 23 | + * by core 1, and read by core 0. |
| 24 | + * @ingroup modm_platform_multicore |
| 25 | + */ |
| 26 | +struct Mailbox |
| 27 | +{ |
| 28 | + static inline bool canRead() |
| 29 | + { |
| 30 | + return sio_hw->fifo_st & SIO_FIFO_ST_VLD_BITS; |
| 31 | + } |
| 32 | + static inline bool canWrite() |
| 33 | + { |
| 34 | + return sio_hw->fifo_st & SIO_FIFO_ST_RDY_BITS; |
| 35 | + } |
| 36 | + static inline bool push(uint32_t msg) |
| 37 | + { |
| 38 | + if (!canWrite()) return false; |
| 39 | + sio_hw->fifo_wr = msg; |
| 40 | + __SEV(); |
| 41 | + return true; |
| 42 | + } |
| 43 | + static inline bool pop(uint32_t& msg) |
| 44 | + { |
| 45 | + if (!canRead()) return false; |
| 46 | + msg = sio_hw->fifo_rd; |
| 47 | + return true; |
| 48 | + } |
| 49 | + static inline void pushBlocked(uint32_t msg) |
| 50 | + { |
| 51 | + while (!canWrite()) __NOP(); |
| 52 | + sio_hw->fifo_wr = msg; |
| 53 | + __SEV(); |
| 54 | + } |
| 55 | + static inline uint32_t popBlocked() |
| 56 | + { |
| 57 | + while (!canRead()) __WFE(); |
| 58 | + return sio_hw->fifo_rd; |
| 59 | + } |
| 60 | + static inline void drain() |
| 61 | + { |
| 62 | + while (canRead()) |
| 63 | + (void) sio_hw->fifo_rd; |
| 64 | + } |
| 65 | +}; |
| 66 | + |
| 67 | +/** |
| 68 | + * The RP2040 provides 32 hardware spin locks, which can be used to manage mutually-exclusive access to shared software |
| 69 | + * and hardware resources. |
| 70 | + * |
| 71 | + * Instance 0 allocated for modm usage. |
| 72 | + * |
| 73 | + * Acquire a spin lock without disabling interrupts (hence unsafe) |
| 74 | + * @ingroup modm_platform_multicore |
| 75 | + */ |
| 76 | +template <uint8_t instance> |
| 77 | +class SpinLockUnsafe |
| 78 | +{ |
| 79 | + static_assert(instance < 32); |
| 80 | + using LockType = volatile uint32_t; |
| 81 | + |
| 82 | +private: |
| 83 | + static inline LockType* getInstance() |
| 84 | + { |
| 85 | + return (LockType *) (SIO_BASE + SIO_SPINLOCK0_OFFSET + instance * 4); |
| 86 | + } |
105 | 87 |
|
106 |
| - /// @cond |
107 |
| - // for use in modm::atomic::Lock |
108 |
| - struct CoreLock |
| 88 | +public: |
| 89 | + static void init() |
| 90 | + { |
| 91 | + unlock(); |
| 92 | + } |
| 93 | + static inline void lock() |
| 94 | + { |
| 95 | + auto l = getInstance(); |
| 96 | + while (*l == 0); |
| 97 | + std::atomic_thread_fence(std::memory_order_acquire); |
| 98 | + } |
| 99 | + static inline void unlock() |
109 | 100 | {
|
110 |
| - CoreLock() { SpinLockUnsafe<0>::lock(); } |
111 |
| - ~CoreLock() { SpinLockUnsafe<0>::unlock(); } |
112 |
| - }; |
113 |
| - /// @endcond |
| 101 | + auto l = getInstance(); |
| 102 | + std::atomic_thread_fence(std::memory_order_release); |
| 103 | + *l = 0; |
| 104 | + } |
| 105 | +}; |
| 106 | + |
| 107 | +/// @cond |
| 108 | +// for use in modm::atomic::Lock |
| 109 | +struct CoreLock |
| 110 | +{ |
| 111 | + CoreLock() { SpinLockUnsafe<0>::lock(); } |
| 112 | + ~CoreLock() { SpinLockUnsafe<0>::unlock(); } |
| 113 | +}; |
| 114 | +/// @endcond |
114 | 115 |
|
115 |
| - /// This class will disable interrupts prior to acquiring the spinlock |
116 |
| - /// @ingroup modm_platform_multicore |
117 |
| - template <uint8_t instance> |
118 |
| - class SpinLockBlocking : public SpinLockUnsafe<instance> |
| 116 | +/// This class will disable interrupts prior to acquiring the spinlock |
| 117 | +/// @ingroup modm_platform_multicore |
| 118 | +template <uint8_t instance> |
| 119 | +class SpinLockBlocking : public SpinLockUnsafe<instance> |
| 120 | +{ |
| 121 | + using Base = SpinLockUnsafe<instance>; |
| 122 | + |
| 123 | +public: |
| 124 | + static inline uint32_t lock() |
119 | 125 | {
|
120 |
| - using Base = SpinLockUnsafe<instance>; |
| 126 | + uint32_t is = __get_PRIMASK(); |
| 127 | + __disable_irq(); |
| 128 | + Base::lock(); |
| 129 | + return is; |
| 130 | + } |
| 131 | + static inline void unlock(uint32_t is) |
| 132 | + { |
| 133 | + Base::unlock(); |
| 134 | + __set_PRIMASK(is); |
| 135 | + } |
| 136 | +}; |
| 137 | +/// @ingroup modm_platform_multicore |
| 138 | +using SystemSpinLock = SpinLockBlocking<0>; |
121 | 139 |
|
122 |
| - public: |
123 |
| - static inline uint32_t lock() |
124 |
| - { |
125 |
| - uint32_t is = __get_PRIMASK(); |
126 |
| - __disable_irq(); |
127 |
| - Base::lock(); |
128 |
| - return is; |
129 |
| - } |
130 |
| - static inline void unlock(uint32_t is) |
131 |
| - { |
132 |
| - Base::unlock(); |
133 |
| - __set_PRIMASK(is); |
134 |
| - } |
135 |
| - }; |
136 |
| - /// @ingroup modm_platform_multicore |
137 |
| - using SystemSpinLock = SpinLockBlocking<0>; |
138 |
| - |
139 |
| - |
140 |
| - /// RAI lock acquiring and releasing |
141 |
| - /// @ingroup modm_platform_multicore |
142 |
| - template <class SpinLock> |
143 |
| - class SpinLockGuard |
144 |
| - { |
145 |
| - private: |
146 |
| - SpinLockGuard(const SpinLockGuard& ) = delete; |
147 |
| - SpinLockGuard(SpinLockGuard&&) = delete; |
148 |
| - public: |
149 |
| - inline SpinLockGuard() { SpinLock::lock(); } |
150 |
| - inline ~SpinLockGuard() { SpinLock::unlock(); } |
151 |
| - }; |
152 |
| - |
153 |
| - /// @ingroup modm_platform_multicore |
154 |
| - template <uint8_t instance> |
155 |
| - class SpinLockGuard<SpinLockBlocking<instance>> |
156 |
| - { |
157 |
| - private: |
158 |
| - using SpinLock = SpinLockBlocking<instance>; |
159 |
| - uint32_t is; |
160 |
| - SpinLockGuard(const SpinLockGuard& ) = delete; |
161 |
| - SpinLockGuard(SpinLockGuard&&) = delete; |
162 |
| - public: |
163 |
| - inline SpinLockGuard() : is(SpinLock::lock()) {} |
164 |
| - inline ~SpinLockGuard() { SpinLock::unlock(is); } |
165 |
| - }; |
166 |
| - /// @ingroup modm_platform_multicore |
167 |
| - using SystemSpinLockGuard = SpinLockGuard<SystemSpinLock>; |
168 |
| - |
169 |
| - /// @ingroup modm_platform_multicore |
170 |
| - class Mutex |
171 |
| - { |
172 |
| - private: |
173 |
| - volatile bool locked = false; |
174 |
| - Mutex(const Mutex& ) = delete; |
175 |
| - Mutex(Mutex&&) = delete; |
176 |
| - public: |
177 |
| - Mutex() {} |
178 |
| - void lock() |
| 140 | + |
| 141 | +/// RAI lock acquiring and releasing |
| 142 | +/// @ingroup modm_platform_multicore |
| 143 | +template <class SpinLock> |
| 144 | +class SpinLockGuard |
| 145 | +{ |
| 146 | +private: |
| 147 | + SpinLockGuard(const SpinLockGuard& ) = delete; |
| 148 | + SpinLockGuard(SpinLockGuard&&) = delete; |
| 149 | +public: |
| 150 | + inline SpinLockGuard() { SpinLock::lock(); } |
| 151 | + inline ~SpinLockGuard() { SpinLock::unlock(); } |
| 152 | +}; |
| 153 | + |
| 154 | +/// @ingroup modm_platform_multicore |
| 155 | +template <uint8_t instance> |
| 156 | +class SpinLockGuard<SpinLockBlocking<instance>> |
| 157 | +{ |
| 158 | +private: |
| 159 | + using SpinLock = SpinLockBlocking<instance>; |
| 160 | + uint32_t is; |
| 161 | + SpinLockGuard(const SpinLockGuard& ) = delete; |
| 162 | + SpinLockGuard(SpinLockGuard&&) = delete; |
| 163 | +public: |
| 164 | + inline SpinLockGuard() : is(SpinLock::lock()) {} |
| 165 | + inline ~SpinLockGuard() { SpinLock::unlock(is); } |
| 166 | +}; |
| 167 | +/// @ingroup modm_platform_multicore |
| 168 | +using SystemSpinLockGuard = SpinLockGuard<SystemSpinLock>; |
| 169 | + |
| 170 | +/// @ingroup modm_platform_multicore |
| 171 | +class Mutex |
| 172 | +{ |
| 173 | +private: |
| 174 | + volatile bool locked = false; |
| 175 | + Mutex(const Mutex& ) = delete; |
| 176 | + Mutex(Mutex&&) = delete; |
| 177 | +public: |
| 178 | + Mutex() {} |
| 179 | + void lock() |
| 180 | + { |
| 181 | + while(true) |
179 | 182 | {
|
180 |
| - while(true) |
181 | 183 | {
|
182 |
| - { |
183 |
| - SystemSpinLockGuard g; |
184 |
| - if (!locked) { |
185 |
| - locked = true; |
186 |
| - return; |
187 |
| - } |
| 184 | + SystemSpinLockGuard g; |
| 185 | + if (!locked) { |
| 186 | + locked = true; |
| 187 | + return; |
188 | 188 | }
|
189 |
| - __WFE(); |
190 | 189 | }
|
| 190 | + __WFE(); |
191 | 191 | }
|
192 |
| - void unlock() |
| 192 | + } |
| 193 | + void unlock() |
| 194 | + { |
193 | 195 | {
|
194 |
| - { |
195 |
| - SystemSpinLockGuard g; |
196 |
| - locked = false; |
197 |
| - } |
198 |
| - __SEV(); |
| 196 | + SystemSpinLockGuard g; |
| 197 | + locked = false; |
199 | 198 | }
|
200 |
| - }; |
| 199 | + __SEV(); |
| 200 | + } |
| 201 | +}; |
201 | 202 |
|
202 |
| - /// @ingroup modm_platform_multicore |
203 |
| - struct Core |
| 203 | +/// @ingroup modm_platform_multicore |
| 204 | +struct Core |
| 205 | +{ |
| 206 | + static inline uint32_t cpuId() |
204 | 207 | {
|
205 |
| - static inline uint32_t cpuId() |
206 |
| - { |
207 |
| - return sio_hw->cpuid; |
208 |
| - } |
209 |
| - }; |
210 |
| - /// Wake up (a previously reset) core 1 and enter the given function on |
211 |
| - /// core 1 using the default core 1 stack (below core 0 stack). |
212 |
| - /// @ingroup modm_platform_multicore |
213 |
| - struct Core1 : Core |
214 |
| - { |
215 |
| - static void run(void(*func)()); |
216 |
| - }; |
217 |
| -} |
| 208 | + return sio_hw->cpuid; |
| 209 | + } |
| 210 | +}; |
| 211 | +/// Wake up (a previously reset) core 1 and enter the given function on |
| 212 | +/// core 1 using the default core 1 stack (below core 0 stack). |
| 213 | +/// @ingroup modm_platform_multicore |
| 214 | +struct Core1 : Core |
| 215 | +{ |
| 216 | + static void run(void(*func)()); |
| 217 | +}; |
| 218 | + |
| 219 | +} // namespace modm::platform::multicore |
218 | 220 |
|
219 | 221 | /// @ingroup modm_platform_multicore
|
220 | 222 | /// @{
|
|
0 commit comments