Class: Amaterasu::GameBoy::Interrupts

Inherits:
Object
  • Object
show all
Defined in:
lib/amaterasu/game_boy/interrupts.rb

Overview

Models the Interrupts Controller inside the Game Boy

Constant Summary collapse

TYPES =

Interrupt types sorted by highest to lowest priority.

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

Address vectors to jump to for each interrupt type.

{
  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.



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:

  • (Boolean)


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

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

#highest_pendingObject

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

Raises:

  • (ArgumentError)


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_registerObject

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



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

def ie_register
  @ie
end

#ie_register=(value) ⇒ Object

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.



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

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

#if_registerObject

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

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



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

def if_register
  @if | 0b11100000
end

#if_register=(value) ⇒ Object

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.



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

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

#priority_serviceObject



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

def priority_service
  service(highest_pending)
end

#priority_vectorObject



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

def priority_vector
  VECTORS[highest_pending]
end

#request(type) ⇒ Object

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



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) ⇒ Object

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



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