diff --git a/src/crab/gba.cr b/src/crab/gba.cr index 3449ef2..a0f962d 100644 --- a/src/crab/gba.cr +++ b/src/crab/gba.cr @@ -3,6 +3,7 @@ require "./util" require "./scheduler" require "./cartridge" require "./mmio" +require "./keypad" require "./bus" require "./interrupts" require "./cpu" @@ -13,6 +14,7 @@ class GBA getter scheduler : Scheduler getter cartridge : Cartridge getter mmio : MMIO { MMIO.new self } + getter keypad : Keypad { Keypad.new } getter bus : Bus { Bus.new self } getter interrupts : Interrupts { Interrupts.new } getter cpu : CPU { CPU.new self } @@ -36,7 +38,7 @@ class GBA when SDL::Event::Quit then exit 0 when SDL::Event::Keyboard, SDL::Event::JoyHat, - SDL::Event::JoyButton + SDL::Event::JoyButton then keypad.handle_keypad_event event else nil end end diff --git a/src/crab/keypad.cr b/src/crab/keypad.cr new file mode 100644 index 0000000..9410465 --- /dev/null +++ b/src/crab/keypad.cr @@ -0,0 +1,97 @@ +class Keypad + class KEYINPUT < BitField(UInt16) + num not_used, 6 + bool l + bool r + bool down + bool up + bool left + bool right + bool start + bool :select + bool b + bool a + end + + class KEYCNT < BitField(UInt16) + bool irq_condition + bool irq_enable + num not_used, 4 + bool l + bool r + bool down + bool up + bool left + bool right + bool start + bool :select + bool b + bool a + end + + @keyinput = KEYINPUT.new 0xFFFF_u16 + @keycnt = KEYCNT.new 0xFFFF_u16 + + def read_io(io_addr : Int) : Byte + case io_addr + when 0x130 then 0xFF_u8 & @keyinput.value + when 0x131 then 0xFF_u8 & @keyinput.value >> 8 + when 0x132 then 0xFF_u8 & @keycnt.value + when 0x133 then 0xFF_u8 & @keycnt.value >> 8 + else raise "Unimplemented keypad read ~ addr:#{hex_str io_addr.to_u8!}" + end + end + + def write_io(io_addr : Int, value : Byte) : Nil + case io_addr + when 0x130 then nil + when 0x131 then nil + else raise "Unimplemented keypad write ~ addr:#{hex_str io_addr.to_u8!}, val:#{value}" + end + end + + def handle_keypad_event(event : SDL::Event) : Nil + case event + when SDL::Event::Keyboard + bit = !event.pressed? + case event.sym + when .down?, .d? then @keyinput.down = bit + when .up?, .e? then @keyinput.up = bit + when .left?, .s? then @keyinput.left = bit + when .right?, .f? then @keyinput.right = bit + when .semicolon? then @keyinput.start = bit + when .l? then @keyinput.select = bit + when .b?, .j? then @keyinput.b = bit + when .a?, .k? then @keyinput.a = bit + when .w? then @keyinput.l = bit + when .r? then @keyinput.r = bit + else nil + end + when SDL::Event::JoyHat + @keyinput.value |= 0x00F0 + case event.value + when LibSDL::HAT_DOWN then @keyinput.down = false + when LibSDL::HAT_UP then @keyinput.up = false + when LibSDL::HAT_LEFT then @keyinput.left = false + when LibSDL::HAT_RIGHT then @keyinput.right = false + when LibSDL::HAT_LEFTUP then @keyinput.left = true; @keyinput.up = true + when LibSDL::HAT_LEFTDOWN then @keyinput.left = true; @keyinput.down = true + when LibSDL::HAT_RIGHTUP then @keyinput.right = true; @keyinput.up = true + when LibSDL::HAT_RIGHTDOWN then @keyinput.right = true; @keyinput.down = true + else nil + end + when SDL::Event::JoyButton + bit = !event.pressed? + case event.button + when 0 then @keyinput.b = bit + when 1 then @keyinput.a = bit + when 4 then @keyinput.l = bit + when 5 then @keyinput.r = bit + when 6 then @keyinput.select = bit + when 7 then @keyinput.start = bit + else nil + end + else nil + end + end +end diff --git a/src/crab/mmio.cr b/src/crab/mmio.cr index e15a48e..6a5ce83 100644 --- a/src/crab/mmio.cr +++ b/src/crab/mmio.cr @@ -8,8 +8,8 @@ class MMIO @gba.ppu.read_io io_addr elsif (io_addr >= 0x200 && io_addr <= 0x203) || (io_addr >= 0x208 && io_addr <= 0x209) @gba.interrupts.read_io io_addr - elsif io_addr >= 0x130 && io_addr <= 0x133 # todo keypad - 0xFF_u8 + elsif io_addr >= 0x130 && io_addr <= 0x133 + @gba.keypad.read_io io_addr elsif not_used? io_addr 0xFF_u8 # todo what is returned here? else @@ -23,6 +23,8 @@ class MMIO @gba.ppu.write_io io_addr, value elsif (io_addr >= 0x200 && io_addr <= 0x203) || (io_addr >= 0x208 && io_addr <= 0x209) @gba.interrupts.write_io io_addr, value + elsif io_addr >= 0x130 && io_addr <= 0x133 + @gba.keypad.read_io io_addr elsif not_used? io_addr else raise "Unmapped MMIO write: #{hex_str index.to_u32}"