2023-02-07 10:08:34 +11:00
|
|
|
use crate::processor::memory::Address;
|
|
|
|
|
|
|
|
pub(super) trait MBC {
|
|
|
|
fn get(&self, address: Address) -> u8;
|
|
|
|
fn set(&mut self, address: Address, data: u8);
|
2023-02-09 17:32:47 +11:00
|
|
|
fn mbc_type(&self) -> &str;
|
2023-02-07 10:08:34 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
pub(super) struct NONE {
|
|
|
|
pub(super) data: Vec<u8>,
|
|
|
|
}
|
|
|
|
|
2023-02-07 19:28:06 +11:00
|
|
|
impl NONE {
|
|
|
|
pub(super) fn init(data: Vec<u8>) -> Self {
|
|
|
|
Self { data }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-07 10:08:34 +11:00
|
|
|
impl MBC for NONE {
|
|
|
|
fn get(&self, address: Address) -> u8 {
|
|
|
|
self.data[address as usize]
|
|
|
|
}
|
|
|
|
|
2023-02-07 19:28:06 +11:00
|
|
|
fn set(&mut self, _address: Address, _data: u8) {
|
2023-02-07 10:08:34 +11:00
|
|
|
return;
|
|
|
|
}
|
2023-02-09 17:32:47 +11:00
|
|
|
|
|
|
|
fn mbc_type(&self) -> &str {
|
|
|
|
"None"
|
|
|
|
}
|
2023-02-07 10:08:34 +11:00
|
|
|
}
|
|
|
|
|
2023-02-07 19:28:06 +11:00
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
enum BankingMode {
|
|
|
|
RomBanking,
|
|
|
|
RamBanking,
|
|
|
|
}
|
|
|
|
|
2023-02-07 10:08:34 +11:00
|
|
|
pub(super) struct MBC1 {
|
|
|
|
pub(super) data: Vec<u8>,
|
2023-02-07 19:28:06 +11:00
|
|
|
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,
|
|
|
|
}
|
|
|
|
}
|
2023-02-07 10:08:34 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
impl MBC for MBC1 {
|
|
|
|
fn get(&self, address: Address) -> u8 {
|
2023-02-07 19:28:06 +11:00
|
|
|
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!"),
|
|
|
|
}
|
2023-02-07 10:08:34 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
fn set(&mut self, address: Address, data: u8) {
|
2023-02-07 19:28:06 +11:00
|
|
|
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
|
|
|
|
};
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
2023-02-08 08:58:56 +11:00
|
|
|
self.rom_bank = (self.rom_bank as usize % self.num_banks) as u8;
|
2023-02-07 10:08:34 +11:00
|
|
|
return;
|
|
|
|
}
|
2023-02-09 17:32:47 +11:00
|
|
|
|
|
|
|
fn mbc_type(&self) -> &str {
|
|
|
|
"MBC1"
|
|
|
|
}
|
2023-02-07 10:08:34 +11:00
|
|
|
}
|