Class: Amaterasu::GameBoy::Interrupts

Inherits:
Object
  • Object
show all
Defined in:
lib/amaterasu/game_boy/interrupts.rb,
sig/akane/game_boy/interrupts.rbs

Overview

Models the Interrupts Controller inside the Game Boy

Constant Summary collapse

TYPES =

Interrupt types sorted by highest to lowest priority.

Returns:

{
  v_blank: 0,
  lcd_stat: 1,
  timer: 2,
  serial: 3,
  joypad: 4
}.freeze
VECTORS =

Address vectors to jump to for each interrupt type.

Returns:

{
  v_blank: 0x0040,
  lcd_stat: 0x0048,
  timer: 0x0050,
  serial: 0x0058,
  joypad: 0x0060
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(skip_boot_rom: true) ⇒ Interrupts

Creates a new interrupts object holding the registers state.

  • IF register value changes based on the Boot ROM being skipped.

Parameters:

  • (defaults to: true)


28
29
30
31
# File 'lib/amaterasu/game_boy/interrupts.rb', line 28

def initialize(skip_boot_rom: true)
  @if = skip_boot_rom ? 0xE1 : 0x00
  @ie = 0x00
end

Instance Method Details

#any_pending?Boolean

Checks if any interrupt is requested and enabled at the same time.

  • Ignores the 3 upper bits that are not bound to any interrupt type.

Returns:



66
67
68
# File 'lib/amaterasu/game_boy/interrupts.rb', line 66

def any_pending?
  (@if & @ie).anybits?(0b00011111)
end

#highest_pendinginterrupt_types

Returns which interrupt is currently requested and enabled, sorted by priority.

Returns:

Raises:



71
72
73
74
75
76
77
# File 'lib/amaterasu/game_boy/interrupts.rb', line 71

def highest_pending
  TYPES.each_key do |type|
    return type if pending?(type)
  end

  raise ArgumentError, 'No interrupts found for highest pending'
end

#ie_registerInteger

TODO: convert to attr_reader Returns the 8-bit value of the IE (Interrupt Enable) register.

Returns:



42
43
44
# File 'lib/amaterasu/game_boy/interrupts.rb', line 42

def ie_register
  @ie
end

#ie_register=(value) ⇒ void

This method returns an undefined value.

Sets a 8-bit value into the IE register.

  • Values are set by the game's code during CPU fetch-decode.
  • Controls whether or not a given interrupt is enabled and can be serviced.

Parameters:



59
60
61
# File 'lib/amaterasu/game_boy/interrupts.rb', line 59

def ie_register=(value)
  @ie = value & 0xFF
end

#if_registerInteger

Returns the 8-bit value of the IF (Interrupt Flag) register.

  • When read, it always returns 1 for Bits 7, 6 and 5.

Returns:



36
37
38
# File 'lib/amaterasu/game_boy/interrupts.rb', line 36

def if_register
  @if | 0b11100000
end

#if_register=(value) ⇒ void

This method returns an undefined value.

Sets a 8-bit value into the IF register.

  • Bits 7, 6 and 5 are set to 0 when writing to it.
  • Components are responsible for requesting their own interrupts.
  • Controls whether or not a given interrupt is currently requested.

Parameters:



51
52
53
# File 'lib/amaterasu/game_boy/interrupts.rb', line 51

def if_register=(value)
  @if = value & 0b00011111
end

#pending?(type) ⇒ Boolean

Checks if a given interrupt is requested and enabled at the same time.

Parameters:

Returns:



102
103
104
105
# File 'lib/amaterasu/game_boy/interrupts.rb', line 102

def pending?(type)
  set_mask = (1 << TYPES[type])
  ((@if & set_mask) & (@ie & set_mask)).anybits?(0b00011111)
end

#priority_servicevoid

This method returns an undefined value.



91
92
93
# File 'lib/amaterasu/game_boy/interrupts.rb', line 91

def priority_service
  service(highest_pending)
end

#priority_vectorInteger

Returns:



95
96
97
# File 'lib/amaterasu/game_boy/interrupts.rb', line 95

def priority_vector
  VECTORS[highest_pending]
end

#request(type) ⇒ void

This method returns an undefined value.

Sets the correct Bit in the IF register based on the interrupt type.

Parameters:



80
81
82
83
# File 'lib/amaterasu/game_boy/interrupts.rb', line 80

def request(type)
  set_mask = 1 << TYPES[type]
  @if |= set_mask
end

#service(type) ⇒ void

This method returns an undefined value.

Clears the correct Bit in the IF register based on the interrupt type.

Parameters:



86
87
88
89
# File 'lib/amaterasu/game_boy/interrupts.rb', line 86

def service(type)
  clear_mask = ~(1 << TYPES[type])
  @if &= clear_mask
end