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.
Этот коммит содержится в:
родитель
f14127be76
коммит
8687f3f8f4
5 изменённых файлов: 77 добавлений и 6 удалений
|
@ -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)))
|
||||
|
||||
|
|
36
src/runtime/interrupt/interrupt_gameboyadvance.go
Обычный файл
36
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<<uint(i)) != 0 {
|
||||
regInterruptRequestFlags.Set(1 << uint(i)) // acknowledge interrupt
|
||||
callInterruptHandler(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// callInterruptHandler is a compiler-generated function that calls the
|
||||
// appropriate interrupt handler for the given interrupt ID.
|
||||
//go:linkname callInterruptHandler runtime.callInterruptHandler
|
||||
func callInterruptHandler(id int)
|
|
@ -3,6 +3,7 @@
|
|||
package runtime
|
||||
|
||||
import (
|
||||
_ "runtime/interrupt" // make sure the interrupt handler is defined
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
OUTPUT_ARCH(arm)
|
||||
ENTRY(_start)
|
||||
|
||||
/* Note: iwram is reduced by 96 bytes because the last part of that RAM
|
||||
* (starting at 0x03007FA0) is used for interrupt handling.
|
||||
*/
|
||||
MEMORY {
|
||||
ewram : ORIGIN = 0x02000000, LENGTH = 256K /* on-board work RAM (2 wait states) */
|
||||
iwram : ORIGIN = 0x03000000, LENGTH = 32K /* in-chip work RAM (faster) */
|
||||
rom : ORIGIN = 0x08000000, LENGTH = 32M /* flash ROM */
|
||||
ewram : ORIGIN = 0x02000000, LENGTH = 256K /* on-board work RAM (2 wait states) */
|
||||
iwram : ORIGIN = 0x03000000, LENGTH = 32K-96 /* in-chip work RAM (faster) */
|
||||
rom : ORIGIN = 0x08000000, LENGTH = 32M /* flash ROM */
|
||||
}
|
||||
|
||||
__stack_size_irq = 1K;
|
||||
|
|
|
@ -17,9 +17,7 @@ _start:
|
|||
.byte 0x00,0x00 // Checksum (80000BEh)
|
||||
|
||||
start_vector:
|
||||
mov r0, #0x4000000 // REG_BASE
|
||||
str r0, [r0, #0x208]
|
||||
|
||||
// Configure stacks
|
||||
mov r0, #0x12 // Switch to IRQ Mode
|
||||
msr cpsr, r0
|
||||
ldr sp, =_stack_top_irq // Set IRQ stack
|
||||
|
@ -27,7 +25,21 @@ start_vector:
|
|||
msr cpsr, r0
|
||||
ldr sp, =_stack_top // Set user stack
|
||||
|
||||
// Configure interrupt handler
|
||||
mov r0, #0x4000000 // REG_BASE
|
||||
ldr r1, =handleInterruptARM
|
||||
str r1, [r0, #-4] // actually storing to 0x03007FFC due to mirroring
|
||||
|
||||
// Enable interrupts
|
||||
mov r1, #1
|
||||
str r1, [r0, #0x208] // 0x04000208 Interrupt Master Enable
|
||||
|
||||
// Jump to user code (switching to Thumb mode)
|
||||
ldr r3, =main
|
||||
bx r3
|
||||
|
||||
// Small interrupt handler that immediately jumps to a function defined in the
|
||||
// program (in Thumb) for further processing.
|
||||
handleInterruptARM:
|
||||
ldr r0, =handleInterrupt
|
||||
bx r0
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче