diff options
-rw-r--r-- | src/runtime/runtime.go | 2 | ||||
-rw-r--r-- | src/runtime/runtime_arm7tdmi.go | 10 | ||||
-rw-r--r-- | src/runtime/runtime_atsamd21.go | 35 | ||||
-rw-r--r-- | src/runtime/runtime_atsamd51.go | 31 | ||||
-rw-r--r-- | src/runtime/runtime_avr.go | 12 | ||||
-rw-r--r-- | src/runtime/runtime_cortexm_qemu.go | 10 | ||||
-rw-r--r-- | src/runtime/runtime_fe310_baremetal.go | 16 | ||||
-rw-r--r-- | src/runtime/runtime_fe310_qemu.go | 12 | ||||
-rw-r--r-- | src/runtime/runtime_nrf.go | 22 | ||||
-rw-r--r-- | src/runtime/runtime_stm32f103xx.go | 10 | ||||
-rw-r--r-- | src/runtime/runtime_stm32f407.go | 10 | ||||
-rw-r--r-- | src/runtime/runtime_tinygoriscv_qemu.go | 10 | ||||
-rw-r--r-- | src/runtime/runtime_unix.go | 13 | ||||
-rw-r--r-- | src/runtime/runtime_wasm.go | 15 | ||||
-rw-r--r-- | src/runtime/scheduler.go | 6 | ||||
-rw-r--r-- | src/runtime/scheduler_any.go | 2 | ||||
-rw-r--r-- | src/runtime/scheduler_none.go | 2 |
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. |