Class: Amaterasu::GameBoy::Interrupts
- Inherits:
-
Object
- Object
- Amaterasu::GameBoy::Interrupts
- 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
-
#any_pending? ⇒ Boolean
Checks if any interrupt is requested and enabled at the same time.
-
#highest_pending ⇒ Object
Returns which interrupt is currently requested and enabled, sorted by priority.
-
#ie_register ⇒ Object
TODO: convert to attr_reader Returns the 8-bit value of the IE (Interrupt Enable) register.
-
#ie_register=(value) ⇒ Object
Sets a 8-bit value into the IE register.
-
#if_register ⇒ Object
Returns the 8-bit value of the IF (Interrupt Flag) register.
-
#if_register=(value) ⇒ Object
Sets a 8-bit value into the IF register.
-
#initialize(skip_boot_rom: true) ⇒ Interrupts
constructor
Creates a new interrupts object holding the registers state.
- #priority_service ⇒ Object
- #priority_vector ⇒ Object
-
#request(type) ⇒ Object
Sets the correct Bit in the IF register based on the interrupt type.
-
#service(type) ⇒ Object
Clears the correct Bit in the IF register based on the interrupt type.
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.
66 67 68 |
# File 'lib/amaterasu/game_boy/interrupts.rb', line 66 def any_pending? (@if & @ie).anybits?(0b00011111) end |
#highest_pending ⇒ Object
Returns which interrupt is currently requested and enabled, sorted by priority.
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_register ⇒ Object
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_register ⇒ Object
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_service ⇒ Object
91 92 93 |
# File 'lib/amaterasu/game_boy/interrupts.rb', line 91 def priority_service service(highest_pending) end |
#priority_vector ⇒ Object
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 |