first pass on rumble

This commit is contained in:
Alex Janka 2023-02-27 10:00:12 +11:00
parent 0417f94518
commit 6c60438da7
5 changed files with 48 additions and 9 deletions

View file

@ -8,4 +8,6 @@ pub trait Renderer {
fn set_title(&mut self, _title: String) {} fn set_title(&mut self, _title: String) {}
fn latest_joypad_state(&mut self) -> JoypadState; fn latest_joypad_state(&mut self) -> JoypadState;
fn set_rumble(&mut self, _rumbling: bool) {}
} }

View file

@ -94,6 +94,10 @@ impl Memory {
0x0..0x8000 => { 0x0..0x8000 => {
// change this with MBC code... // change this with MBC code...
self.rom.set(address, data); 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), 0x8000..0xA000 => self.gpu.vram.set(address, data),
0xA000..0xC000 => self.rom.set_ram(address, data), 0xA000..0xC000 => self.rom.set_ram(address, data),

View file

@ -40,23 +40,23 @@ impl Rom {
println!("MBC3 w/battery - battery not implemented!"); println!("MBC3 w/battery - battery not implemented!");
Box::new(Mbc3::init(data, rom_size, 0)) Box::new(Mbc3::init(data, rom_size, 0))
} }
0x19 => Box::new(Mbc5::init(data, rom_size, 0)), 0x19 => Box::new(Mbc5::init(data, rom_size, 0, false)),
0x1A => Box::new(Mbc5::init(data, rom_size, ram_size)), 0x1A => Box::new(Mbc5::init(data, rom_size, ram_size, false)),
0x1B => { 0x1B => {
println!("MBC5 w/battery - battery not implemented!"); 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 => { 0x1C => {
println!("MBC5 w/rumble - rumble not implemented!"); 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 => { 0x1D => {
println!("MBC5 w/rumble - rumble not implemented!"); 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 => { 0x1E => {
println!("MBC5 w/rumble + battery - rumble + battery not implemented!"); 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]), _ => panic!("unimplemented mbc: {:#X}", data[0x147]),
}; };
@ -83,6 +83,14 @@ impl Rom {
self.mbc.set_ram(address, data); 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 { pub fn mbc_type(&self) -> String {
self.mbc.mbc_type() self.mbc.mbc_type()
} }

View file

@ -21,6 +21,12 @@ pub(super) trait Mbc {
fn set(&mut self, address: Address, data: u8); fn set(&mut self, address: Address, data: u8);
fn set_ram(&mut self, address: Address, data: u8); fn set_ram(&mut self, address: Address, data: u8);
fn mbc_type(&self) -> String; fn mbc_type(&self) -> String;
fn is_rumbling(&self) -> bool {
false
}
fn can_rumble(&self) -> bool {
false
}
} }
fn rom_banks(rom_size: u8) -> usize { fn rom_banks(rom_size: u8) -> usize {

View file

@ -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}; 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_bank: u8,
ram_size: usize, ram_size: usize,
ram_enabled: bool, ram_enabled: bool,
rumble: bool,
is_rumbling: bool,
} }
impl Mbc5 { impl Mbc5 {
pub fn init(data: Vec<u8>, rom_size: u8, ram_size: u8) -> Self { pub fn init(data: Vec<u8>, rom_size: u8, ram_size: u8, rumble: bool) -> Self {
let ram = ram_size_kb(ram_size).map(|s| vec![0; s * KB]); let ram = ram_size_kb(ram_size).map(|s| vec![0; s * KB]);
Self { Self {
data, data,
@ -23,6 +25,8 @@ impl Mbc5 {
ram_bank: 0, ram_bank: 0,
ram_size: ram_size_kb(ram_size).map_or(1, |s| s * KB), ram_size: ram_size_kb(ram_size).map_or(1, |s| s * KB),
ram_enabled: false, 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), 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), 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 => {} 0x6000..0x8000 => {}
_ => panic!("address {address} incompatible with MBC5"), _ => panic!("address {address} incompatible with MBC5"),
} }
@ -90,4 +101,12 @@ impl Mbc for Mbc5 {
format!("{}KB MBC5", self.rom_size / KB) format!("{}KB MBC5", self.rom_size / KB)
} }
} }
fn is_rumbling(&self) -> bool {
self.is_rumbling
}
fn can_rumble(&self) -> bool {
self.rumble
}
} }