Class: Amaterasu::GameBoy::Joypad
- Inherits:
-
Object
- Object
- Amaterasu::GameBoy::Joypad
- Defined in:
- lib/amaterasu/game_boy/joypad.rb
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
-
#initialize(interrupts, skip_boot_rom: true) ⇒ Joypad
constructor
Creates a joypad object.
-
#p1 ⇒ Object
Returns the 8-bit value stored in the P1 register.
-
#p1=(value) ⇒ Object
Sets a 8-bit value into the P1 register.
- #press_dpad(button) ⇒ Object
- #press_face(button) ⇒ Object
- #release_dpad(button) ⇒ Object
- #release_face(button) ⇒ Object
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
#p1 ⇒ Object
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) ⇒ Object
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) ⇒ Object
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) ⇒ Object
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) ⇒ Object
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) ⇒ Object
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 |