1
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
24
25
26
27
28
29
30
31
32
33
34
37
38
39
40
41
45
46
47
48
49
50
51
52
53
56
57
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
141
142
144
145
146
147
148
149
151
152
153
154
155
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
219
220
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
250
251
252
255
256
259
262
263
264
265
266
267
268
269
272
273
274
275
276
277
278
279
282
283
286
287
288
289
292
293
294
297
298
299
300
301
304
305
308
309
312
313
314
315
316
317
320
321
324
325
328
329
348
349
355
356
357
358
359
365
368
369
370
371
372
383
384
385
/* ... */
#include "pico/multicore.h"
#include "hardware/sync.h"
#include "hardware/irq.h"
#include "pico/runtime_init.h"
#ifdef __riscv
#include "hardware/riscv.h"
#else
#include "hardware/structs/scb.h"
#endif
#include "hardware/structs/sio.h"
#include "hardware/regs/psm.h"
#include "hardware/claim.h"
#if !PICO_RP2040
#ifndef __riscv
#include "hardware/structs/m33.h"
#endif/* ... */
#endif
static bool lockout_victim_initialized[NUM_CORES];
void multicore_fifo_push_blocking(uint32_t data) {
multicore_fifo_push_blocking_inline(data);
}{ ... }
bool multicore_fifo_push_timeout_us(uint32_t data, uint64_t timeout_us) {
absolute_time_t end_time = make_timeout_time_us(timeout_us);
while (!multicore_fifo_wready()) {
tight_loop_contents();
if (time_reached(end_time)) return false;
}while (!multicore_fifo_wready()) { ... }
sio_hw->fifo_wr = data;
__sev();
return true;
}{ ... }
uint32_t multicore_fifo_pop_blocking(void) {
return multicore_fifo_pop_blocking_inline();
}{ ... }
bool multicore_fifo_pop_timeout_us(uint64_t timeout_us, uint32_t *out) {
absolute_time_t end_time = make_timeout_time_us(timeout_us);
while (!multicore_fifo_rvalid()) {
if (best_effort_wfe_or_timeout(end_time)) return false;
}while (!multicore_fifo_rvalid()) { ... }
*out = sio_hw->fifo_rd;
return true;
}{ ... }
static uint32_t __attribute__((section(".stack1"))) core1_stack[PICO_CORE1_STACK_SIZE / sizeof(uint32_t)];
static void __attribute__ ((naked)) core1_trampoline(void) {
#ifdef __riscv
pico_default_asm(
"lw a0, 0(sp)\n"
"lw a1, 4(sp)\n"
"lw a2, 8(sp)\n"
"lw gp, 12(sp)\n"
"addi sp, sp, 16\n"
"jr a2\n"
);/* ... */
#else
pico_default_asm("pop {r0, r1, pc}");
#endif
}{ ... }
int core1_wrapper(int (*entry)(void), void *stack_base) {
#if !PICO_RUNTIME_SKIP_INIT_PER_CORE_INSTALL_STACK_GUARD
runtime_init_per_core_install_stack_guard(stack_base);/* ... */
#else
(void)stack_base;
#endif
runtime_run_per_core_initializers();
return (*entry)();
}{ ... }
void multicore_reset_core1(void) {
io_rw_32 *power_off = (io_rw_32 *) (PSM_BASE + PSM_FRCE_OFF_OFFSET);
io_rw_32 *power_off_set = hw_set_alias(power_off);
io_rw_32 *power_off_clr = hw_clear_alias(power_off);
*power_off_set = PSM_FRCE_OFF_PROC1_BITS;
while (!(*power_off & PSM_FRCE_OFF_PROC1_BITS)) tight_loop_contents();
uint irq_num = SIO_FIFO_IRQ_NUM(0);
bool enabled = irq_is_enabled(irq_num);
irq_set_enabled(irq_num, false);
*power_off_clr = PSM_FRCE_OFF_PROC1_BITS;
uint32_t value = multicore_fifo_pop_blocking();
assert(value == 0);
(void) value;
irq_set_enabled(irq_num, enabled);
}{ ... }
void multicore_launch_core1_with_stack(void (*entry)(void), uint32_t *stack_bottom, size_t stack_size_bytes) {
assert(!(stack_size_bytes & 3u));
uint32_t *stack_ptr = stack_bottom + stack_size_bytes / sizeof(uint32_t);
#ifdef __riscv
stack_ptr -= 4;
uint32_t vector_table = riscv_read_csr(mtvec);
asm volatile ("mv %0, gp" : "=r"(stack_ptr[3]));/* ... */
#else
stack_ptr -= 3;
uint32_t vector_table = scb_hw->vtor;/* ... */
#endif
stack_ptr[0] = (uintptr_t) entry;
stack_ptr[1] = (uintptr_t) stack_bottom;
stack_ptr[2] = (uintptr_t) core1_wrapper;
#if PICO_VTABLE_PER_CORE
#warning PICO_VTABLE_PER_CORE==1 is not currently supported in pico_multicore
panic_unsupported();/* ... */
#endif
multicore_launch_core1_raw(core1_trampoline, stack_ptr, vector_table);
}{ ... }
void multicore_launch_core1(void (*entry)(void)) {
extern uint32_t __StackOneBottom;
uint32_t *stack_limit = (uint32_t *) &__StackOneBottom;
uint32_t *stack = core1_stack <= stack_limit ? stack_limit : (uint32_t *) -1;
multicore_launch_core1_with_stack(entry, stack, sizeof(core1_stack));
}{ ... }
void multicore_launch_core1_raw(void (*entry)(void), uint32_t *sp, uint32_t vector_table) {
uint irq_num = SIO_FIFO_IRQ_NUM(0);
bool enabled = irq_is_enabled(irq_num);
irq_set_enabled(irq_num, false);
const uint32_t cmd_sequence[] =
{0, 0, 1, (uintptr_t) vector_table, (uintptr_t) sp, (uintptr_t) entry};
uint seq = 0;
do {
uint cmd = cmd_sequence[seq];
if (!cmd) {
multicore_fifo_drain();
__sev();
}if (!cmd) { ... }
multicore_fifo_push_blocking(cmd);
uint32_t response = multicore_fifo_pop_blocking();
seq = cmd == response ? seq + 1 : 0;
...} while (seq < count_of(cmd_sequence));
irq_set_enabled(irq_num, enabled);
}{ ... }
#define LOCKOUT_MAGIC_START 0x73a8831eu
#define LOCKOUT_MAGIC_END (~LOCKOUT_MAGIC_START)
static mutex_t lockout_mutex;
static bool lockout_in_progress;
static void __isr __not_in_flash_func(multicore_lockout_handler)(void) {
multicore_fifo_clear_irq();
while (multicore_fifo_rvalid()) {
if (sio_hw->fifo_rd == LOCKOUT_MAGIC_START) {
uint32_t save = save_and_disable_interrupts();
multicore_fifo_push_blocking_inline(LOCKOUT_MAGIC_START);
while (multicore_fifo_pop_blocking_inline() != LOCKOUT_MAGIC_END) {
tight_loop_contents();
}while (multicore_fifo_pop_blocking_inline() != LOCKOUT_MAGIC_END) { ... }
restore_interrupts_from_disabled(save);
multicore_fifo_push_blocking_inline(LOCKOUT_MAGIC_END);
}if (sio_hw->fifo_rd == LOCKOUT_MAGIC_START) { ... }
}while (multicore_fifo_rvalid()) { ... }
...}
static void check_lockout_mutex_init(void) {
uint32_t save = hw_claim_lock();
if (!mutex_is_initialized(&lockout_mutex)) {
mutex_init(&lockout_mutex);
}if (!mutex_is_initialized(&lockout_mutex)) { ... }
hw_claim_unlock(save);
}{ ... }
void multicore_lockout_victim_init(void) {
check_lockout_mutex_init();
uint core_num = get_core_num();
uint fifo_irq_this_core = SIO_FIFO_IRQ_NUM(core_num);
irq_set_exclusive_handler(fifo_irq_this_core, multicore_lockout_handler);
irq_set_enabled(fifo_irq_this_core, true);
lockout_victim_initialized[core_num] = true;
}{ ... }
static bool multicore_lockout_handshake(uint32_t magic, absolute_time_t until) {
uint irq_num = SIO_FIFO_IRQ_NUM(get_core_num());
bool enabled = irq_is_enabled(irq_num);
if (enabled) irq_set_enabled(irq_num, false);
bool rc = false;
do {
int64_t next_timeout_us = absolute_time_diff_us(get_absolute_time(), until);
if (next_timeout_us < 0) {
break;
}if (next_timeout_us < 0) { ... }
multicore_fifo_push_timeout_us(magic, (uint64_t)next_timeout_us);
next_timeout_us = absolute_time_diff_us(get_absolute_time(), until);
if (next_timeout_us < 0) {
break;
}if (next_timeout_us < 0) { ... }
uint32_t word = 0;
if (!multicore_fifo_pop_timeout_us((uint64_t)next_timeout_us, &word)) {
break;
}if (!multicore_fifo_pop_timeout_us((uint64_t)next_timeout_us, &word)) { ... }
if (word == magic) {
rc = true;
}if (word == magic) { ... }
...} while (!rc);
if (enabled) irq_set_enabled(irq_num, true);
return rc;
}{ ... }
static bool multicore_lockout_start_block_until(absolute_time_t until) {
check_lockout_mutex_init();
if (!mutex_enter_block_until(&lockout_mutex, until)) {
return false;
}if (!mutex_enter_block_until(&lockout_mutex, until)) { ... }
hard_assert(!lockout_in_progress);
bool rc = multicore_lockout_handshake(LOCKOUT_MAGIC_START, until);
lockout_in_progress = rc;
mutex_exit(&lockout_mutex);
return rc;
}{ ... }
bool multicore_lockout_start_timeout_us(uint64_t timeout_us) {
return multicore_lockout_start_block_until(make_timeout_time_us(timeout_us));
}{ ... }
void multicore_lockout_start_blocking(void) {
multicore_lockout_start_block_until(at_the_end_of_time);
}{ ... }
static bool multicore_lockout_end_block_until(absolute_time_t until) {
assert(mutex_is_initialized(&lockout_mutex));
if (!mutex_enter_block_until(&lockout_mutex, until)) {
return false;
}if (!mutex_enter_block_until(&lockout_mutex, until)) { ... }
assert(lockout_in_progress);
bool rc = multicore_lockout_handshake(LOCKOUT_MAGIC_END, until);
if (rc) {
lockout_in_progress = false;
}if (rc) { ... }
mutex_exit(&lockout_mutex);
return rc;
}{ ... }
bool multicore_lockout_end_timeout_us(uint64_t timeout_us) {
return multicore_lockout_end_block_until(make_timeout_time_us(timeout_us));
}{ ... }
void multicore_lockout_end_blocking(void) {
multicore_lockout_end_block_until(at_the_end_of_time);
}{ ... }
bool multicore_lockout_victim_is_initialized(uint core_num) {
return lockout_victim_initialized[core_num];
}{ ... }
#if NUM_DOORBELLS
static uint8_t doorbell_claimed[NUM_CORES][(NUM_DOORBELLS + 7) >> 3];
static inline bool is_bit_claimed(const uint8_t *bits, uint bit_index) {
return (bits[bit_index >> 3u] & (1u << (bit_index & 7u)));
}{ ... }
static inline void set_claimed_bit(uint8_t *bits, uint bit_index) {
bits[bit_index >> 3u] |= ( uint8_t ) ( 1u << ( bit_index & 7u ));
}{ ... }
static inline void clear_claimed_bit(uint8_t *bits, uint bit_index) {
bits[bit_index >> 3u] &= ( uint8_t ) ~( 1u << ( bit_index & 7u ));
}{ ... }
static bool multicore_doorbell_claim_under_lock(uint doorbell_num, uint core_mask, bool required) {
static_assert(NUM_CORES == 2, "");
uint claimed_cores_for_doorbell = (uint) (is_bit_claimed(doorbell_claimed[0], doorbell_num) |
(is_bit_claimed(doorbell_claimed[1], doorbell_num + 1u) << 1));
if (claimed_cores_for_doorbell & core_mask) {
if (required) {
panic( "Multicoore doorbell %d already claimed on core mask 0x%x; requested core mask 0x%x\n",
claimed_cores_for_doorbell, core_mask);
}if (required) { ... }
return false;
}if (claimed_cores_for_doorbell & core_mask) { ... } else {
for(uint i=0; i<NUM_CORES; i++) {
if (core_mask & (1u << i)) {
set_claimed_bit(doorbell_claimed[i], doorbell_num);
}if (core_mask & (1u << i)) { ... }
}for (uint i=0; i
return true;
}else { ... }
}{ ... }
void multicore_doorbell_claim(uint doorbell_num, uint core_mask) {
check_doorbell_num_param(doorbell_num);
uint32_t save = hw_claim_lock();
multicore_doorbell_claim_under_lock(doorbell_num, core_mask, true);
hw_claim_unlock(save);
}{ ... }
int multicore_doorbell_claim_unused(uint core_mask, bool required) {
int rc = PICO_ERROR_INSUFFICIENT_RESOURCES;
uint32_t save = hw_claim_lock();
for(int i=NUM_DOORBELLS-1; i>=0; i--) {
if (multicore_doorbell_claim_under_lock((uint) i, core_mask, false)) {
rc = i;
break;
}if (multicore_doorbell_claim_under_lock((uint) i, core_mask, false)) { ... }
}for (int i=NUM_DOORBELLS-1; i>=0; i--) { ... }
if (required && rc < 0) {
panic("No free doorbells");
}if (required && rc < 0) { ... }
hw_claim_unlock(save);
return rc;
}{ ... }
void multicore_doorbell_unclaim(uint doorbell_num, uint core_mask) {
check_doorbell_num_param(doorbell_num);
uint32_t save = hw_claim_lock();
for(uint i=0; i < NUM_CORES; i++) {
if (core_mask & (1u << i)) {
assert(is_bit_claimed(doorbell_claimed[i], doorbell_num));
clear_claimed_bit(doorbell_claimed[i], doorbell_num);
}if (core_mask & (1u << i)) { ... }
}for (uint i=0; i < NUM_CORES; i++) { ... }
hw_claim_unlock(save);
}{ ... }
/* ... */
#endif