all: add compiler support for interrupts

This commit lets the compiler know about interrupts and allows
optimizations to be performed based on that: interrupts are eliminated
when they appear to be unused in a program. This is done with a new
pseudo-call (runtime/interrupt.New) that is treated specially by the
compiler.
This commit is contained in:
Ayke van Laethem
2019-12-15 14:16:22 +01:00
committed by Ron Evans
parent 3729fcfa9e
commit a5ed993f8d
36 changed files with 766 additions and 199 deletions
+38
View File
@@ -0,0 +1,38 @@
// Package interrupt provides access to hardware interrupts. It provides a way
// to define interrupts and to enable/disable them.
package interrupt
// Interrupt provides direct access to hardware interrupts. You can configure
// this interrupt through this interface.
//
// Do not use the zero value of an Interrupt object. Instead, call New to obtain
// an interrupt handle.
type Interrupt struct {
// Make this number unexported so it cannot be set directly. This provides
// some encapsulation.
num int
}
// New is a compiler intrinsic that creates a new Interrupt object. You may call
// it only once, and must pass constant parameters to it. That means that the
// interrupt ID must be a Go constant and that the handler must be a simple
// function: closures are not supported.
func New(id int, handler func(Interrupt)) Interrupt
// Register is used to declare an interrupt. You should not normally call this
// function: it is only for telling the compiler about the mapping between an
// interrupt number and the interrupt handler name.
func Register(id int, handlerName string) int
// handle is used internally, between IR generation and interrupt lowering. The
// frontend will create runtime/interrupt.handle objects, cast them to an int,
// and use that in an Interrupt object. That way the compiler will be able to
// optimize away all interrupt handles that are never used in a program.
// This system only works when interrupts need to be enabled before use and this
// is done only through calling Enable() on this object. If interrups cannot
// individually be enabled/disabled, the compiler should create a pseudo-call
// (like runtime/interrupt.use()) that keeps the interrupt alive.
type handle struct {
handler func(Interrupt)
Interrupt
}
@@ -0,0 +1,23 @@
// +build cortexm
package interrupt
import (
"device/arm"
)
// Enable enables this interrupt. Right after calling this function, the
// interrupt may be invoked if it was already pending.
func (irq Interrupt) Enable() {
arm.EnableIRQ(uint32(irq.num))
}
// SetPriority sets the interrupt priority for this interrupt. A lower number
// means a higher priority. Additionally, most hardware doesn't implement all
// priority bits (only the uppoer bits).
//
// Examples: 0xff (lowest priority), 0xc0 (low priority), 0x00 (highest possible
// priority).
func (irq Interrupt) SetPriority(priority uint8) {
arm.SetPriority(uint32(irq.num), uint32(priority))
}
+9 -10
View File
@@ -6,6 +6,7 @@ import (
"device/arm"
"device/sam"
"machine"
"runtime/interrupt"
"runtime/volatile"
"unsafe"
)
@@ -214,8 +215,14 @@ func initRTC() {
sam.RTC_MODE0.CTRL.SetBits(sam.RTC_MODE0_CTRL_ENABLE)
waitForSync()
arm.SetPriority(sam.IRQ_RTC, 0xc0)
arm.EnableIRQ(sam.IRQ_RTC)
intr := interrupt.New(sam.IRQ_RTC, func(intr interrupt.Interrupt) {
// disable IRQ for CMP0 compare
sam.RTC_MODE0.INTFLAG.Set(sam.RTC_MODE0_INTENSET_CMP0)
timerWakeup.Set(1)
})
intr.SetPriority(0xc0)
intr.Enable()
}
func waitForSync() {
@@ -286,14 +293,6 @@ func timerSleep(ticks uint32) {
}
}
//go:export RTC_IRQHandler
func handleRTC() {
// disable IRQ for CMP0 compare
sam.RTC_MODE0.INTFLAG.Set(sam.RTC_MODE0_INTENSET_CMP0)
timerWakeup.Set(1)
}
func initUSBClock() {
// Turn on clock for USB
sam.PM.APBBMASK.SetBits(sam.PM_APBBMASK_USB_)
+9 -10
View File
@@ -6,6 +6,7 @@ import (
"device/arm"
"device/sam"
"machine"
"runtime/interrupt"
"runtime/volatile"
)
@@ -202,8 +203,14 @@ func initRTC() {
for sam.RTC_MODE0.SYNCBUSY.HasBits(sam.RTC_MODE0_SYNCBUSY_ENABLE) {
}
arm.SetPriority(sam.IRQ_RTC, 0xc0)
arm.EnableIRQ(sam.IRQ_RTC)
irq := interrupt.New(sam.IRQ_RTC, func(interrupt.Interrupt) {
// disable IRQ for CMP0 compare
sam.RTC_MODE0.INTFLAG.SetBits(sam.RTC_MODE0_INTENSET_CMP0)
timerWakeup.Set(1)
})
irq.SetPriority(0xc0)
irq.Enable()
}
func waitForSync() {
@@ -271,14 +278,6 @@ func timerSleep(ticks uint32) {
}
}
//go:export RTC_IRQHandler
func handleRTC() {
// disable IRQ for CMP0 compare
sam.RTC_MODE0.INTFLAG.SetBits(sam.RTC_MODE0_INTENSET_CMP0)
timerWakeup.Set(1)
}
func initUSBClock() {
// Turn on clock(s) for USB
//MCLK->APBBMASK.reg |= MCLK_APBBMASK_USB;
+8 -9
View File
@@ -6,6 +6,7 @@ import (
"device/arm"
"device/nrf"
"machine"
"runtime/interrupt"
"runtime/volatile"
)
@@ -43,8 +44,13 @@ func initLFCLK() {
func initRTC() {
nrf.RTC1.TASKS_START.Set(1)
arm.SetPriority(nrf.IRQ_RTC1, 0xc0) // low priority
arm.EnableIRQ(nrf.IRQ_RTC1)
intr := interrupt.New(nrf.IRQ_RTC1, func(intr interrupt.Interrupt) {
nrf.RTC1.INTENCLR.Set(nrf.RTC_INTENSET_COMPARE0)
nrf.RTC1.EVENTS_COMPARE[0].Set(0)
rtc_wakeup.Set(1)
})
intr.SetPriority(0xc0) // low priority
intr.Enable()
}
func putchar(c byte) {
@@ -96,10 +102,3 @@ func rtc_sleep(ticks uint32) {
arm.Asm("wfi")
}
}
//go:export RTC1_IRQHandler
func handleRTC1() {
nrf.RTC1.INTENCLR.Set(nrf.RTC_INTENSET_COMPARE0)
nrf.RTC1.EVENTS_COMPARE[0].Set(0)
rtc_wakeup.Set(1)
}
+5 -4
View File
@@ -6,6 +6,7 @@ import (
"device/arm"
"device/stm32"
"machine"
"runtime/interrupt"
"runtime/volatile"
)
@@ -101,8 +102,9 @@ func initRTC() {
func initTIM() {
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN)
arm.SetPriority(stm32.IRQ_TIM3, 0xc3)
arm.EnableIRQ(stm32.IRQ_TIM3)
intr := interrupt.New(stm32.IRQ_TIM3, handleTIM3)
intr.SetPriority(0xc3)
intr.Enable()
}
const asyncScheduler = false
@@ -186,8 +188,7 @@ func timerSleep(ticks uint32) {
}
}
//go:export TIM3_IRQHandler
func handleTIM3() {
func handleTIM3(interrupt.Interrupt) {
if stm32.TIM3.SR.HasBits(stm32.TIM_SR_UIF) {
// Disable the timer.
stm32.TIM3.CR1.ClearBits(stm32.TIM_CR1_CEN)
+9 -8
View File
@@ -6,6 +6,7 @@ import (
"device/arm"
"device/stm32"
"machine"
"runtime/interrupt"
"runtime/volatile"
)
@@ -121,8 +122,9 @@ var timerWakeup volatile.Register8
func initTIM3() {
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN)
arm.SetPriority(stm32.IRQ_TIM3, 0xc3)
arm.EnableIRQ(stm32.IRQ_TIM3)
intr := interrupt.New(stm32.IRQ_TIM3, handleTIM3)
intr.SetPriority(0xc3)
intr.Enable()
}
// Enable the TIM7 clock.(tick count)
@@ -139,8 +141,9 @@ func initTIM7() {
// Enable the timer.
stm32.TIM7.CR1.SetBits(stm32.TIM_CR1_CEN)
arm.SetPriority(stm32.IRQ_TIM7, 0xc1)
arm.EnableIRQ(stm32.IRQ_TIM7)
intr := interrupt.New(stm32.IRQ_TIM7, handleTIM7)
intr.SetPriority(0xc1)
intr.Enable()
}
const asyncScheduler = false
@@ -183,8 +186,7 @@ func timerSleep(ticks uint32) {
}
}
//go:export TIM3_IRQHandler
func handleTIM3() {
func handleTIM3(interrupt.Interrupt) {
if stm32.TIM3.SR.HasBits(stm32.TIM_SR_UIF) {
// Disable the timer.
stm32.TIM3.CR1.ClearBits(stm32.TIM_CR1_CEN)
@@ -197,8 +199,7 @@ func handleTIM3() {
}
}
//go:export TIM7_IRQHandler
func handleTIM7() {
func handleTIM7(interrupt.Interrupt) {
if stm32.TIM7.SR.HasBits(stm32.TIM_SR_UIF) {
// clear the update flag
stm32.TIM7.SR.ClearBits(stm32.TIM_SR_UIF)