mbc support

This commit is contained in:
Alex Janka 2023-02-07 19:28:06 +11:00
parent 5ef4e8c792
commit 89370fd077
2 changed files with 81 additions and 5 deletions

View file

@ -22,11 +22,11 @@ impl ROM {
let title = unsafe { from_utf8_unchecked(&data[0x134..title_length]).to_string() };
let _gbc_flag = data[0x143];
let _sgb_flag = data[0x146];
let _rom_size = data[0x148];
let rom_size = data[0x148];
let _ram_size = data[0x149];
let mbc: Box<dyn MBC> = match data[0x147] {
0x00 => Box::new(NONE { data }),
0x01 => Box::new(MBC1 { data }),
0x00 => Box::new(NONE::init(data)),
0x01 => Box::new(MBC1::init(data, rom_size)),
_ => panic!("unimplemented mbc: {:#X}", data[0x147]),
};
Self { title, mbc }

View file

@ -9,26 +9,102 @@ pub(super) struct NONE {
pub(super) data: Vec<u8>,
}
impl NONE {
pub(super) fn init(data: Vec<u8>) -> Self {
Self { data }
}
}
impl MBC for NONE {
fn get(&self, address: Address) -> u8 {
self.data[address as usize]
}
fn set(&mut self, address: Address, data: u8) {
fn set(&mut self, _address: Address, _data: u8) {
return;
}
}
#[derive(Clone, Copy)]
enum BankingMode {
RomBanking,
RamBanking,
}
pub(super) struct MBC1 {
pub(super) data: Vec<u8>,
num_banks: usize,
bank_mode: BankingMode,
ram_enabled: bool,
rom_bank: u8,
}
impl MBC1 {
pub(super) fn init(data: Vec<u8>, rom_size: u8) -> Self {
let num_banks = match rom_size {
0x00 => 2,
0x01 => 4,
0x02 => 8,
0x03 => 16,
0x04 => 32,
0x05 => 64,
0x06 => 128,
0x07 => 256,
0x08 => 512,
0x52 => 72,
0x53 => 80,
0x54 => 96,
_ => panic!("unacceptable rom size"),
};
Self {
data,
num_banks,
bank_mode: BankingMode::RomBanking,
ram_enabled: false,
rom_bank: 0x1,
}
}
}
impl MBC for MBC1 {
fn get(&self, address: Address) -> u8 {
self.data[address as usize]
match address {
0x0..0x4000 => self.data[address as usize],
0x4000..0x8000 => self.data[address as usize - (self.rom_bank as usize * 0x4000)],
_ => panic!("address too big for rom!"),
}
}
fn set(&mut self, address: Address, data: u8) {
match address {
0x0..0x2000 => {
// enable/disable ram
self.ram_enabled = (data & 0x0F) == 0xA;
}
0x2000..0x4000 => {
// rom bank number - lower 5 bits
let mut set_data = data & 0b00011111;
if set_data == 0 {
set_data = 1;
}
self.rom_bank = (self.rom_bank & 0b11100000) | set_data;
}
0x4000..0x6000 => {
// ram bank OR upper bits 5 & 6 of rom bank
self.rom_bank = (self.rom_bank & 0b00011111) | ((data & 0b00000011) << 5);
}
0x6000..0x8000 => {
// mode select
self.bank_mode = if data == 0x1 {
BankingMode::RamBanking
} else if data == 0x0 {
BankingMode::RomBanking
} else {
self.bank_mode
};
}
_ => {}
}
return;
}
}