mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-04 02:57:46 +00:00
602c264749
Before this commit, goroutine support was spread through the compiler. This commit changes this support, so that the compiler itself only generates simple intrinsics and leaves the real support to a compiler pass that runs as one of the TinyGo-specific optimization passes. The biggest change, that was done together with the rewrite, was support for goroutines in WebAssembly for JavaScript. The challenge in JavaScript is that in general no blocking operations are allowed, which means that programs that call time.Sleep() but do not start goroutines also have to be scheduled by the scheduler.
108 lines
2.2 KiB
Go
108 lines
2.2 KiB
Go
// +build nrf
|
|
|
|
package runtime
|
|
|
|
import (
|
|
"device/arm"
|
|
"device/nrf"
|
|
"machine"
|
|
)
|
|
|
|
type timeUnit int64
|
|
|
|
const tickMicros = 1024 * 32
|
|
|
|
//go:linkname systemInit SystemInit
|
|
func systemInit()
|
|
|
|
//go:export Reset_Handler
|
|
func main() {
|
|
systemInit()
|
|
preinit()
|
|
initAll()
|
|
callMain()
|
|
abort()
|
|
}
|
|
|
|
func init() {
|
|
machine.UART0.Configure(machine.UARTConfig{})
|
|
initLFCLK()
|
|
initRTC()
|
|
}
|
|
|
|
func initLFCLK() {
|
|
if machine.HasLowFrequencyCrystal {
|
|
nrf.CLOCK.LFCLKSRC = nrf.CLOCK_LFCLKSTAT_SRC_Xtal
|
|
}
|
|
nrf.CLOCK.TASKS_LFCLKSTART = 1
|
|
for nrf.CLOCK.EVENTS_LFCLKSTARTED == 0 {
|
|
}
|
|
nrf.CLOCK.EVENTS_LFCLKSTARTED = 0
|
|
}
|
|
|
|
func initRTC() {
|
|
nrf.RTC1.TASKS_START = 1
|
|
arm.SetPriority(nrf.IRQ_RTC1, 0xc0) // low priority
|
|
arm.EnableIRQ(nrf.IRQ_RTC1)
|
|
}
|
|
|
|
func putchar(c byte) {
|
|
machine.UART0.WriteByte(c)
|
|
}
|
|
|
|
const asyncScheduler = false
|
|
|
|
func sleepTicks(d timeUnit) {
|
|
for d != 0 {
|
|
ticks() // update timestamp
|
|
ticks := uint32(d) & 0x7fffff // 23 bits (to be on the safe side)
|
|
rtc_sleep(ticks) // TODO: not accurate (must be d / 30.5175...)
|
|
d -= timeUnit(ticks)
|
|
}
|
|
}
|
|
|
|
var (
|
|
timestamp timeUnit // nanoseconds since boottime
|
|
rtcLastCounter uint32 // 24 bits ticks
|
|
)
|
|
|
|
// Monotonically increasing numer of ticks since start.
|
|
//
|
|
// Note: very long pauses between measurements (more than 8 minutes) may
|
|
// overflow the counter, leading to incorrect results. This might be fixed by
|
|
// handling the overflow event.
|
|
func ticks() timeUnit {
|
|
rtcCounter := uint32(nrf.RTC1.COUNTER)
|
|
offset := (rtcCounter - rtcLastCounter) & 0xffffff // change since last measurement
|
|
rtcLastCounter = rtcCounter
|
|
timestamp += timeUnit(offset) // TODO: not precise
|
|
return timestamp
|
|
}
|
|
|
|
//go:volatile
|
|
type isrFlag bool
|
|
|
|
var rtc_wakeup isrFlag
|
|
|
|
func rtc_sleep(ticks uint32) {
|
|
nrf.RTC1.INTENSET = nrf.RTC_INTENSET_COMPARE0
|
|
rtc_wakeup = false
|
|
if ticks == 1 {
|
|
// Race condition (even in hardware) at ticks == 1.
|
|
// TODO: fix this in a better way by detecting it, like the manual
|
|
// describes.
|
|
ticks = 2
|
|
}
|
|
nrf.RTC1.CC[0] = (nrf.RTC1.COUNTER + nrf.RegValue(ticks)) & 0x00ffffff
|
|
for !rtc_wakeup {
|
|
arm.Asm("wfi")
|
|
}
|
|
}
|
|
|
|
//go:export RTC1_IRQHandler
|
|
func handleRTC1() {
|
|
nrf.RTC1.INTENCLR = nrf.RTC_INTENSET_COMPARE0
|
|
nrf.RTC1.EVENTS_COMPARE[0] = 0
|
|
rtc_wakeup = true
|
|
}
|