github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/runtime/interrupt/interrupt_gameboyadvance.go (about) 1 //go:build gameboyadvance 2 3 package interrupt 4 5 // This is good documentation of the GBA: https://www.akkit.org/info/gbatek.htm 6 7 import ( 8 "device/gba" 9 ) 10 11 // Enable enables this interrupt. Right after calling this function, the 12 // interrupt may be invoked if it was already pending. 13 func (irq Interrupt) Enable() { 14 gba.INTERRUPT.IE.SetBits(1 << uint(irq.num)) 15 } 16 17 var inInterrupt bool 18 19 //export handleInterrupt 20 func handleInterrupt() { 21 inInterrupt = true 22 flags := gba.INTERRUPT.IF.Get() 23 for i := 0; i < 14; i++ { 24 if flags&(1<<uint(i)) != 0 { 25 gba.INTERRUPT.IF.Set(1 << uint(i)) // acknowledge interrupt 26 callInterruptHandler(i) 27 } 28 } 29 inInterrupt = false 30 } 31 32 // Pseudo function call that is replaced by the compiler with the actual 33 // functions registered through interrupt.New. If there are none, calls will be 34 // replaced with 'unreachablecalls will be replaced with 'unreachable'. 35 // 36 //go:linkname callHandlers runtime/interrupt.callHandlers 37 func callHandlers(num int) 38 39 func callInterruptHandler(id int) { 40 switch id { 41 case gba.IRQ_VBLANK: 42 callHandlers(gba.IRQ_VBLANK) 43 case gba.IRQ_HBLANK: 44 callHandlers(gba.IRQ_HBLANK) 45 case gba.IRQ_VCOUNT: 46 callHandlers(gba.IRQ_VCOUNT) 47 case gba.IRQ_TIMER0: 48 callHandlers(gba.IRQ_TIMER0) 49 case gba.IRQ_TIMER1: 50 callHandlers(gba.IRQ_TIMER1) 51 case gba.IRQ_TIMER2: 52 callHandlers(gba.IRQ_TIMER2) 53 case gba.IRQ_TIMER3: 54 callHandlers(gba.IRQ_TIMER3) 55 case gba.IRQ_COM: 56 callHandlers(gba.IRQ_COM) 57 case gba.IRQ_DMA0: 58 callHandlers(gba.IRQ_DMA0) 59 case gba.IRQ_DMA1: 60 callHandlers(gba.IRQ_DMA1) 61 case gba.IRQ_DMA2: 62 callHandlers(gba.IRQ_DMA2) 63 case gba.IRQ_DMA3: 64 callHandlers(gba.IRQ_DMA3) 65 case gba.IRQ_KEYPAD: 66 callHandlers(gba.IRQ_KEYPAD) 67 case gba.IRQ_GAMEPAK: 68 callHandlers(gba.IRQ_GAMEPAK) 69 } 70 } 71 72 // State represents the previous global interrupt state. 73 type State uint8 74 75 // Disable disables all interrupts and returns the previous interrupt state. It 76 // can be used in a critical section like this: 77 // 78 // state := interrupt.Disable() 79 // // critical section 80 // interrupt.Restore(state) 81 // 82 // Critical sections can be nested. Make sure to call Restore in the same order 83 // as you called Disable (this happens naturally with the pattern above). 84 func Disable() (state State) { 85 // Save the previous interrupt state. 86 state = State(gba.INTERRUPT.PAUSE.Get()) 87 // Disable all interrupts. 88 gba.INTERRUPT.PAUSE.Set(0) 89 return 90 } 91 92 // Restore restores interrupts to what they were before. Give the previous state 93 // returned by Disable as a parameter. If interrupts were disabled before 94 // calling Disable, this will not re-enable interrupts, allowing for nested 95 // cricital sections. 96 func Restore(state State) { 97 // Restore interrupts to the previous state. 98 gba.INTERRUPT.PAUSE.Set(uint16(state)) 99 } 100 101 // In returns whether the system is currently in an interrupt. 102 func In() bool { 103 return inInterrupt 104 }