aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/runtime/runtime.go2
-rw-r--r--src/runtime/runtime_arm7tdmi.go10
-rw-r--r--src/runtime/runtime_atsamd21.go35
-rw-r--r--src/runtime/runtime_atsamd51.go31
-rw-r--r--src/runtime/runtime_avr.go12
-rw-r--r--src/runtime/runtime_cortexm_qemu.go10
-rw-r--r--src/runtime/runtime_fe310_baremetal.go16
-rw-r--r--src/runtime/runtime_fe310_qemu.go12
-rw-r--r--src/runtime/runtime_nrf.go22
-rw-r--r--src/runtime/runtime_stm32f103xx.go10
-rw-r--r--src/runtime/runtime_stm32f407.go10
-rw-r--r--src/runtime/runtime_tinygoriscv_qemu.go10
-rw-r--r--src/runtime/runtime_unix.go13
-rw-r--r--src/runtime/runtime_wasm.go15
-rw-r--r--src/runtime/scheduler.go6
-rw-r--r--src/runtime/scheduler_any.go2
-rw-r--r--src/runtime/scheduler_none.go2
17 files changed, 168 insertions, 50 deletions
diff --git a/src/runtime/runtime.go b/src/runtime/runtime.go
index 41d0b9ace..3a4a8cd8d 100644
--- a/src/runtime/runtime.go
+++ b/src/runtime/runtime.go
@@ -61,7 +61,7 @@ func memequal(x, y unsafe.Pointer, n uintptr) bool {
}
func nanotime() int64 {
- return int64(ticks()) * tickMicros
+ return ticksToNanoseconds(ticks())
}
// timeOffset is how long the monotonic clock started after the Unix epoch. It
diff --git a/src/runtime/runtime_arm7tdmi.go b/src/runtime/runtime_arm7tdmi.go
index 0c36be540..70b764042 100644
--- a/src/runtime/runtime_arm7tdmi.go
+++ b/src/runtime/runtime_arm7tdmi.go
@@ -9,8 +9,6 @@ import (
type timeUnit int64
-const tickMicros = 1
-
func putchar(c byte) {
// dummy, TODO
}
@@ -60,6 +58,14 @@ func preinit() {
}
}
+func ticksToNanoseconds(ticks timeUnit) int64 {
+ return int64(ticks)
+}
+
+func nanosecondsToTicks(ns int64) timeUnit {
+ return timeUnit(ns)
+}
+
func ticks() timeUnit {
// TODO
return 0
diff --git a/src/runtime/runtime_atsamd21.go b/src/runtime/runtime_atsamd21.go
index 17bba3802..1055db0c6 100644
--- a/src/runtime/runtime_atsamd21.go
+++ b/src/runtime/runtime_atsamd21.go
@@ -231,9 +231,6 @@ func waitForSync() {
}
}
-// treat all ticks params coming from runtime as being in microseconds
-const tickMicros = 1000
-
var (
timestamp timeUnit // ticks since boottime
timerLastCounter uint64
@@ -243,6 +240,22 @@ var timerWakeup volatile.Register8
const asyncScheduler = false
+// ticksToNanoseconds converts RTC ticks (at 32768Hz) to nanoseconds.
+func ticksToNanoseconds(ticks timeUnit) int64 {
+ // The following calculation is actually the following, but with both sides
+ // reduced to reduce the risk of overflow:
+ // ticks * 1e9 / 32768
+ return int64(ticks) * 1953125 / 64
+}
+
+// nanosecondsToTicks converts nanoseconds to RTC ticks (running at 32768Hz).
+func nanosecondsToTicks(ns int64) timeUnit {
+ // The following calculation is actually the following, but with both sides
+ // reduced to reduce the risk of overflow:
+ // ns * 32768 / 1e9
+ return timeUnit(ns * 64 / 1953125)
+}
+
// sleepTicks should sleep for d number of microseconds.
func sleepTicks(d timeUnit) {
for d != 0 {
@@ -259,22 +272,22 @@ func ticks() timeUnit {
sam.RTC_MODE0.READREQ.Set(sam.RTC_MODE0_READREQ_RREQ)
waitForSync()
- rtcCounter := (uint64(sam.RTC_MODE0.COUNT.Get()) * 305) / 10 // each counter tick == 30.5us
- offset := (rtcCounter - timerLastCounter) // change since last measurement
+ rtcCounter := uint64(sam.RTC_MODE0.COUNT.Get()) // each counter tick == 30.5us
+ offset := (rtcCounter - timerLastCounter) // change since last measurement
timerLastCounter = rtcCounter
- timestamp += timeUnit(offset) // TODO: not precise
+ timestamp += timeUnit(offset)
return timestamp
}
// ticks are in microseconds
func timerSleep(ticks uint32) {
timerWakeup.Set(0)
- if ticks < 214 {
- // due to around 183us delay waiting for the register value to sync, the minimum sleep value
- // for the SAMD21 is 214us.
+ if ticks < 7 {
+ // Due to around 6 clock ticks delay waiting for the register value to
+ // sync, the minimum sleep value for the SAMD21 is 214us.
// For related info, see:
// https://community.atmel.com/comment/2507091#comment-2507091
- ticks = 214
+ ticks = 7
}
// request read of count
@@ -283,7 +296,7 @@ func timerSleep(ticks uint32) {
// set compare value
cnt := sam.RTC_MODE0.COUNT.Get()
- sam.RTC_MODE0.COMP0.Set(uint32(cnt) + (ticks * 10 / 305)) // each counter tick == 30.5us
+ sam.RTC_MODE0.COMP0.Set(uint32(cnt) + ticks)
waitForSync()
// enable IRQ for CMP0 compare
diff --git a/src/runtime/runtime_atsamd51.go b/src/runtime/runtime_atsamd51.go
index 93ae1216a..dd9da121f 100644
--- a/src/runtime/runtime_atsamd51.go
+++ b/src/runtime/runtime_atsamd51.go
@@ -219,9 +219,6 @@ func waitForSync() {
}
}
-// treat all ticks params coming from runtime as being in microseconds
-const tickMicros = 1000
-
var (
timestamp timeUnit // ticks since boottime
timerLastCounter uint64
@@ -231,6 +228,22 @@ var timerWakeup volatile.Register8
const asyncScheduler = false
+// ticksToNanoseconds converts RTC ticks (at 32768Hz) to nanoseconds.
+func ticksToNanoseconds(ticks timeUnit) int64 {
+ // The following calculation is actually the following, but with both sides
+ // reduced to reduce the risk of overflow:
+ // ticks * 1e9 / 32768
+ return int64(ticks) * 1953125 / 64
+}
+
+// nanosecondsToTicks converts nanoseconds to RTC ticks (running at 32768Hz).
+func nanosecondsToTicks(ns int64) timeUnit {
+ // The following calculation is actually the following, but with both sides
+ // reduced to reduce the risk of overflow:
+ // ns * 32768 / 1e9
+ return timeUnit(ns * 64 / 1953125)
+}
+
// sleepTicks should sleep for d number of microseconds.
func sleepTicks(d timeUnit) {
for d != 0 {
@@ -245,22 +258,22 @@ func sleepTicks(d timeUnit) {
func ticks() timeUnit {
waitForSync()
- rtcCounter := (uint64(sam.RTC_MODE0.COUNT.Get()) * 305) / 10 // each counter tick == 30.5us
- offset := (rtcCounter - timerLastCounter) // change since last measurement
+ rtcCounter := uint64(sam.RTC_MODE0.COUNT.Get())
+ offset := (rtcCounter - timerLastCounter) // change since last measurement
timerLastCounter = rtcCounter
- timestamp += timeUnit(offset) // TODO: not precise
+ timestamp += timeUnit(offset)
return timestamp
}
// ticks are in microseconds
func timerSleep(ticks uint32) {
timerWakeup.Set(0)
- if ticks < 260 {
+ if ticks < 8 {
// due to delay waiting for the register value to sync, the minimum sleep value
// for the SAMD51 is 260us.
// For related info for SAMD21, see:
// https://community.atmel.com/comment/2507091#comment-2507091
- ticks = 260
+ ticks = 8
}
// request read of count
@@ -269,7 +282,7 @@ func timerSleep(ticks uint32) {
// set compare value
cnt := sam.RTC_MODE0.COUNT.Get()
- sam.RTC_MODE0.COMP[0].Set(uint32(cnt) + (ticks * 10 / 305)) // each counter tick == 30.5us
+ sam.RTC_MODE0.COMP[0].Set(uint32(cnt) + ticks)
// enable IRQ for CMP0 compare
sam.RTC_MODE0.INTENSET.SetBits(sam.RTC_MODE0_INTENSET_CMP0)
diff --git a/src/runtime/runtime_avr.go b/src/runtime/runtime_avr.go
index 18a763966..ae8a4d41e 100644
--- a/src/runtime/runtime_avr.go
+++ b/src/runtime/runtime_avr.go
@@ -14,8 +14,6 @@ type timeUnit uint32
var currentTime timeUnit
-const tickMicros = 1024 * 16384
-
// Watchdog timer periods. These can be off by a large margin (hence the jump
// between 64ms and 125ms which is not an exact double), so don't rely on this
// for accurate time keeping.
@@ -71,6 +69,16 @@ func putchar(c byte) {
const asyncScheduler = false
+const tickNanos = 1024 * 16384 // roughly 16ms in nanoseconds
+
+func ticksToNanoseconds(ticks timeUnit) int64 {
+ return int64(ticks) * tickNanos
+}
+
+func nanosecondsToTicks(ns int64) timeUnit {
+ return timeUnit(ns / tickNanos)
+}
+
// Sleep this number of ticks of 16ms.
//
// TODO: not very accurate. Improve accuracy by calibrating on startup and every
diff --git a/src/runtime/runtime_cortexm_qemu.go b/src/runtime/runtime_cortexm_qemu.go
index 1686c2d8e..eed201563 100644
--- a/src/runtime/runtime_cortexm_qemu.go
+++ b/src/runtime/runtime_cortexm_qemu.go
@@ -13,8 +13,6 @@ import (
type timeUnit int64
-const tickMicros = 1
-
var timestamp timeUnit
func postinit() {}
@@ -29,6 +27,14 @@ func main() {
const asyncScheduler = false
+func ticksToNanoseconds(ticks timeUnit) int64 {
+ return int64(ticks)
+}
+
+func nanosecondsToTicks(ns int64) timeUnit {
+ return timeUnit(ns)
+}
+
func sleepTicks(d timeUnit) {
// TODO: actually sleep here for the given time.
timestamp += d
diff --git a/src/runtime/runtime_fe310_baremetal.go b/src/runtime/runtime_fe310_baremetal.go
index e04560c4a..4fa62e69a 100644
--- a/src/runtime/runtime_fe310_baremetal.go
+++ b/src/runtime/runtime_fe310_baremetal.go
@@ -6,7 +6,21 @@ import (
"device/riscv"
)
-const tickMicros = 32768 // RTC clock runs at 32.768kHz
+// ticksToNanoseconds converts RTC ticks (at 32768Hz) to nanoseconds.
+func ticksToNanoseconds(ticks timeUnit) int64 {
+ // The following calculation is actually the following, but with both sides
+ // reduced to reduce the risk of overflow:
+ // ticks * 1e9 / 32768
+ return int64(ticks) * 1953125 / 64
+}
+
+// nanosecondsToTicks converts nanoseconds to RTC ticks (running at 32768Hz).
+func nanosecondsToTicks(ns int64) timeUnit {
+ // The following calculation is actually the following, but with both sides
+ // reduced to reduce the risk of overflow:
+ // ns * 32768 / 1e9
+ return timeUnit(ns * 64 / 1953125)
+}
func abort() {
// lock up forever
diff --git a/src/runtime/runtime_fe310_qemu.go b/src/runtime/runtime_fe310_qemu.go
index 132515e79..ce14abfdd 100644
--- a/src/runtime/runtime_fe310_qemu.go
+++ b/src/runtime/runtime_fe310_qemu.go
@@ -7,12 +7,18 @@ import (
"unsafe"
)
-const tickMicros = 100 // CLINT.MTIME increments every 100ns
-
// Special memory-mapped device to exit tests, created by SiFive.
var testExit = (*volatile.Register32)(unsafe.Pointer(uintptr(0x100000)))
-var timestamp timeUnit
+// ticksToNanoseconds converts CLINT ticks (at 100ns per tick) to nanoseconds.
+func ticksToNanoseconds(ticks timeUnit) int64 {
+ return int64(ticks) * 100
+}
+
+// nanosecondsToTicks converts nanoseconds to CLINT ticks (at 100ns per tick).
+func nanosecondsToTicks(ns int64) timeUnit {
+ return timeUnit(ns / 100)
+}
func abort() {
// Signal a successful exit.
diff --git a/src/runtime/runtime_nrf.go b/src/runtime/runtime_nrf.go
index c3cde0026..9a0678c6d 100644
--- a/src/runtime/runtime_nrf.go
+++ b/src/runtime/runtime_nrf.go
@@ -12,8 +12,6 @@ import (
type timeUnit int64
-const tickMicros = 1024 * 32
-
//go:linkname systemInit SystemInit
func systemInit()
@@ -64,7 +62,7 @@ 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...)
+ rtc_sleep(ticks)
d -= timeUnit(ticks)
}
}
@@ -74,6 +72,22 @@ var (
rtcLastCounter uint32 // 24 bits ticks
)
+// ticksToNanoseconds converts RTC ticks (at 32768Hz) to nanoseconds.
+func ticksToNanoseconds(ticks timeUnit) int64 {
+ // The following calculation is actually the following, but with both sides
+ // reduced to reduce the risk of overflow:
+ // ticks * 1e9 / 32768
+ return int64(ticks) * 1953125 / 64
+}
+
+// nanosecondsToTicks converts nanoseconds to RTC ticks (running at 32768Hz).
+func nanosecondsToTicks(ns int64) timeUnit {
+ // The following calculation is actually the following, but with both sides
+ // reduced to reduce the risk of overflow:
+ // ns * 32768 / 1e9
+ return timeUnit(ns * 64 / 1953125)
+}
+
// Monotonically increasing numer of ticks since start.
//
// Note: very long pauses between measurements (more than 8 minutes) may
@@ -83,7 +97,7 @@ func ticks() timeUnit {
rtcCounter := uint32(nrf.RTC1.COUNTER.Get())
offset := (rtcCounter - rtcLastCounter) & 0xffffff // change since last measurement
rtcLastCounter = rtcCounter
- timestamp += timeUnit(offset) // TODO: not precise
+ timestamp += timeUnit(offset)
return timestamp
}
diff --git a/src/runtime/runtime_stm32f103xx.go b/src/runtime/runtime_stm32f103xx.go
index 8c29c264b..7407fa738 100644
--- a/src/runtime/runtime_stm32f103xx.go
+++ b/src/runtime/runtime_stm32f103xx.go
@@ -53,8 +53,6 @@ func initCLK() {
}
}
-const tickMicros = 1000
-
var (
timestamp timeUnit // microseconds since boottime
timerLastCounter uint64
@@ -109,6 +107,14 @@ func initTIM() {
const asyncScheduler = false
+func ticksToNanoseconds(ticks timeUnit) int64 {
+ return int64(ticks) * 1000
+}
+
+func nanosecondsToTicks(ns int64) timeUnit {
+ return timeUnit(ns / 1000)
+}
+
// sleepTicks should sleep for specific number of microseconds.
func sleepTicks(d timeUnit) {
for d != 0 {
diff --git a/src/runtime/runtime_stm32f407.go b/src/runtime/runtime_stm32f407.go
index fd1be5b43..626dabd94 100644
--- a/src/runtime/runtime_stm32f407.go
+++ b/src/runtime/runtime_stm32f407.go
@@ -109,8 +109,6 @@ func initCLK() {
}
-const tickMicros = 1000
-
var (
// tick in milliseconds
tickCount timeUnit
@@ -118,6 +116,14 @@ var (
var timerWakeup volatile.Register8
+func ticksToNanoseconds(ticks timeUnit) int64 {
+ return int64(ticks) * 1000
+}
+
+func nanosecondsToTicks(ns int64) timeUnit {
+ return timeUnit(ns / 1000)
+}
+
// Enable the TIM3 clock.(sleep count)
func initTIM3() {
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN)
diff --git a/src/runtime/runtime_tinygoriscv_qemu.go b/src/runtime/runtime_tinygoriscv_qemu.go
index 1155d553e..27caa398a 100644
--- a/src/runtime/runtime_tinygoriscv_qemu.go
+++ b/src/runtime/runtime_tinygoriscv_qemu.go
@@ -13,8 +13,6 @@ import (
type timeUnit int64
-const tickMicros = 1
-
var timestamp timeUnit
func postinit() {}
@@ -28,6 +26,14 @@ func main() {
const asyncScheduler = false
+func ticksToNanoseconds(ticks timeUnit) int64 {
+ return int64(ticks)
+}
+
+func nanosecondsToTicks(ns int64) timeUnit {
+ return timeUnit(ns)
+}
+
func sleepTicks(d timeUnit) {
// TODO: actually sleep here for the given time.
timestamp += d
diff --git a/src/runtime/runtime_unix.go b/src/runtime/runtime_unix.go
index a23d9e0e6..e1adeb342 100644
--- a/src/runtime/runtime_unix.go
+++ b/src/runtime/runtime_unix.go
@@ -26,8 +26,6 @@ func clock_gettime(clk_id int32, ts *timespec)
type timeUnit int64
-const tickMicros = 1
-
// Note: tv_sec and tv_nsec vary in size by platform. They are 32-bit on 32-bit
// systems and 64-bit on 64-bit systems (at least on macOS/Linux), so we can
// simply use the 'int' type which does the same.
@@ -57,7 +55,18 @@ func putchar(c byte) {
const asyncScheduler = false
+func ticksToNanoseconds(ticks timeUnit) int64 {
+ // The OS API works in nanoseconds so no conversion necessary.
+ return int64(ticks)
+}
+
+func nanosecondsToTicks(ns int64) timeUnit {
+ // The OS API works in nanoseconds so no conversion necessary.
+ return timeUnit(ns)
+}
+
func sleepTicks(d timeUnit) {
+ // timeUnit is in nanoseconds, so need to convert to microseconds here.
usleep(uint(d) / 1000)
}
diff --git a/src/runtime/runtime_wasm.go b/src/runtime/runtime_wasm.go
index 0b955c756..3cddd9d8e 100644
--- a/src/runtime/runtime_wasm.go
+++ b/src/runtime/runtime_wasm.go
@@ -6,8 +6,6 @@ import "unsafe"
type timeUnit float64 // time in milliseconds, just like Date.now() in JavaScript
-const tickMicros = 1000000
-
// Implements __wasi_ciovec_t and __wasi_iovec_t.
type wasiIOVec struct {
buf unsafe.Pointer
@@ -68,6 +66,19 @@ func go_scheduler() {
const asyncScheduler = true
+func ticksToNanoseconds(ticks timeUnit) int64 {
+ // The JavaScript API works in float64 milliseconds, so convert to
+ // nanoseconds first before converting to a timeUnit (which is a float64),
+ // to avoid precision loss.
+ return int64(ticks * 1e6)
+}
+
+func nanosecondsToTicks(ns int64) timeUnit {
+ // The JavaScript API works in float64 milliseconds, so convert to timeUnit
+ // (which is a float64) first before dividing, to avoid precision loss.
+ return timeUnit(ns) / 1e6
+}
+
// This function is called by the scheduler.
// Schedule a call to runtime.scheduler, do not actually sleep.
//export runtime.sleepTicks
diff --git a/src/runtime/scheduler.go b/src/runtime/scheduler.go
index 49cf8e402..a8c9f16b1 100644
--- a/src/runtime/scheduler.go
+++ b/src/runtime/scheduler.go
@@ -75,14 +75,14 @@ func runqueuePushBack(t *task.Task) {
}
// Add this task to the sleep queue, assuming its state is set to sleeping.
-func addSleepTask(t *task.Task, duration int64) {
+func addSleepTask(t *task.Task, duration timeUnit) {
if schedulerDebug {
- println(" set sleep:", t, uint(duration/tickMicros))
+ println(" set sleep:", t, duration)
if t.Next != nil {
panic("runtime: addSleepTask: expected next task to be nil")
}
}
- t.Data = uint(duration / tickMicros) // TODO: longer durations
+ t.Data = uint(duration) // TODO: longer durations
now := ticks()
if sleepQueue == nil {
scheduleLog(" -> sleep new queue")
diff --git a/src/runtime/scheduler_any.go b/src/runtime/scheduler_any.go
index 41a904535..fb7ca6e96 100644
--- a/src/runtime/scheduler_any.go
+++ b/src/runtime/scheduler_any.go
@@ -7,7 +7,7 @@ import "internal/task"
// Pause the current task for a given time.
//go:linkname sleep time.Sleep
func sleep(duration int64) {
- addSleepTask(task.Current(), duration)
+ addSleepTask(task.Current(), nanosecondsToTicks(duration))
task.Pause()
}
diff --git a/src/runtime/scheduler_none.go b/src/runtime/scheduler_none.go
index d462ca15c..e40615fe8 100644
--- a/src/runtime/scheduler_none.go
+++ b/src/runtime/scheduler_none.go
@@ -4,7 +4,7 @@ package runtime
//go:linkname sleep time.Sleep
func sleep(duration int64) {
- sleepTicks(timeUnit(duration / tickMicros))
+ sleepTicks(nanosecondsToTicks(duration))
}
// getSystemStackPointer returns the current stack pointer of the system stack.