3
3
package runtime
4
4
5
5
import (
6
+ "device/arm"
6
7
"device/rp"
7
8
)
8
9
@@ -14,3 +15,60 @@ const (
14
15
sioIrqFifoProc0 = rp .IRQ_SIO_IRQ_FIFO
15
16
sioIrqFifoProc1 = rp .IRQ_SIO_IRQ_FIFO
16
17
)
18
+
19
+ // Due to hardware errata RP2350-E2 spinlocks are emulated in software as in pico-sdk.
20
+ type spinLock struct {
21
+ // lock field must be first field so its address is the same as the struct address.
22
+ lock uint8
23
+ id uint8
24
+ uint16 // Padding to prevent false sharing
25
+ }
26
+
27
+ func (l * spinLock ) Lock () {
28
+ // Original reference:
29
+ // https://github.com/raspberrypi/pico-sdk/blob/2.2.0/src/rp2_common/hardware_sync_spin_lock/include/hardware/sync/spin_lock.h#L112
30
+
31
+ // r0 is automatically filled with the pointer value "l" here.
32
+ // We create a variable to allow access the lock byte and avoid a memory
33
+ // fault when accessing l.lock in assembly.
34
+ lock := & l .lock
35
+ _ = lock
36
+
37
+ // Set a loop start point
38
+ arm .Asm ("1:" )
39
+ // Exclusively load the state variable (l.lock) and put its value in r2.
40
+ arm .Asm ("ldaexb r2, [r0]" )
41
+ // Store the "locked" state value (1) into r1 to keep things moving.
42
+ arm .Asm ("movs r1, #1" )
43
+ // Check if the lock was already taken (r2 != 0).
44
+ arm .Asm ("cmp r2, #0" )
45
+ // Jump back to "1:" if the lock is already held
46
+ arm .Asm ("bne 1b" )
47
+
48
+ // Attempt to store '1' into the lock address.
49
+ // The return code (0 for success, 1 for failure) is placed in r2.
50
+ arm .Asm ("strexb r2, r1, [r0]" )
51
+ // Check if the result was successful (r2 == 0).
52
+ arm .Asm ("cmp r2, #0" )
53
+ // Jump back to "1:" if the lock was not acquired.
54
+ arm .Asm ("bne 1b" )
55
+
56
+ // Memory barrier to ensure everyone knows we're holding the lock now.
57
+ arm .Asm ("dmb" )
58
+ }
59
+
60
+ func (l * spinLock ) Unlock () {
61
+ // Original reference:
62
+ // https://github.com/raspberrypi/pico-sdk/blob/2.2.0/src/rp2_common/hardware_sync_spin_lock/include/hardware/sync/spin_lock.h#L197
63
+
64
+ // r0 is automatically filled with the pointer value l here.
65
+ // We create a variable to allow access the lock byte and avoid a memory
66
+ // fault when accessing l.lock in assembly.
67
+ lock := & l .lock
68
+ _ = lock
69
+ // Fill r1 with 0 and store it to the lock address in r0. stlb requires a
70
+ // register as a source so we can't use a literal 0 directly.
71
+ arm .Asm ("movs r1, #0" )
72
+ // Release the pseudo-spinlock by writing 0 to and releasing l.lock.
73
+ arm .Asm ("stlb r1, [r0]" )
74
+ }
0 commit comments