Class: Amaterasu::GameBoy::Joypad
- Inherits:
-
Object
- Object
- Amaterasu::GameBoy::Joypad
- Defined in:
- lib/amaterasu/game_boy/joypad.rb,
sig/akane/game_boy/joypad.rbs
Overview
Models the joypad inputs and logic.
Constant Summary collapse
- BIT_MASK_UNUSED_BITS =
0b11000000- BIT_MASK_BUTTONS_SELECT_BIT =
0b00100000- BIT_MASK_DPAD_SELECT_BIT =
0b00010000- FACE_BUTTONS =
Maps all face buttons to its relevant bit.
{ a: 0, b: 1, select: 2, start: 3 }.freeze
- DPAD_BUTTONS =
Maps all D-pad buttons to its relevant bit.
{ right: 0, left: 1, up: 2, down: 3 }.freeze
Instance Method Summary collapse
- #buttons_selected? ⇒ Boolean
- #buttons_state ⇒ Integer
- #dpad_selected? ⇒ Boolean
-
#initialize(interrupts, skip_boot_rom: true) ⇒ Joypad
constructor
Creates a joypad object.
-
#p1 ⇒ Integer
Returns the 8-bit value stored in the P1 register.
-
#p1=(value) ⇒ void
Sets a 8-bit value into the P1 register.
- #press_dpad(button) ⇒ void
- #press_face(button) ⇒ void
- #release_dpad(button) ⇒ void
- #release_face(button) ⇒ void
- #request_interrupt ⇒ void
Constructor Details
#initialize(interrupts, skip_boot_rom: true) ⇒ Joypad
Creates a joypad object.
- Holds interrupts instance to request a :joypad interrupt.
- @p1 register only holds the relevant selection bits (Bits 5 and 4).
- Dpad and button state are tracked as separate nibbles.
33 34 35 36 37 38 39 |
# File 'lib/amaterasu/game_boy/joypad.rb', line 33 def initialize(interrupts, skip_boot_rom: true) @interrupts = interrupts @p1 = skip_boot_rom ? 0xCF : 0x00 @dpad = 0xF @buttons = 0xF end |
Instance Method Details
#buttons_selected? ⇒ Boolean
114 115 116 |
# File 'lib/amaterasu/game_boy/joypad.rb', line 114 def (@p1 >> 5).nobits?(1) end |
#buttons_state ⇒ Integer
118 119 120 121 122 123 124 |
# File 'lib/amaterasu/game_boy/joypad.rb', line 118 def return @dpad & @buttons if dpad_selected? && return @dpad if dpad_selected? return @buttons if 0xF end |
#dpad_selected? ⇒ Boolean
110 111 112 |
# File 'lib/amaterasu/game_boy/joypad.rb', line 110 def dpad_selected? (@p1 >> 4).nobits?(1) end |
#p1 ⇒ Integer
Returns the 8-bit value stored in the P1 register.
- Bits 7 and 6 are unused, they always read 1.
- The actual @p1 register only holds the 2 selection bits (Bit 5 and 4).
- Calculate the buttons state based on the pressed buttons and use it as the lower nibble.
46 47 48 |
# File 'lib/amaterasu/game_boy/joypad.rb', line 46 def p1 BIT_MASK_UNUSED_BITS | @p1 | end |
#p1=(value) ⇒ void
This method returns an undefined value.
Sets a 8-bit value into the P1 register.
- The lower nibble is read-only.
- Bit 5 is used to select the face buttons.
- Bit 4 is used to select the d-pad.
55 56 57 58 59 60 61 62 |
# File 'lib/amaterasu/game_boy/joypad.rb', line 55 def p1=(value) old_state = @p1 = value & 0b00110000 new_state = falling_edges = old_state & ~new_state # checks for bits that went 1 -> 0 request_interrupt if falling_edges.anybits?(0x0F) end |
#press_dpad(button) ⇒ void
This method returns an undefined value.
65 66 67 68 69 70 71 72 73 |
# File 'lib/amaterasu/game_boy/joypad.rb', line 65 def press_dpad() relevant_bit = DPAD_BUTTONS[] return if (@dpad >> relevant_bit).nobits?(1) # already pressed clear_mask = ~(1 << relevant_bit) @dpad &= clear_mask request_interrupt if dpad_selected? end |
#press_face(button) ⇒ void
This method returns an undefined value.
85 86 87 88 89 90 91 92 93 |
# File 'lib/amaterasu/game_boy/joypad.rb', line 85 def press_face() relevant_bit = FACE_BUTTONS[] return if (@buttons >> relevant_bit).nobits?(1) # already pressed clear_mask = ~(1 << relevant_bit) @buttons &= clear_mask request_interrupt if end |
#release_dpad(button) ⇒ void
This method returns an undefined value.
76 77 78 79 80 81 82 |
# File 'lib/amaterasu/game_boy/joypad.rb', line 76 def release_dpad() relevant_bit = DPAD_BUTTONS[] return if (@dpad >> relevant_bit).anybits?(1) # already released set_mask = (1 << relevant_bit) @dpad |= set_mask end |
#release_face(button) ⇒ void
This method returns an undefined value.
96 97 98 99 100 101 102 |
# File 'lib/amaterasu/game_boy/joypad.rb', line 96 def release_face() relevant_bit = FACE_BUTTONS[] return if (@buttons >> relevant_bit).anybits?(1) # already released set_mask = (1 << relevant_bit) @buttons |= set_mask end |
#request_interrupt ⇒ void
This method returns an undefined value.
106 107 108 |
# File 'lib/amaterasu/game_boy/joypad.rb', line 106 def request_interrupt @interrupts.request(:joypad) end |