From 12497caaa706e6d970065a82031e8b670a0423c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com> Date: Mon, 4 Jul 2022 16:06:59 +0100 Subject: [PATCH] feat: initial game pad support --- src/cpu.rs | 4 +-- src/gb.rs | 8 +++--- src/lib.rs | 1 + src/mmu.rs | 76 +++++++++++++++++++++++++-------------------------- src/pad.rs | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/ppu.rs | 4 +-- 6 files changed, 127 insertions(+), 45 deletions(-) create mode 100644 src/pad.rs diff --git a/src/cpu.rs b/src/cpu.rs index 4862a4b7..ceed42e7 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -28,7 +28,7 @@ pub struct Cpu { } impl Cpu { - pub fn new(mmu: Mmu) -> Cpu { + pub fn new(mmu: Mmu) -> Self { let mut implemented = 0; let mut implemented_ext = 0; @@ -55,7 +55,7 @@ impl Cpu { EXTENDED.len() ); - Cpu { + Self { pc: 0x0, sp: 0x0, a: 0x0, diff --git a/src/gb.rs b/src/gb.rs index ca34032c..286fdc4b 100644 --- a/src/gb.rs +++ b/src/gb.rs @@ -2,6 +2,7 @@ use crate::{ cpu::Cpu, data::{DMG_BOOT, SGB_BOOT}, mmu::Mmu, + pad::Pad, ppu::{Ppu, FRAME_BUFFER_SIZE}, util::read_file, }; @@ -20,11 +21,12 @@ pub struct GameBoy { #[cfg_attr(feature = "wasm", wasm_bindgen)] impl GameBoy { #[cfg_attr(feature = "wasm", wasm_bindgen(constructor))] - pub fn new() -> GameBoy { + pub fn new() -> Self { + let pad = Pad::new(); let ppu = Ppu::new(); - let mmu = Mmu::new(ppu); + let mmu = Mmu::new(ppu, pad); let cpu = Cpu::new(mmu); - GameBoy { cpu: cpu } + Self { cpu: cpu } } pub fn pc(&self) -> u16 { diff --git a/src/lib.rs b/src/lib.rs index 23d5ff7a..cd9b622a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,5 +3,6 @@ pub mod data; pub mod gb; pub mod inst; pub mod mmu; +pub mod pad; pub mod ppu; pub mod util; diff --git a/src/mmu.rs b/src/mmu.rs index ce4c54d2..2d9ace7f 100644 --- a/src/mmu.rs +++ b/src/mmu.rs @@ -1,4 +1,4 @@ -use crate::ppu::Ppu; +use crate::{pad::Pad, ppu::Ppu}; pub const BIOS_SIZE: usize = 256; pub const ROM_SIZE: usize = 32768; @@ -7,6 +7,7 @@ pub const ERAM_SIZE: usize = 8192; pub struct Mmu { ppu: Ppu, + pad: Pad, boot_active: bool, boot: [u8; BIOS_SIZE], rom: [u8; ROM_SIZE], @@ -15,9 +16,10 @@ pub struct Mmu { } impl Mmu { - pub fn new(ppu: Ppu) -> Mmu { - Mmu { + pub fn new(ppu: Ppu, pad: Pad) -> Self { + Self { ppu: ppu, + pad: pad, boot_active: true, boot: [0u8; BIOS_SIZE], rom: [0u8; ROM_SIZE], @@ -76,11 +78,14 @@ impl Mmu { self.ppu.hram[(addr & 0x007f) as usize] } else { match addr & 0x00f0 { + 0x00 => match addr & 0x00ff { + 0x00 => self.pad.read(addr), + _ => { + println!("Reading from unknown IO control 0x{:04x}", addr); + 0x00 + } + }, 0x40 | 0x50 | 0x60 | 0x70 => self.ppu.read(addr), - 0x00 => { - println!("Reading from Game Pad control 0x{:04x}", addr); - 0x00 - } _ => { println!("Reading from unknown IO control 0x{:04x}", addr); 0x00 @@ -129,41 +134,36 @@ impl Mmu { self.ram[(addr & 0x1fff) as usize] = value; } // Working RAM Shadow, I/O, Zero-page RAM - 0xf000 => { - match addr & 0x0f00 { - 0x000 | 0x100 | 0x200 | 0x300 | 0x400 | 0x500 | 0x600 | 0x700 | 0x800 - | 0x900 | 0xa00 | 0xb00 | 0xc00 | 0xd00 => { - self.ram[(addr & 0x1fff) as usize] = value; - } - 0xe00 => { - println!("Writing to PPU OAM at 0x{:04x}", addr); - } - 0xf00 => { - if addr >= 0xff80 { - self.ppu.hram[(addr & 0x007f) as usize] = value; - } else { - match addr & 0x00f0 { - 0x40 | 0x60 | 0x70 => { - self.ppu.write(addr, value); - } - 0x00 => { - println!("Writing to Game Pad, timer, etc. control 0x{:04x} := 0x{:02x}", addr, value); - } - 0x50 => match addr & 0x00ff { - 0x50 => self.boot_active = false, - _ => { - println!("Writing to unknown IO control 0x{:04x}", addr); - } - }, - _ => { - println!("Writing to unknown IO control 0x{:04x}", addr); - } + 0xf000 => match addr & 0x0f00 { + 0x000 | 0x100 | 0x200 | 0x300 | 0x400 | 0x500 | 0x600 | 0x700 | 0x800 | 0x900 + | 0xa00 | 0xb00 | 0xc00 | 0xd00 => { + self.ram[(addr & 0x1fff) as usize] = value; + } + 0xe00 => { + println!("Writing to PPU OAM at 0x{:04x}", addr); + } + 0xf00 => { + if addr >= 0xff80 { + self.ppu.hram[(addr & 0x007f) as usize] = value; + } else { + match addr & 0x00f0 { + 0x00 => match addr & 0x00ff { + 0x00 => self.pad.write(addr, value), + _ => println!("Writing to unknown IO control 0x{:04x}", addr), + }, + 0x40 | 0x60 | 0x70 => { + self.ppu.write(addr, value); } + 0x50 => match addr & 0x00ff { + 0x50 => self.boot_active = false, + _ => println!("Writing to unknown IO control 0x{:04x}", addr), + }, + _ => println!("Writing to unknown IO control 0x{:04x}", addr), } } - addr => panic!("Writing in unknown location 0x{:04x}", addr), } - } + addr => panic!("Writing in unknown location 0x{:04x}", addr), + }, addr => panic!("Writing in unknown location 0x{:04x}", addr), } } diff --git a/src/pad.rs b/src/pad.rs new file mode 100644 index 00000000..62ad7ad3 --- /dev/null +++ b/src/pad.rs @@ -0,0 +1,79 @@ +pub struct Pad { + down: bool, + up: bool, + left: bool, + right: bool, + start: bool, + select: bool, + b: bool, + a: bool, + selection: PadSelection, +} + +#[derive(Clone, Copy, PartialEq)] +pub enum PadSelection { + Action, + Direction, +} + +impl Pad { + pub fn new() -> Self { + Self { + down: false, + up: false, + left: false, + right: false, + start: false, + select: false, + b: false, + a: false, + selection: PadSelection::Action, + } + } + + pub fn read(&mut self, addr: u16) -> u8 { + match addr & 0x00ff { + 0x0000 => { + let mut value; + match self.selection { + PadSelection::Action => { + value = if self.a { 0x01 } else { 0x00 } + | if self.b { 0x02 } else { 0x00 } + | if self.select { 0x04 } else { 0x00 } + | if self.start { 0x08 } else { 0x00 } + } + PadSelection::Direction => { + value = if self.right { 0x01 } else { 0x00 } + | if self.left { 0x02 } else { 0x00 } + | if self.up { 0x04 } else { 0x00 } + | if self.down { 0x08 } else { 0x00 } + } + } + value |= if self.selection == PadSelection::Direction { + 0x00 + } else { + 0x10 + } | if self.selection == PadSelection::Action { + 0x00 + } else { + 0x20 + }; + value + } + addr => panic!("Reading from unknown Pad location 0x{:04x}", addr), + } + } + + pub fn write(&mut self, addr: u16, value: u8) { + match addr & 0x00ff { + 0x0000 => { + self.selection = if value & 0x10 == 0x00 { + PadSelection::Direction + } else { + PadSelection::Action + } + } + addr => panic!("Reading from unknown Pad location 0x{:04x}", addr), + } + } +} diff --git a/src/ppu.rs b/src/ppu.rs index c3b7667a..84c7e4b7 100644 --- a/src/ppu.rs +++ b/src/ppu.rs @@ -95,8 +95,8 @@ pub enum PpuMode { } impl Ppu { - pub fn new() -> Ppu { - Ppu { + pub fn new() -> Self { + Self { frame_buffer: Box::new([0u8; DISPLAY_WIDTH * DISPLAY_HEIGHT * RGB_SIZE]), vram: [0u8; VRAM_SIZE], hram: [0u8; HRAM_SIZE], -- GitLab