|
|
@ -5,37 +5,13 @@ package interrupt |
|
|
|
// This is good documentation of the GBA: https://www.akkit.org/info/gbatek.htm
|
|
|
|
|
|
|
|
import ( |
|
|
|
"runtime/volatile" |
|
|
|
"unsafe" |
|
|
|
) |
|
|
|
|
|
|
|
const ( |
|
|
|
IRQ_VBLANK = 0 |
|
|
|
IRQ_HBLANK = 1 |
|
|
|
IRQ_VCOUNT = 2 |
|
|
|
IRQ_TIMER0 = 3 |
|
|
|
IRQ_TIMER1 = 4 |
|
|
|
IRQ_TIMER2 = 5 |
|
|
|
IRQ_TIMER3 = 6 |
|
|
|
IRQ_COM = 7 |
|
|
|
IRQ_DMA0 = 8 |
|
|
|
IRQ_DMA1 = 9 |
|
|
|
IRQ_DMA2 = 10 |
|
|
|
IRQ_DMA3 = 11 |
|
|
|
IRQ_KEYPAD = 12 |
|
|
|
IRQ_GAMEPAK = 13 |
|
|
|
) |
|
|
|
|
|
|
|
var ( |
|
|
|
regInterruptEnable = (*volatile.Register16)(unsafe.Pointer(uintptr(0x4000200))) |
|
|
|
regInterruptRequestFlags = (*volatile.Register16)(unsafe.Pointer(uintptr(0x4000202))) |
|
|
|
regGlobalInterruptEnable = (*volatile.Register16)(unsafe.Pointer(uintptr(0x4000208))) |
|
|
|
"device/gba" |
|
|
|
) |
|
|
|
|
|
|
|
// Enable enables this interrupt. Right after calling this function, the
|
|
|
|
// interrupt may be invoked if it was already pending.
|
|
|
|
func (irq Interrupt) Enable() { |
|
|
|
regInterruptEnable.SetBits(1 << uint(irq.num)) |
|
|
|
gba.INTERRUPT.IE.SetBits(1 << uint(irq.num)) |
|
|
|
} |
|
|
|
|
|
|
|
var inInterrupt bool |
|
|
@ -43,10 +19,10 @@ var inInterrupt bool |
|
|
|
//export handleInterrupt
|
|
|
|
func handleInterrupt() { |
|
|
|
inInterrupt = true |
|
|
|
flags := regInterruptRequestFlags.Get() |
|
|
|
flags := gba.INTERRUPT.IF.Get() |
|
|
|
for i := 0; i < 14; i++ { |
|
|
|
if flags&(1<<uint(i)) != 0 { |
|
|
|
regInterruptRequestFlags.Set(1 << uint(i)) // acknowledge interrupt
|
|
|
|
gba.INTERRUPT.IF.Set(1 << uint(i)) // acknowledge interrupt
|
|
|
|
callInterruptHandler(i) |
|
|
|
} |
|
|
|
} |
|
|
@ -62,34 +38,34 @@ func callHandlers(num int) |
|
|
|
|
|
|
|
func callInterruptHandler(id int) { |
|
|
|
switch id { |
|
|
|
case IRQ_VBLANK: |
|
|
|
callHandlers(IRQ_VBLANK) |
|
|
|
case IRQ_HBLANK: |
|
|
|
callHandlers(IRQ_HBLANK) |
|
|
|
case IRQ_VCOUNT: |
|
|
|
callHandlers(IRQ_VCOUNT) |
|
|
|
case IRQ_TIMER0: |
|
|
|
callHandlers(IRQ_TIMER0) |
|
|
|
case IRQ_TIMER1: |
|
|
|
callHandlers(IRQ_TIMER1) |
|
|
|
case IRQ_TIMER2: |
|
|
|
callHandlers(IRQ_TIMER2) |
|
|
|
case IRQ_TIMER3: |
|
|
|
callHandlers(IRQ_TIMER3) |
|
|
|
case IRQ_COM: |
|
|
|
callHandlers(IRQ_COM) |
|
|
|
case IRQ_DMA0: |
|
|
|
callHandlers(IRQ_DMA0) |
|
|
|
case IRQ_DMA1: |
|
|
|
callHandlers(IRQ_DMA1) |
|
|
|
case IRQ_DMA2: |
|
|
|
callHandlers(IRQ_DMA2) |
|
|
|
case IRQ_DMA3: |
|
|
|
callHandlers(IRQ_DMA3) |
|
|
|
case IRQ_KEYPAD: |
|
|
|
callHandlers(IRQ_KEYPAD) |
|
|
|
case IRQ_GAMEPAK: |
|
|
|
callHandlers(IRQ_GAMEPAK) |
|
|
|
case gba.IRQ_VBLANK: |
|
|
|
callHandlers(gba.IRQ_VBLANK) |
|
|
|
case gba.IRQ_HBLANK: |
|
|
|
callHandlers(gba.IRQ_HBLANK) |
|
|
|
case gba.IRQ_VCOUNT: |
|
|
|
callHandlers(gba.IRQ_VCOUNT) |
|
|
|
case gba.IRQ_TIMER0: |
|
|
|
callHandlers(gba.IRQ_TIMER0) |
|
|
|
case gba.IRQ_TIMER1: |
|
|
|
callHandlers(gba.IRQ_TIMER1) |
|
|
|
case gba.IRQ_TIMER2: |
|
|
|
callHandlers(gba.IRQ_TIMER2) |
|
|
|
case gba.IRQ_TIMER3: |
|
|
|
callHandlers(gba.IRQ_TIMER3) |
|
|
|
case gba.IRQ_COM: |
|
|
|
callHandlers(gba.IRQ_COM) |
|
|
|
case gba.IRQ_DMA0: |
|
|
|
callHandlers(gba.IRQ_DMA0) |
|
|
|
case gba.IRQ_DMA1: |
|
|
|
callHandlers(gba.IRQ_DMA1) |
|
|
|
case gba.IRQ_DMA2: |
|
|
|
callHandlers(gba.IRQ_DMA2) |
|
|
|
case gba.IRQ_DMA3: |
|
|
|
callHandlers(gba.IRQ_DMA3) |
|
|
|
case gba.IRQ_KEYPAD: |
|
|
|
callHandlers(gba.IRQ_KEYPAD) |
|
|
|
case gba.IRQ_GAMEPAK: |
|
|
|
callHandlers(gba.IRQ_GAMEPAK) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -107,9 +83,9 @@ type State uint8 |
|
|
|
// as you called Disable (this happens naturally with the pattern above).
|
|
|
|
func Disable() (state State) { |
|
|
|
// Save the previous interrupt state.
|
|
|
|
state = State(regGlobalInterruptEnable.Get()) |
|
|
|
state = State(gba.INTERRUPT.PAUSE.Get()) |
|
|
|
// Disable all interrupts.
|
|
|
|
regGlobalInterruptEnable.Set(0) |
|
|
|
gba.INTERRUPT.PAUSE.Set(0) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
@ -119,7 +95,7 @@ func Disable() (state State) { |
|
|
|
// cricital sections.
|
|
|
|
func Restore(state State) { |
|
|
|
// Restore interrupts to the previous state.
|
|
|
|
regGlobalInterruptEnable.Set(uint16(state)) |
|
|
|
gba.INTERRUPT.PAUSE.Set(uint16(state)) |
|
|
|
} |
|
|
|
|
|
|
|
// In returns whether the system is currently in an interrupt.
|
|
|
|