
This reduces current consumption from 500-1000µA to very low (<10µA) current consumption. This change is important for battery powered devices, especially devices that may be running for long periods of time.
104 строки
2,5 КиБ
Go
104 строки
2,5 КиБ
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)
|
|
}
|