108 строки
2,6 КиБ
Go
108 строки
2,6 КиБ
Go
// +build cortexm
|
|
|
|
package runtime
|
|
|
|
import (
|
|
"device/arm"
|
|
)
|
|
|
|
const GOARCH = "arm"
|
|
|
|
// The bitness of the CPU (e.g. 8, 32, 64).
|
|
const TargetBits = 32
|
|
|
|
// Align on word boundary.
|
|
func align(ptr uintptr) uintptr {
|
|
return (ptr + 3) &^ 3
|
|
}
|
|
|
|
func getCurrentStackPointer() uintptr {
|
|
return arm.AsmFull("mov {}, sp", nil)
|
|
}
|
|
|
|
// Documentation:
|
|
// * https://llvm.org/docs/Atomics.html
|
|
// * https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html
|
|
//
|
|
// In the case of Cortex-M, some atomic operations are emitted inline while
|
|
// others are emitted as libcalls. How many are emitted as libcalls depends on
|
|
// the MCU core variant (M3 and higher support some 32-bit atomic operations
|
|
// while M0 and M0+ do not).
|
|
|
|
//export __sync_fetch_and_add_4
|
|
func __sync_fetch_and_add_4(ptr *uint32, value uint32) uint32 {
|
|
mask := arm.DisableInterrupts()
|
|
oldValue := *ptr
|
|
*ptr = oldValue + value
|
|
arm.EnableInterrupts(mask)
|
|
return oldValue
|
|
}
|
|
|
|
//export __sync_fetch_and_add_8
|
|
func __sync_fetch_and_add_8(ptr *uint64, value uint64) uint64 {
|
|
mask := arm.DisableInterrupts()
|
|
oldValue := *ptr
|
|
*ptr = oldValue + value
|
|
arm.EnableInterrupts(mask)
|
|
return oldValue
|
|
}
|
|
|
|
//export __sync_lock_test_and_set_4
|
|
func __sync_lock_test_and_set_4(ptr *uint32, value uint32) uint32 {
|
|
mask := arm.DisableInterrupts()
|
|
oldValue := *ptr
|
|
*ptr = value
|
|
arm.EnableInterrupts(mask)
|
|
return oldValue
|
|
}
|
|
|
|
//export __sync_lock_test_and_set_8
|
|
func __sync_lock_test_and_set_8(ptr *uint64, value uint64) uint64 {
|
|
mask := arm.DisableInterrupts()
|
|
oldValue := *ptr
|
|
*ptr = value
|
|
arm.EnableInterrupts(mask)
|
|
return oldValue
|
|
}
|
|
|
|
//export __sync_val_compare_and_swap_4
|
|
func __sync_val_compare_and_swap_4(ptr *uint32, expected, desired uint32) uint32 {
|
|
mask := arm.DisableInterrupts()
|
|
oldValue := *ptr
|
|
if oldValue == expected {
|
|
*ptr = desired
|
|
}
|
|
arm.EnableInterrupts(mask)
|
|
return oldValue
|
|
}
|
|
|
|
//export __sync_val_compare_and_swap_8
|
|
func __sync_val_compare_and_swap_8(ptr *uint64, expected, desired uint64) uint64 {
|
|
mask := arm.DisableInterrupts()
|
|
oldValue := *ptr
|
|
if oldValue == expected {
|
|
*ptr = desired
|
|
}
|
|
arm.EnableInterrupts(mask)
|
|
return oldValue
|
|
}
|
|
|
|
// The safest thing to do here would just be to disable interrupts for
|
|
// procPin/procUnpin. Note that a global variable is safe in this case, as any
|
|
// access to procPinnedMask will happen with interrupts disabled.
|
|
|
|
var procPinnedMask uintptr
|
|
|
|
//go:linkname procPin sync/atomic.runtime_procPin
|
|
func procPin() {
|
|
procPinnedMask = arm.DisableInterrupts()
|
|
}
|
|
|
|
//go:linkname procUnpin sync/atomic.runtime_procUnpin
|
|
func procUnpin() {
|
|
arm.EnableInterrupts(procPinnedMask)
|
|
}
|
|
|
|
func waitForEvents() {
|
|
arm.Asm("wfe")
|
|
}
|