diff --git a/src/processor/memory/rom/mbcs.rs b/src/processor/memory/rom/mbcs.rs index f867123..6ccbe4c 100644 --- a/src/processor/memory/rom/mbcs.rs +++ b/src/processor/memory/rom/mbcs.rs @@ -1,5 +1,10 @@ use crate::processor::memory::Address; +mod mbc1; +mod none; +pub use mbc1::Mbc1; +pub use none::None; + pub(super) trait Mbc { fn get(&self, address: Address) -> u8; fn get_ram(&self, address: Address) -> u8; @@ -8,194 +13,8 @@ pub(super) trait Mbc { fn mbc_type(&self) -> String; } -pub(super) struct None { - pub(super) data: Vec, -} - -impl None { - pub(super) fn init(data: Vec) -> Self { - Self { data } - } -} - -impl Mbc for None { - fn get(&self, address: Address) -> u8 { - self.data[address as usize] - } - - fn get_ram(&self, _address: Address) -> u8 { - 0xFF - } - - fn set_ram(&mut self, _address: Address, _data: u8) {} - - fn set(&mut self, _address: Address, _data: u8) {} - - fn mbc_type(&self) -> String { - String::from("None") - } -} - #[derive(Clone, Copy)] enum BankingMode { Simple, Advanced, } - -pub(super) struct Mbc1 { - pub(super) data: Vec, - rom_len: usize, - rom_bank: u8, - ram_enabled: bool, - ram: Option>, - ram_bank: u8, - upper_banks: u8, - bank_mode: BankingMode, -} - -const KB: usize = 1024; -const ROM_BANK_SIZE: usize = 16 * KB; -const RAM_BANK_SIZE: usize = 8 * KB; - -impl Mbc1 { - pub(super) fn init( - data: Vec, - rom_size: u8, - ram_size: u8, - _save_file: Option>, - ) -> Self { - let rom_len = 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"), - } * 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"), - }; - Self { - data, - rom_len, - rom_bank: 0x1, - ram_enabled: false, - ram, - ram_bank: 0, - upper_banks: 0, - bank_mode: BankingMode::Simple, - } - } -} - -impl Mbc for Mbc1 { - fn get(&self, address: Address) -> u8 { - 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 { - addr %= ram.len(); - ram[addr] = data; - } - } - - 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 = set_data; - } - 0x4000..0x6000 => { - // ram bank OR upper bits 5 & 6 of rom bank - self.upper_banks = data & 0b11; - } - 0x6000..0x8000 => { - // mode select - self.bank_mode = if (data & 0x1) == 0x1 { - BankingMode::Advanced - } else { - BankingMode::Simple - }; - } - _ => {} - } - } - - fn mbc_type(&self) -> String { - if let Some(ram) = &self.ram { - format!("{}KB MBC1 with {}KB RAM", self.rom_len / KB, ram.len() / KB) - } else { - format!("{}KB MBC1", self.rom_len / KB) - } - } -} - -impl Mbc1 { - 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"), - } - } -} diff --git a/src/processor/memory/rom/mbcs/mbc1.rs b/src/processor/memory/rom/mbcs/mbc1.rs new file mode 100644 index 0000000..dd6051b --- /dev/null +++ b/src/processor/memory/rom/mbcs/mbc1.rs @@ -0,0 +1,155 @@ +use super::{BankingMode, Mbc}; +use crate::processor::memory::Address; + +pub struct Mbc1 { + pub data: Vec, + rom_len: usize, + rom_bank: u8, + ram_enabled: bool, + ram: Option>, + ram_bank: u8, + upper_banks: u8, + bank_mode: BankingMode, +} + +const KB: usize = 1024; +const ROM_BANK_SIZE: usize = 16 * KB; +const RAM_BANK_SIZE: usize = 8 * KB; + +impl Mbc1 { + pub fn init(data: Vec, rom_size: u8, ram_size: u8, _save_file: Option>) -> Self { + let rom_len = 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"), + } * 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"), + }; + Self { + data, + rom_len, + rom_bank: 0x1, + ram_enabled: false, + ram, + ram_bank: 0, + upper_banks: 0, + bank_mode: BankingMode::Simple, + } + } +} + +impl Mbc for Mbc1 { + fn get(&self, address: Address) -> u8 { + 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 { + addr %= ram.len(); + ram[addr] = data; + } + } + + 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 = set_data; + } + 0x4000..0x6000 => { + // ram bank OR upper bits 5 & 6 of rom bank + self.upper_banks = data & 0b11; + } + 0x6000..0x8000 => { + // mode select + self.bank_mode = if (data & 0x1) == 0x1 { + BankingMode::Advanced + } else { + BankingMode::Simple + }; + } + _ => {} + } + } + + fn mbc_type(&self) -> String { + if let Some(ram) = &self.ram { + format!("{}KB MBC1 with {}KB RAM", self.rom_len / KB, ram.len() / KB) + } else { + format!("{}KB MBC1", self.rom_len / KB) + } + } +} + +impl Mbc1 { + 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"), + } + } +} diff --git a/src/processor/memory/rom/mbcs/none.rs b/src/processor/memory/rom/mbcs/none.rs new file mode 100644 index 0000000..1d232b3 --- /dev/null +++ b/src/processor/memory/rom/mbcs/none.rs @@ -0,0 +1,30 @@ +use super::Mbc; +use crate::processor::memory::Address; + +pub struct None { + pub(super) data: Vec, +} + +impl None { + pub fn init(data: Vec) -> Self { + Self { data } + } +} + +impl Mbc for None { + fn get(&self, address: Address) -> u8 { + self.data[address as usize] + } + + fn get_ram(&self, _address: Address) -> u8 { + 0xFF + } + + fn set_ram(&mut self, _address: Address, _data: u8) {} + + fn set(&mut self, _address: Address, _data: u8) {} + + fn mbc_type(&self) -> String { + String::from("None") + } +}