gb-emu/src/processor/memory/rom/mbcs.rs

200 lines
5.3 KiB
Rust
Raw Normal View History

2023-02-07 10:08:34 +11:00
use crate::processor::memory::Address;
2023-02-12 09:46:47 +11:00
pub(super) trait Mbc {
2023-02-07 10:08:34 +11:00
fn get(&self, address: Address) -> u8;
2023-02-11 21:43:36 +11:00
fn get_ram(&self, address: Address) -> u8;
2023-02-07 10:08:34 +11:00
fn set(&mut self, address: Address, data: u8);
2023-02-11 21:43:36 +11:00
fn set_ram(&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
}
2023-02-12 09:46:47 +11:00
pub(super) struct None {
2023-02-07 10:08:34 +11:00
pub(super) data: Vec<u8>,
}
2023-02-12 09:46:47 +11:00
impl None {
2023-02-07 19:28:06 +11:00
pub(super) fn init(data: Vec<u8>) -> Self {
Self { data }
}
}
2023-02-12 09:46:47 +11:00
impl Mbc for None {
2023-02-07 10:08:34 +11:00
fn get(&self, address: Address) -> u8 {
self.data[address as usize]
}
2023-02-11 21:43:36 +11:00
fn get_ram(&self, _address: Address) -> u8 {
0xFF
}
fn set_ram(&mut self, _address: Address, _data: u8) {}
2023-02-12 09:46:47 +11:00
fn set(&mut self, _address: Address, _data: u8) {}
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 {
2023-02-11 21:43:36 +11:00
Simple,
Advanced,
2023-02-07 19:28:06 +11:00
}
2023-02-12 09:46:47 +11:00
pub(super) struct Mbc1 {
2023-02-07 10:08:34 +11:00
pub(super) data: Vec<u8>,
2023-02-11 21:43:36 +11:00
rom_len: usize,
2023-02-07 19:28:06 +11:00
rom_bank: u8,
2023-02-11 21:43:36 +11:00
ram_enabled: bool,
ram: Option<Vec<u8>>,
ram_bank: u8,
upper_banks: u8,
bank_mode: BankingMode,
2023-02-07 19:28:06 +11:00
}
2023-02-11 21:43:36 +11:00
const KB: usize = 1024;
const ROM_BANK_SIZE: usize = 16 * KB;
const RAM_BANK_SIZE: usize = 8 * KB;
2023-02-12 09:46:47 +11:00
impl Mbc1 {
2023-02-11 21:43:36 +11:00
pub(super) fn init(
data: Vec<u8>,
rom_size: u8,
ram_size: u8,
_save_file: Option<Vec<u8>>,
) -> Self {
let rom_len = match rom_size {
2023-02-07 19:28:06 +11:00
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"),
2023-02-11 21:43:36 +11:00
} * ROM_BANK_SIZE;
// in kb
let ram = match ram_size {
0x00 => None,
0x01 => Some(vec![0; 2 * KB]),
0x02 => Some(vec![0; 8 * KB]),
0x03 => Some(vec![0; 32 * KB]),
0x04 => Some(vec![0; 128 * KB]),
0x05 => Some(vec![0; 64 * KB]),
_ => panic!("unacceptable ram size"),
2023-02-07 19:28:06 +11:00
};
Self {
data,
2023-02-11 21:43:36 +11:00
rom_len,
2023-02-07 19:28:06 +11:00
rom_bank: 0x1,
2023-02-11 21:43:36 +11:00
ram_enabled: false,
ram,
ram_bank: 0,
upper_banks: 0,
bank_mode: BankingMode::Simple,
2023-02-07 19:28:06 +11:00
}
}
2023-02-07 10:08:34 +11:00
}
2023-02-12 09:46:47 +11:00
impl Mbc for Mbc1 {
2023-02-07 10:08:34 +11:00
fn get(&self, address: Address) -> u8 {
2023-02-11 21:43:36 +11:00
self.data[self.get_rom_addr(address)]
}
fn get_ram(&self, address: Address) -> u8 {
if self.ram_enabled && let Some(ram) = &self.ram {
let addr = self.get_ram_addr(address)%ram.len();
return ram[addr];
}
0xFF
}
fn set_ram(&mut self, address: Address, data: u8) {
let mut addr = self.get_ram_addr(address);
if self.ram_enabled && let Some(ram) = &mut self.ram {
2023-02-12 09:41:34 +11:00
addr %= ram.len();
2023-02-11 21:43:36 +11:00
ram[addr] = data;
2023-02-07 19:28:06 +11:00
}
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;
}
2023-02-11 21:43:36 +11:00
self.rom_bank = set_data;
2023-02-07 19:28:06 +11:00
}
0x4000..0x6000 => {
// ram bank OR upper bits 5 & 6 of rom bank
2023-02-11 21:43:36 +11:00
self.upper_banks = data & 0b11;
2023-02-07 19:28:06 +11:00
}
0x6000..0x8000 => {
// mode select
self.bank_mode = if data == 0x1 {
2023-02-11 21:43:36 +11:00
BankingMode::Advanced
2023-02-07 19:28:06 +11:00
} else if data == 0x0 {
2023-02-11 21:43:36 +11:00
BankingMode::Simple
2023-02-07 19:28:06 +11:00
} else {
self.bank_mode
};
}
_ => {}
}
2023-02-07 10:08:34 +11:00
}
2023-02-09 17:32:47 +11:00
fn mbc_type(&self) -> &str {
"MBC1"
}
2023-02-07 10:08:34 +11:00
}
2023-02-11 21:43:36 +11:00
2023-02-12 09:46:47 +11:00
impl Mbc1 {
2023-02-11 21:43:36 +11:00
fn get_rom_addr(&self, address: Address) -> usize {
(match address {
0x0..0x4000 => match self.bank_mode {
BankingMode::Simple => address as usize,
BankingMode::Advanced => {
(address as usize) + (self.upper_banks as usize * 512 * KB)
}
},
0x4000..0x8000 => {
(address - 0x4000) as usize
+ (ROM_BANK_SIZE * self.rom_bank as usize)
+ (self.upper_banks as usize * 512 * KB)
}
0xA000..0xC000 => panic!("passed ram address to rom address function"),
_ => panic!("address {address} incompatible with MBC1"),
} % self.rom_len)
}
fn get_ram_addr(&self, address: Address) -> usize {
match address {
0x0..0x8000 => panic!("passed rom address to ram address function"),
0xA000..0xC000 => match self.bank_mode {
BankingMode::Simple => {
(address - 0xA000) as usize + (RAM_BANK_SIZE * self.ram_bank as usize)
}
BankingMode::Advanced => {
(address - 0xA000) as usize
+ (RAM_BANK_SIZE * self.ram_bank as usize)
+ (self.upper_banks as usize * 16 * KB)
}
},
_ => panic!("address {address} incompatible with MBC1"),
}
}
}