diff --git a/src/runtime/runtime_rp2.go b/src/runtime/runtime_rp2.go index 08ae865699..9a6a1c1bda 100644 --- a/src/runtime/runtime_rp2.go +++ b/src/runtime/runtime_rp2.go @@ -298,36 +298,6 @@ var ( futexLock = spinLock{id: 23} ) -func resetSpinLocks() { - for i := uint8(0); i < numSpinlocks; i++ { - l := &spinLock{id: i} - l.spinlock().Set(0) - } -} - -// A hardware spinlock, one of the 32 spinlocks defined in the SIO peripheral. -type spinLock struct { - id uint8 -} - -// Return the spinlock register: rp.SIO.SPINLOCKx -func (l *spinLock) spinlock() *volatile.Register32 { - return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&rp.SIO.SPINLOCK0), l.id*4)) -} - -func (l *spinLock) Lock() { - // Wait for the lock to be available. - spinlock := l.spinlock() - for spinlock.Get() == 0 { - arm.Asm("wfe") - } -} - -func (l *spinLock) Unlock() { - l.spinlock().Set(0) - arm.Asm("sev") -} - // Wait until a signal is received, indicating that it can resume from the // spinloop. func spinLoopWait() { diff --git a/src/runtime/runtime_rp2040.go b/src/runtime/runtime_rp2040.go index 2ca3605e03..84377ace37 100644 --- a/src/runtime/runtime_rp2040.go +++ b/src/runtime/runtime_rp2040.go @@ -3,10 +3,43 @@ package runtime import ( + "device/arm" "device/rp" + "runtime/volatile" + "unsafe" ) const ( sioIrqFifoProc0 = rp.IRQ_SIO_IRQ_PROC0 sioIrqFifoProc1 = rp.IRQ_SIO_IRQ_PROC1 ) + +func resetSpinLocks() { + for i := uint8(0); i < numSpinlocks; i++ { + l := &spinLock{id: i} + l.spinlock().Set(0) + } +} + +// A hardware spinlock, one of the 32 spinlocks defined in the SIO peripheral. +type spinLock struct { + id uint8 +} + +// Return the spinlock register: rp.SIO.SPINLOCKx +func (l *spinLock) spinlock() *volatile.Register32 { + return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&rp.SIO.SPINLOCK0), l.id*4)) +} + +func (l *spinLock) Lock() { + // Wait for the lock to be available. + spinlock := l.spinlock() + for spinlock.Get() == 0 { + arm.Asm("wfe") + } +} + +func (l *spinLock) Unlock() { + l.spinlock().Set(0) + arm.Asm("sev") +} diff --git a/src/runtime/runtime_rp2350.go b/src/runtime/runtime_rp2350.go index 91af23212e..93ac2f7ff7 100644 --- a/src/runtime/runtime_rp2350.go +++ b/src/runtime/runtime_rp2350.go @@ -2,8 +2,40 @@ package runtime +// #include +// +// static void spinlock_lock(void *lock) { +// uint32_t _tmp0, _tmp1; +// __asm volatile ( \ +// "1:\n" \ +// "ldaexb %1, [%2]\n" \ +// "movs %0, #1\n" /* fill dependency slot */ \ +// "cmp %1, #0\n" \ +// /* Immediately retry if lock is seen to be taken */ \ +// "bne 1b\n" \ +// /* Attempt to claim */ \ +// "strexb %1, %0, [%2]\n" \ +// "cmp %1, #0\n" \ +// /* Claim failed due to intervening write, so retry */ \ +// "bne 1b\n" \ +// : "=&r" (_tmp0), "=&r" (_tmp1) : "r" (lock) \ +// ); \ +// __asm volatile ("dmb" : : : "memory"); +// } +// +// static void spinlock_unlock(void *lock) { +// /* Release-ordered store is available: use instead of separate fence */ \ +// uint32_t zero = 0; \ +// __asm volatile ( \ +// "stlb %0, [%1]\n" \ +// : : "r" (zero), "r" (lock) \ +// ); \ +// } +import "C" + import ( "device/rp" + "unsafe" ) const ( @@ -14,3 +46,27 @@ const ( sioIrqFifoProc0 = rp.IRQ_SIO_IRQ_FIFO sioIrqFifoProc1 = rp.IRQ_SIO_IRQ_FIFO ) + +// Software spinlocks don't persist across soft resets so this is a no-op. +func resetSpinLocks() {} + +type spinLock struct { + state uint8 + id uint8 + _ [2]uint8 +} + +func (l *spinLock) Lock() { + // Try to replace 0 with 1. Once we succeed, the lock has been acquired. + C.spinlock_lock(unsafe.Pointer(&l.state)) +} + +func (l *spinLock) Unlock() { + // Safety check: the spinlock should have been locked. + if schedulerAsserts && l.state != 1 { + runtimePanic("unlock of unlocked spinlock") + } + + // Unlock the lock. Simply write 0, because we already know it is locked. + C.spinlock_unlock(unsafe.Pointer(&l.state)) +}