From aeab98baaf21317d0dc91a5bfde8efb2fbd7998c Mon Sep 17 00:00:00 2001 From: Colby Date: Tue, 2 Aug 2016 23:44:46 +1000 Subject: [PATCH] add support for the joypad --- lib/waterfoul.rb | 1 + lib/waterfoul/emulator.rb | 6 +++- lib/waterfoul/input.rb | 65 +++++++++++++++++++++++++++++++++++++++ lib/waterfoul/mmu.rb | 5 +-- lib/waterfoul/screen.rb | 2 -- 5 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 lib/waterfoul/input.rb diff --git a/lib/waterfoul.rb b/lib/waterfoul.rb index 7acc8ec..0187aec 100644 --- a/lib/waterfoul.rb +++ b/lib/waterfoul.rb @@ -12,6 +12,7 @@ require "waterfoul/screen" require "waterfoul/gpu" require "waterfoul/cartridge" require "waterfoul/emulator" +require "waterfoul/input" require "byebug" module Waterfoul diff --git a/lib/waterfoul/emulator.rb b/lib/waterfoul/emulator.rb index b480d2a..2a96186 100644 --- a/lib/waterfoul/emulator.rb +++ b/lib/waterfoul/emulator.rb @@ -1,7 +1,9 @@ -require 'pp' +require 'sdl2' + module Waterfoul class Emulator def initialize(rom_filename, options = {}) + SDL2.init SDL2::INIT_EVERYTHING # read the rom into host memory rom = read_program(rom_filename).bytes # initialize emulated CPU, GPU & Sound components @@ -12,6 +14,7 @@ module Waterfoul cpu = CPU.new @cpu = options.has_key?('skip_boot') ? SkipBoot.set_state(cpu) : cpu @gpu = GPU.new + @input = Input.new @screen = Screen.new # @sound = Sound.new end @@ -21,6 +24,7 @@ module Waterfoul @cpu.step @gpu.step @cpu.m @screen.render @gpu.framebuffer if @gpu.vblank? + @input.step @cpu.m # @sound.step end end diff --git a/lib/waterfoul/input.rb b/lib/waterfoul/input.rb new file mode 100644 index 0000000..248f5d3 --- /dev/null +++ b/lib/waterfoul/input.rb @@ -0,0 +1,65 @@ +require 'sdl2' + +module Waterfoul + class Input + + UP_INPUT_KEYCODE = 82 + DOWN_INPUT_KEYCODE = 81 + LEFT_INPUT_KEYCODE = 80 + RIGHT_INPUT_KEYCODE = 79 + A_INPUT_KEYCODE = 4 + B_INPUT_KEYCODE = 5 + START_INPUT_KEYCODE = 40 + SELECT_INPUT_KEYCODE = 229 + POLL_RATE = 65536 + + def initialize + @modeclock = 0 + @current_key = 0 + $mmu.write_byte 0xFF00, 0x3F, hardware_operation: true + end + + def step(cycles = 1) + @modeclock =+ cycles + event = SDL2::Event.poll + if @modeclock >= POLL_RATE + @modeclock -= POLL_RATE + + return unless @current_key > 0 + joypad_byte = $mmu.read_byte 0xFF00 + key_byte = 0x3F + + if joypad_byte & 0x10 == 0x00 + case @current_key + when UP_INPUT_KEYCODE + key_byte ^= 0x4 + when DOWN_INPUT_KEYCODE + key_byte ^= 0x8 + when RIGHT_INPUT_KEYCODE + key_byte ^= 0x1 + when LEFT_INPUT_KEYCODE + key_byte ^= 0x2 + end + p "bar!" + elsif joypad_byte & 0x20 == 0x00 + case @current_key + when A_INPUT_KEYCODE + key_byte ^= 0x1 + when B_INPUT_KEYCODE + key_byte ^= 0x2 + when START_INPUT_KEYCODE + key_byte ^= 0x8 + when SELECT_INPUT_KEYCODE + key_byte ^= 0x4 + end + p "foo!" + end + + $mmu.write_byte 0xFF00, (joypad_byte & key_byte), hardware_operation: true + Interrupt.request_interrupt Interrupt::INTERRUPT_JOYPAD + elsif event.kind_of? SDL2::Event::KeyDown + @current_key = event.scancode + end + end + end +end diff --git a/lib/waterfoul/mmu.rb b/lib/waterfoul/mmu.rb index 6b01046..765b044 100644 --- a/lib/waterfoul/mmu.rb +++ b/lib/waterfoul/mmu.rb @@ -35,8 +35,6 @@ module Waterfoul raise MemoryOutOfBounds if i > MEMORY_SIZE || i < 0 case i - when 0xFF00 - 0xFF when 0x0000...0x8000 # ROM Bank 0 + n if @map_boot_rom && i <= BOOT_ROM_END_MEM_LOC BootROM[i] @@ -68,6 +66,9 @@ module Waterfoul case i when UNMAP_BOOT_ROM_MEM_LOC # unmap the boot rom when 0xFF50 is wrtiten to in memory @map_boot_rom = false if v == 0x1 && @map_boot_rom + when 0xFF00 + current = self[0xFF00] + @memory[0xFF00] = (current & 0xF) | (v & 0x30) when 0xFF46 # DMA transfer dma_transfer v @memory[i] = v diff --git a/lib/waterfoul/screen.rb b/lib/waterfoul/screen.rb index 68da993..e5d3c95 100644 --- a/lib/waterfoul/screen.rb +++ b/lib/waterfoul/screen.rb @@ -1,4 +1,3 @@ -require 'sdl2' require 'waterfoul/io/lcd_status' module Waterfoul @@ -15,7 +14,6 @@ module Waterfoul } def initialize - SDL2.init SDL2::INIT_VIDEO @screen = SDL2::Window.create('main', 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0) @renderer = @screen.create_renderer 1, 0 @lcd_status = IO::LCDStatus.new