From 8687f3f8f40f69bea64e8a1a836a5eb49b72de92 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Mon, 6 Jan 2020 11:50:41 +0100 Subject: [PATCH] targets/gba: implement interrupt handler Thanks to Kyle Lemons for the inspiration and original design. The implementation in this commit is very different however, building on top of the software vectoring needed in RISC-V. The result is a flexible interrupt handler that does not take up any RAM for configuration. --- src/machine/machine_gameboyadvance.go | 19 ++++++++++ .../interrupt/interrupt_gameboyadvance.go | 36 +++++++++++++++++++ src/runtime/runtime_arm7tdmi.go | 1 + targets/gameboy-advance.ld | 9 +++-- targets/gameboy-advance.s | 18 ++++++++-- 5 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 src/runtime/interrupt/interrupt_gameboyadvance.go diff --git a/src/machine/machine_gameboyadvance.go b/src/machine/machine_gameboyadvance.go index 7c6ffcb8..6913205f 100644 --- a/src/machine/machine_gameboyadvance.go +++ b/src/machine/machine_gameboyadvance.go @@ -8,6 +8,25 @@ import ( "unsafe" ) +// Interrupt numbers as used on the GameBoy Advance. Register them with +// runtime/interrupt.New. +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 +) + // Make it easier to directly write to I/O RAM. var ioram = (*[0x400]volatile.Register8)(unsafe.Pointer(uintptr(0x04000000))) diff --git a/src/runtime/interrupt/interrupt_gameboyadvance.go b/src/runtime/interrupt/interrupt_gameboyadvance.go new file mode 100644 index 00000000..c25afc14 --- /dev/null +++ b/src/runtime/interrupt/interrupt_gameboyadvance.go @@ -0,0 +1,36 @@ +// +build gameboyadvance + +package interrupt + +import ( + "runtime/volatile" + "unsafe" +) + +var ( + regInterruptEnable = (*volatile.Register16)(unsafe.Pointer(uintptr(0x4000200))) + regInterruptRequestFlags = (*volatile.Register16)(unsafe.Pointer(uintptr(0x4000202))) + regInterruptMasterEnable = (*volatile.Register16)(unsafe.Pointer(uintptr(0x4000208))) +) + +// 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)) +} + +//export handleInterrupt +func handleInterrupt() { + flags := regInterruptRequestFlags.Get() + for i := 0; i < 14; i++ { + if flags&(1<