diff --git a/src/runtime/interrupt/interrupt_avr.go b/src/runtime/interrupt/interrupt_avr.go new file mode 100644 index 00000000..6eb6b28f --- /dev/null +++ b/src/runtime/interrupt/interrupt_avr.go @@ -0,0 +1,36 @@ +// +build avr + +package interrupt + +import "device" + +// State represents the previous global interrupt state. +type State uint8 + +// Disable disables all interrupts and returns the previous interrupt state. It +// can be used in a critical section like this: +// +// state := interrupt.Disable() +// // critical section +// interrupt.Restore(state) +// +// Critical sections can be nested. Make sure to call Restore in the same order +// as you called Disable (this happens naturally with the pattern above). +func Disable() (state State) { + // SREG is at I/O address 0x3f. + return State(device.AsmFull(` + in {}, 0x3f + cli + `, nil)) +} + +// Restore restores interrupts to what they were before. Give the previous state +// returned by Disable as a parameter. If interrupts were disabled before +// calling Disable, this will not re-enable interrupts, allowing for nested +// cricital sections. +func Restore(state State) { + // SREG is at I/O address 0x3f. + device.AsmFull("out 0x3f, {state}", map[string]interface{}{ + "state": state, + }) +} diff --git a/src/runtime/interrupt/interrupt_cortexm.go b/src/runtime/interrupt/interrupt_cortexm.go index 5354be9e..c23f736d 100644 --- a/src/runtime/interrupt/interrupt_cortexm.go +++ b/src/runtime/interrupt/interrupt_cortexm.go @@ -21,3 +21,27 @@ func (irq Interrupt) Enable() { func (irq Interrupt) SetPriority(priority uint8) { arm.SetPriority(uint32(irq.num), uint32(priority)) } + +// State represents the previous global interrupt state. +type State uintptr + +// Disable disables all interrupts and returns the previous interrupt state. It +// can be used in a critical section like this: +// +// state := interrupt.Disable() +// // critical section +// interrupt.Restore(state) +// +// Critical sections can be nested. Make sure to call Restore in the same order +// as you called Disable (this happens naturally with the pattern above). +func Disable() (state State) { + return State(arm.DisableInterrupts()) +} + +// Restore restores interrupts to what they were before. Give the previous state +// returned by Disable as a parameter. If interrupts were disabled before +// calling Disable, this will not re-enable interrupts, allowing for nested +// cricital sections. +func Restore(state State) { + arm.EnableInterrupts(uintptr(state)) +} diff --git a/src/runtime/interrupt/interrupt_gameboyadvance.go b/src/runtime/interrupt/interrupt_gameboyadvance.go index c25afc14..e4b20293 100644 --- a/src/runtime/interrupt/interrupt_gameboyadvance.go +++ b/src/runtime/interrupt/interrupt_gameboyadvance.go @@ -34,3 +34,32 @@ func handleInterrupt() { // appropriate interrupt handler for the given interrupt ID. //go:linkname callInterruptHandler runtime.callInterruptHandler func callInterruptHandler(id int) + +// State represents the previous global interrupt state. +type State uint8 + +// Disable disables all interrupts and returns the previous interrupt state. It +// can be used in a critical section like this: +// +// state := interrupt.Disable() +// // critical section +// interrupt.Restore(state) +// +// Critical sections can be nested. Make sure to call Restore in the same order +// as you called Disable (this happens naturally with the pattern above). +func Disable() (state State) { + // Save the previous interrupt state. + state = State(regInterruptMasterEnable.Get()) + // Disable all interrupts. + regInterruptMasterEnable.Set(0) + return +} + +// Restore restores interrupts to what they were before. Give the previous state +// returned by Disable as a parameter. If interrupts were disabled before +// calling Disable, this will not re-enable interrupts, allowing for nested +// cricital sections. +func Restore(state State) { + // Restore interrupts to the previous state. + regInterruptMasterEnable.Set(uint16(state)) +} diff --git a/src/runtime/interrupt/interrupt_tinygoriscv.go b/src/runtime/interrupt/interrupt_tinygoriscv.go new file mode 100644 index 00000000..0161018d --- /dev/null +++ b/src/runtime/interrupt/interrupt_tinygoriscv.go @@ -0,0 +1,29 @@ +// +build tinygo.riscv + +package interrupt + +import "device/riscv" + +// State represents the previous global interrupt state. +type State uintptr + +// Disable disables all interrupts and returns the previous interrupt state. It +// can be used in a critical section like this: +// +// state := interrupt.Disable() +// // critical section +// interrupt.Restore(state) +// +// Critical sections can be nested. Make sure to call Restore in the same order +// as you called Disable (this happens naturally with the pattern above). +func Disable() (state State) { + return State(riscv.DisableInterrupts()) +} + +// Restore restores interrupts to what they were before. Give the previous state +// returned by Disable as a parameter. If interrupts were disabled before +// calling Disable, this will not re-enable interrupts, allowing for nested +// cricital sections. +func Restore(state State) { + riscv.EnableInterrupts(uintptr(state)) +}