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  }