chore(cartridge): incremental improvements to MBC1

This commit is contained in:
Rekai Nyangadzayi Musuka 2021-06-11 14:48:21 -05:00
parent dbcab4b5ec
commit 1bc5de7cff
1 changed files with 52 additions and 45 deletions

View File

@ -32,7 +32,7 @@ impl Cartridge {
let ram_size = Self::find_ram_size(memory); let ram_size = Self::find_ram_size(memory);
let bank_count = Self::find_bank_count(memory); let bank_count = Self::find_bank_count(memory);
let mbc_kind = Self::find_mbc(memory); let mbc_kind = Self::find_mbc(memory);
let ram_byte_count = ram_size.as_byte_count(); let ram_byte_count = ram_size.len();
match mbc_kind { match mbc_kind {
MbcKind::None => Box::new(NoMbc {}), MbcKind::None => Box::new(NoMbc {}),
@ -46,6 +46,17 @@ impl Cartridge {
Box::new(mbc) Box::new(mbc)
} }
MbcKind::Mbc1WithBattery => {
// TODO: Implement Saving
let mbc = Mbc1 {
ram_size,
ram: vec![0; ram_byte_count as usize],
bank_count,
..Default::default()
};
Box::new(mbc)
}
MbcKind::Mbc3WithBattery => { MbcKind::Mbc3WithBattery => {
// TODO: Implement Saving // TODO: Implement Saving
let mbc = MBC3 { let mbc = MBC3 {
@ -101,6 +112,8 @@ impl Cartridge {
match id { match id {
0x00 => MbcKind::None, 0x00 => MbcKind::None,
0x01 => MbcKind::Mbc1, 0x01 => MbcKind::Mbc1,
0x02 => MbcKind::Mbc1,
0x03 => MbcKind::Mbc1WithBattery,
0x19 => MbcKind::Mbc5, 0x19 => MbcKind::Mbc5,
0x13 => MbcKind::Mbc3WithBattery, 0x13 => MbcKind::Mbc3WithBattery,
0x11 => MbcKind::Mbc3, 0x11 => MbcKind::Mbc3,
@ -126,8 +139,10 @@ impl BusIo for Cartridge {
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
struct Mbc1 { struct Mbc1 {
rom_bank: u8, // 5-bit Number /// 5-bit number
ram_bank: u8, // 2-bit number rom_bank: u8,
/// 2-bit number
ram_bank: u8,
mode: bool, mode: bool,
ram_size: RamSize, ram_size: RamSize,
ram: Vec<u8>, ram: Vec<u8>,
@ -136,65 +151,53 @@ struct Mbc1 {
} }
impl Mbc1 { impl Mbc1 {
fn calc_zero_bank_number(&self) -> u8 { fn zero_bank(&self) -> u8 {
use BankCount::*; use BankCount::*;
match self.bank_count { match self.bank_count {
ThirtyTwo | Sixteen | Eight | Four => 0, None | Four | Eight | Sixteen | ThirtyTwo => 0x00,
SixtyFour => (self.ram_bank & 0x01) << 5, SixtyFour => (self.ram_bank & 0x01) << 5,
OneHundredTwentyEight => self.ram_bank << 5, OneHundredTwentyEight => self.ram_bank << 5,
_ => unreachable!("{:?} is not a valid MBC1 BankCount", self.bank_count), _ => unreachable!("{:?} is not a valid MBC1 BankCount", self.bank_count),
} }
} }
fn calc_high_bank_number(&self) -> u8 { fn high_bank(&self) -> u8 {
use BankCount::*; use BankCount::*;
let less_than_mb = self.apply_rom_size_bitmask(self.rom_bank); let base = self.rom_bank & self.rom_bank_bitmask();
match self.bank_count { match self.bank_count {
None | Four | Eight | Sixteen | ThirtyTwo => less_than_mb, None | Four | Eight | Sixteen | ThirtyTwo => base,
SixtyFour => (less_than_mb & !(0x01 << 5)) | (self.ram_bank & 0x01) << 5, SixtyFour => (base & !(0x01 << 5)) | (self.ram_bank & 0x01) << 5,
OneHundredTwentyEight => (less_than_mb & !(0b11 << 5)) | (self.ram_bank & 0b11) << 5, OneHundredTwentyEight => (base & !(0x03 << 5)) | (self.ram_bank & 0x03) << 5,
_ => unreachable!("{:?} is not a valid MBC1 BankCount", self.bank_count), _ => unreachable!("{:?} is not a valid MBC1 BankCount", self.bank_count),
} }
} }
fn apply_rom_size_bitmask(&self, byte: u8) -> u8 { fn rom_bank_bitmask(&self) -> u8 {
use BankCount::*; use BankCount::*;
let err_bc = self.bank_count; // Bank Count, but with a shorter name match self.bank_count {
None => 0x1,
let result = match self.bank_count { Four => 0x03,
None => byte, // FIXME: I don't think this is the correct behaviour Eight => 0x07,
Four => byte & 0b00000011, Sixteen => 0x0F,
Eight => byte & 0b00000111, ThirtyTwo | SixtyFour | OneHundredTwentyEight => 0x1F,
Sixteen => byte & 0b00001111, _ => unreachable!("{:?} is not a valid MBC1 BankCount", self.bank_count),
ThirtyTwo => byte & 0b00011111,
SixtyFour => byte & 0b00011111,
OneHundredTwentyEight => byte & 0b00011111,
_ => unreachable!("{:?} does not have a rom size bitmask in MBC1", err_bc),
};
if result == 0 {
return 1;
} }
result
} }
fn calc_ram_address(&self, addr: u16) -> u16 { fn ram_addr(&self, addr: u16) -> usize {
use RamSize::*; use RamSize::*;
match self.ram_size { match self.ram_size {
_2KB | _8KB => { _2KB | _8KB => (addr as usize - 0xA000) % self.ram_size.len() as usize,
let ram_size = self.ram_size.as_byte_count() as u16;
(addr - 0xA000) % ram_size
}
_32KB => { _32KB => {
if self.mode { if self.mode {
0x2000 * self.ram_bank as u16 + (addr - 0xA000) 0x2000 * self.ram_bank as usize + (addr as usize - 0xA000)
} else { } else {
addr - 0xA000 addr as usize - 0xA000
} }
} }
_ => unreachable!("RAM size can not be greater than 32KB on MBC1"), _ => unreachable!("RAM size can not be greater than 32KB on MBC1"),
@ -209,20 +212,19 @@ impl MemoryBankController for Mbc1 {
match addr { match addr {
0x0000..=0x3FFF => { 0x0000..=0x3FFF => {
if self.mode { if self.mode {
let zero_bank = self.calc_zero_bank_number() as u16; let zero_bank = self.zero_bank() as usize;
Address(0x4000 * zero_bank as usize + addr as usize) Address(0x4000 * zero_bank + addr as usize)
} else { } else {
Address(addr as usize) Address(addr as usize)
} }
} }
0x4000..=0x7FFF => { 0x4000..=0x7FFF => {
let high_bank = self.calc_high_bank_number() as u16; let high_bank = self.high_bank() as usize;
Address(0x4000 * high_bank as usize + (addr as usize - 0x4000)) Address(0x4000 * high_bank + (addr as usize - 0x4000))
} }
0xA000..=0xBFFF => { 0xA000..=0xBFFF => {
if self.ram_enabled { if self.ram_enabled {
let ram_addr = self.calc_ram_address(addr); Value(self.ram[self.ram_addr(addr)])
Value(self.ram[ram_addr as usize])
} else { } else {
Value(0xFF) Value(0xFF)
} }
@ -235,14 +237,18 @@ impl MemoryBankController for Mbc1 {
match addr { match addr {
0x0000..=0x1FFF => self.ram_enabled = (byte & 0x0F) == 0x0A, 0x0000..=0x1FFF => self.ram_enabled = (byte & 0x0F) == 0x0A,
0x2000..=0x3FFF => { 0x2000..=0x3FFF => {
self.rom_bank = self.apply_rom_size_bitmask(byte); self.rom_bank = if byte == 0x00 {
0x01
} else {
byte & self.rom_bank_bitmask()
}
} }
0x4000..=0x5FFF => self.ram_bank = byte & 0b11, 0x4000..=0x5FFF => self.ram_bank = byte & 0x03,
0x6000..=0x7FFF => self.mode = (byte & 0x01) == 0x01, 0x6000..=0x7FFF => self.mode = (byte & 0x01) == 0x01,
0xA000..=0xBFFF => { 0xA000..=0xBFFF => {
if self.ram_enabled { if self.ram_enabled {
let ram_addr = self.calc_ram_address(addr); let ram_addr = self.ram_addr(addr);
self.ram[ram_addr as usize] = byte; self.ram[ram_addr] = byte;
} }
} }
_ => unreachable!("A write to {:#06X} should not be handled by MBC1", addr), _ => unreachable!("A write to {:#06X} should not be handled by MBC1", addr),
@ -365,6 +371,7 @@ enum MbcResult {
enum MbcKind { enum MbcKind {
None, None,
Mbc1, Mbc1,
Mbc1WithBattery,
Mbc5, Mbc5,
Mbc3WithBattery, Mbc3WithBattery,
Mbc3, Mbc3,
@ -387,7 +394,7 @@ enum RamSize {
} }
impl RamSize { impl RamSize {
fn as_byte_count(&self) -> u32 { fn len(&self) -> u32 {
use RamSize::*; use RamSize::*;
match *self { match *self {