Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 0 additions & 30 deletions src/runtime/runtime_rp2.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
33 changes: 33 additions & 0 deletions src/runtime/runtime_rp2040.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
56 changes: 56 additions & 0 deletions src/runtime/runtime_rp2350.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,40 @@

package runtime

// #include <stdint.h>
//
// static void spinlock_lock(void *lock) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What was wrong with the sync/atomic operations? Custom assembly for just one target (rp2350) seems to me like a maintenance headache for little gain.

// 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 (
Expand All @@ -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))
}
Loading