diff --git a/src/connect/renderer.rs b/src/connect/renderer.rs index 51d20ad..3d4e01d 100644 --- a/src/connect/renderer.rs +++ b/src/connect/renderer.rs @@ -8,4 +8,6 @@ pub trait Renderer { fn set_title(&mut self, _title: String) {} fn latest_joypad_state(&mut self) -> JoypadState; + + fn set_rumble(&mut self, _rumbling: bool) {} } diff --git a/src/processor/memory.rs b/src/processor/memory.rs index 9c0b264..a02ba5d 100644 --- a/src/processor/memory.rs +++ b/src/processor/memory.rs @@ -94,6 +94,10 @@ impl Memory { 0x0..0x8000 => { // change this with MBC code... self.rom.set(address, data); + if self.rom.can_rumble() { + // rumble + self.gpu.window.set_rumble(self.rom.is_rumbling()) + } } 0x8000..0xA000 => self.gpu.vram.set(address, data), 0xA000..0xC000 => self.rom.set_ram(address, data), diff --git a/src/processor/memory/rom.rs b/src/processor/memory/rom.rs index e325e8e..9df6ad4 100644 --- a/src/processor/memory/rom.rs +++ b/src/processor/memory/rom.rs @@ -40,23 +40,23 @@ impl Rom { println!("MBC3 w/battery - battery not implemented!"); Box::new(Mbc3::init(data, rom_size, 0)) } - 0x19 => Box::new(Mbc5::init(data, rom_size, 0)), - 0x1A => Box::new(Mbc5::init(data, rom_size, ram_size)), + 0x19 => Box::new(Mbc5::init(data, rom_size, 0, false)), + 0x1A => Box::new(Mbc5::init(data, rom_size, ram_size, false)), 0x1B => { println!("MBC5 w/battery - battery not implemented!"); - Box::new(Mbc5::init(data, rom_size, ram_size)) + Box::new(Mbc5::init(data, rom_size, ram_size, false)) } 0x1C => { println!("MBC5 w/rumble - rumble not implemented!"); - Box::new(Mbc5::init(data, rom_size, 0)) + Box::new(Mbc5::init(data, rom_size, 0, true)) } 0x1D => { println!("MBC5 w/rumble - rumble not implemented!"); - Box::new(Mbc5::init(data, rom_size, ram_size)) + Box::new(Mbc5::init(data, rom_size, ram_size, true)) } 0x1E => { println!("MBC5 w/rumble + battery - rumble + battery not implemented!"); - Box::new(Mbc5::init(data, rom_size, ram_size)) + Box::new(Mbc5::init(data, rom_size, ram_size, true)) } _ => panic!("unimplemented mbc: {:#X}", data[0x147]), }; @@ -83,6 +83,14 @@ impl Rom { self.mbc.set_ram(address, data); } + pub(super) fn is_rumbling(&self) -> bool { + self.mbc.is_rumbling() + } + + pub(super) fn can_rumble(&self) -> bool { + self.mbc.can_rumble() + } + pub fn mbc_type(&self) -> String { self.mbc.mbc_type() } diff --git a/src/processor/memory/rom/mbcs.rs b/src/processor/memory/rom/mbcs.rs index e1a4e2f..76813b3 100644 --- a/src/processor/memory/rom/mbcs.rs +++ b/src/processor/memory/rom/mbcs.rs @@ -21,6 +21,12 @@ pub(super) trait Mbc { fn set(&mut self, address: Address, data: u8); fn set_ram(&mut self, address: Address, data: u8); fn mbc_type(&self) -> String; + fn is_rumbling(&self) -> bool { + false + } + fn can_rumble(&self) -> bool { + false + } } fn rom_banks(rom_size: u8) -> usize { diff --git a/src/processor/memory/rom/mbcs/mbc5.rs b/src/processor/memory/rom/mbcs/mbc5.rs index 0f58c10..ba12066 100644 --- a/src/processor/memory/rom/mbcs/mbc5.rs +++ b/src/processor/memory/rom/mbcs/mbc5.rs @@ -1,4 +1,4 @@ -use crate::processor::memory::Address; +use crate::{processor::memory::Address, util::get_bit}; use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE}; @@ -10,10 +10,12 @@ pub struct Mbc5 { ram_bank: u8, ram_size: usize, ram_enabled: bool, + rumble: bool, + is_rumbling: bool, } impl Mbc5 { - pub fn init(data: Vec, rom_size: u8, ram_size: u8) -> Self { + pub fn init(data: Vec, rom_size: u8, ram_size: u8, rumble: bool) -> Self { let ram = ram_size_kb(ram_size).map(|s| vec![0; s * KB]); Self { data, @@ -23,6 +25,8 @@ impl Mbc5 { ram_bank: 0, ram_size: ram_size_kb(ram_size).map_or(1, |s| s * KB), ram_enabled: false, + rumble, + is_rumbling: false, } } @@ -66,7 +70,14 @@ impl Mbc for Mbc5 { } 0x2000..0x3000 => self.rom_bank = (self.rom_bank & 0x100) | (data as u16), 0x3000..0x4000 => self.rom_bank = (self.rom_bank & 0xFF) | ((data as u16 & 0b1) << 8), - 0x4000..0x6000 => self.ram_bank = data & 0xF, + 0x4000..0x6000 => { + if self.rumble { + self.is_rumbling = get_bit(data, 3); + self.ram_bank = data & 0x7; + } else { + self.ram_bank = data & 0xF + } + } 0x6000..0x8000 => {} _ => panic!("address {address} incompatible with MBC5"), } @@ -90,4 +101,12 @@ impl Mbc for Mbc5 { format!("{}KB MBC5", self.rom_size / KB) } } + + fn is_rumbling(&self) -> bool { + self.is_rumbling + } + + fn can_rumble(&self) -> bool { + self.rumble + } }