diff --git a/src/mbc/mbc1.rs b/src/mbc/mbc1.rs index 65fb46f..1ce277c 100644 --- a/src/mbc/mbc1.rs +++ b/src/mbc/mbc1.rs @@ -1,16 +1,17 @@ use super::mbc::MBC; +enum BankMode { + RomBankMode, + RamBankMode, +} + pub struct MBC1 { rom: Box<[u8]>, ram: Box<[u8]>, - bank_no: u8, - ram_rtc_enabled: bool, - ram_bank_no: u8, - - rom_banks: u16, - - bank_mode: u8, + rom_bank_no: u8, + bank_mode: BankMode, bank_no_high: u8, + ram_enable: bool, } impl MBC1 { @@ -18,15 +19,28 @@ impl MBC1 { MBC1 { rom: rom, ram: ram, - bank_no: 0, - ram_rtc_enabled: false, - ram_bank_no: 0, - rom_banks: 0, - bank_mode: 0, + rom_bank_no: 0, + bank_mode: BankMode::RomBankMode, bank_no_high: 0, + + ram_enable: false, } } -} + + fn active_rom_bank(&self) -> u8 { + match self.bank_mode { + BankMode::RomBankMode => self.rom_bank_no | self.bank_no_high << 5, + BankMode::RamBankMode => self.rom_bank_no + } + } + + fn active_ram_bank(&self) -> u8 { + match self.bank_mode { + BankMode::RomBankMode => 0, + BankMode::RamBankMode => self.bank_no_high + } + } + } impl MBC for MBC1 { fn read_byte(&self, addr: u16) -> u8 { @@ -34,21 +48,14 @@ impl MBC for MBC1 { 0x0000 ... 0x3FFF => self.rom[addr as usize], 0x4000 ... 0x7FFF => { let addr = addr - 0x4000; - // println!("BankNo: {:02X}", self.bank_no); - let abs_addr: usize = addr as usize + self.bank_no as usize * 0x4000; + let abs_addr: usize = addr as usize + self.active_rom_bank() as usize * 0x4000; let val: u8 = self.rom[abs_addr]; val }, 0xA000 ... 0xBFFF => { - // TODO: Safty checks? Or let rust handle this? let addr = addr - 0xA000; - if self.ram_bank_no < 4 { - println!("Access [{:02X}] {:04X}", self.ram_bank_no, addr); - self.ram[self.ram_bank_no as usize * 0x2000 + addr as usize] - } else { - println!("Ignoring RTC read"); - 0 - } + println!("Access [{:02X}] {:04X}", self.active_ram_bank(), addr); + self.ram[self.active_ram_bank() as usize * 0x2000 + addr as usize] } _ => { panic!("Cartride: Unable to read from {:04X}", addr); @@ -60,33 +67,31 @@ impl MBC for MBC1 { match addr { 0x0000 ... 0x1FFF => { match val { - 0x0A => self.ram_rtc_enabled = true, - 0x00 => self.ram_rtc_enabled = false, - _ => println!("Unknown MBC value {:02X} for {:04X}", val, addr) + 0x0A => self.ram_enable = true, + 0x00 => self.ram_enable = false, + _ => println!("Unknown MBC1 value {:02X} for {:04X}", val, addr) } }, - 0x2000 ... 0x3FFF => self.bank_no = val & 0x7F, - 0x4000 ... 0x5FFF => { - // RAM bank select - match val { - 0x00 ... 0x03 => self.ram_bank_no = 0, //val, - 0x08 ... 0x0C => self.ram_bank_no = val, // RTC clock values, TODO - _ => panic!("Unknown MBC1 RAM BANK NO: {:02X}", val) - } - - }, - 0x6000 ... 0x7FFF => { - // Latch clock data, ignore. - }, - 0xA000 ... 0xBFFF => { - // TODO: Safty checks? Or let rust handle this? - let addr = addr - 0xA000; - if self.ram_bank_no < 4 { - self.ram[self.ram_bank_no as usize * 0x2000 + addr as usize] = val; + 0x2000 ... 0x3FFF => { + println!("Selecting bank {:02X}", self.rom_bank_no); + if val != 0 { + self.rom_bank_no = val & 0x1F; } else { - println!("Ignoring RTC write"); + self.rom_bank_no = 1; // 0x00 -> 0x01, 0x20 -> 0x21 etc } } + 0x4000 ... 0x5FFF => { + // Upper ROM bank / RAM bank select + self.bank_no_high = val & 3; + }, + 0x6000 ... 0x7FFF => { + // Select upper ROM bytes or RAM bytes + match val { + 0 => self.bank_mode = BankMode::RomBankMode, + 1 => self.bank_mode = BankMode::RamBankMode, + _ => panic!("Invalid bank mode {:02X}", val), + } + }, _ => panic!("MBC1: Writing {:02X} to {:04X} not supported", val, addr), } }