From 3458d4b7d90e318334a7e531630a28ea14bc6d18 Mon Sep 17 00:00:00 2001 From: Kevin Hamacher Date: Sun, 29 May 2016 22:04:22 +0200 Subject: [PATCH] Split MBC logic --- src/cartridge.rs | 180 +++++--------------------------------------- src/cpu.rs | 13 ++-- src/display.rs | 8 +- src/interconnect.rs | 8 +- src/main.rs | 2 + src/mbc/mbc.rs | 40 ++++++++++ src/mbc/mbc3.rs | 93 +++++++++++++++++++++++ src/mbc/mod.rs | 2 + 8 files changed, 173 insertions(+), 173 deletions(-) create mode 100644 src/mbc/mbc.rs create mode 100644 src/mbc/mbc3.rs create mode 100644 src/mbc/mod.rs diff --git a/src/cartridge.rs b/src/cartridge.rs index a8a0ccb..f1ad753 100644 --- a/src/cartridge.rs +++ b/src/cartridge.rs @@ -1,3 +1,5 @@ +use super::mbc::mbc::MBC; + #[derive(Debug,PartialEq)] enum MemoryBankControllerType { None, @@ -16,32 +18,22 @@ enum RamSize { } pub struct Cartridge { - rom: Box<[u8]>, - ram: Box<[u8]>, - bank_no: u8, mbc_type: MemoryBankControllerType, - ram_rtc_enabled: bool, - ram_bank_no: u8, - - ram_size: RamSize, - rom_banks: u16, - - bank_mode: u8, - bank_no_high: u8, + mbc: Box, } impl Cartridge { pub fn new(rom: Box<[u8]>) -> Cartridge { - let mbc: MemoryBankControllerType = match rom[0x0147] { + let mbc_type: MemoryBankControllerType = match rom[0x0147] { 0x00 | 0x08 ... 0x09 => MemoryBankControllerType::None, - 0x01 ... 0x03 => MemoryBankControllerType::MBC1, - 0x05 ... 0x06 => MemoryBankControllerType::MBC2, + // 0x01 ... 0x03 => MemoryBankControllerType::MBC1, + // 0x05 ... 0x06 => MemoryBankControllerType::MBC2, 0x0F ... 0x13 => MemoryBankControllerType::MBC3, - 0xFF => MemoryBankControllerType::HuC1, + // 0xFF => MemoryBankControllerType::HuC1, _ => panic!("Unsupported MBC type: {:02X}", rom[0x0147]), }; - println!("MBC Type: {:?}", &mbc); + println!("MBC Type: {:?}", &mbc_type); let rom_banks: u16 = match rom[0x0148] { 0x00 => 0, @@ -70,157 +62,23 @@ impl Cartridge { RamSize::Ram32KB => vec![0u8; 16 * 2048].into_boxed_slice(), }; + let mbc: Box = match mbc_type { + MemoryBankControllerType::None => Box::new(super::mbc::mbc::NoMBC::new(rom, ram)), + MemoryBankControllerType::MBC3 => Box::new(super::mbc::mbc3::MBC3::new(rom, ram)), + _ => panic!("{:?} not implemented", mbc_type), + }; + Cartridge { - rom: rom, - mbc_type: mbc, - bank_no: 1, - - ram_rtc_enabled: false, - ram_bank_no: 0, - ram_size: ram_size, - rom_banks: rom_banks, - - ram: ram, - bank_mode: 0, - bank_no_high: 0, + mbc: mbc, + mbc_type: mbc_type, } } - pub fn read_byte_mbc3(&self, addr: u16) -> u8 { - match addr { - 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 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 { - self.ram[self.ram_bank_no as usize * 0x2000 + addr as usize] - } else { - println!("Ignoring RTC read"); - 0 - } - } - _ => { - panic!("Cartride: Unable to read from {:04X}", addr); - } - } - } - - pub fn read_byte_mbc1(&self, addr: u16) -> u8 { - match addr { - 0x0000 ... 0x3FFF => self.rom[addr as usize], - 0x4000 ... 0x7FFF => { - let addr = addr - 0x4000; - let mut bank: u8 = self.bank_no; - if self.bank_mode == 0 { - bank |= self.bank_no_high << 5; - } - // println!("BankNo: {:02X}", bank); - let abs_addr: usize = addr as usize + 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; - let mut bank: u8 = 0; - if self.bank_mode == 1 { - bank = self.bank_no_high - } - - self.ram[bank as usize * 0x2000 + addr as usize] - } - _ => { - panic!("Cartride: Unable to read from {:04X}", addr); - } - } - } - pub fn read_byte(&self, addr: u16) -> u8{ - match self.mbc_type { - MemoryBankControllerType::MBC1 => self.read_byte_mbc1(addr), - MemoryBankControllerType::MBC3 | MemoryBankControllerType::None => self.read_byte_mbc3(addr), - _ => panic!("MBC not supported.") - } - } - - fn write_byte_none(&mut self, addr: u16, val: u8) { - match addr { - 0xA000 ... 0xBFFF => { - // self.ram[addr as usize - 0xA000] = val; - println!("No MBC, ignoring RAM write {:02X} to {:04X}", val, addr); - } - _ => println!("No MBC, unable to write {:02X} to {:04X}", val, addr), - } - } - - fn write_byte_mbc1(&mut self, addr: u16, val: u8) { - match addr { - 0x2000 ... 0x3FFF => { - // Write low bits of addr. - self.bank_no &= 0xE0; - self.bank_no |= val & 0x1F; - - // Can't select 0x00, 0x20, 0x40, 0x60. Adapt it to 0x01, 0x21, 0x41, 0x61 - if self.bank_no & 0x1F == 0 { - self.bank_no |= 1; - } - } - 0x4000 ... 0x5FFF => { - self.bank_no_high = val & 3; - } - 0x6000 ... 0x7FFF => { - self.bank_mode = val & 1; - } - _ => panic!("MBC1 Write {:02X} to {:04X} unsupported", val, addr), - } - } - fn write_byte_mbc3(&mut self, addr: u16, val: u8) { - 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) - } - }, - 0x2000 ... 0x3FFF => self.bank_no = val & 0x7F, - 0x4000 ... 0x5FFF => { - // RAM bank select - match val { - 0x00 ... 0x03 => self.ram_bank_no = val, - 0x08 ... 0x0C => self.ram_bank_no = val, // RTC clock values, TODO - _ => panic!("Unknown MBC3 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; - } else { - println!("Ignoring RTC write"); - } - } - _ => panic!("MBC3: Writing {:02X} to {:04X} not supported", val, addr), - } + pub fn read_byte(&self, addr: u16) -> u8 { + self.mbc.read_byte(addr) } pub fn write_byte(&mut self, addr: u16, val: u8) { - match self.mbc_type { - MemoryBankControllerType::None => self.write_byte_none(addr, val), - MemoryBankControllerType::MBC1 => self.write_byte_mbc1(addr, val), - MemoryBankControllerType::MBC3 => self.write_byte_mbc3(addr, val), - _ => panic!("MBC not supported.") - } + self.mbc.write_byte(addr, val); } } diff --git a/src/cpu.rs b/src/cpu.rs index ed31efc..d62cc92 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -157,7 +157,7 @@ impl CPU { self.set_flag(FLAG_N); self.set_clear_flag(FLAG_Z, new == 0); self.set_clear_flag(FLAG_C, new > old || (new == old && c == 1)); - self.set_clear_flag(FLAG_H, ((old & 0x0F) - (val & 0x0F) - c) > 0x0F); + self.set_clear_flag(FLAG_H, ((old & 0x0F).wrapping_sub((val & 0x0F)).wrapping_sub(c)) > 0x0F); } #[inline] @@ -658,7 +658,7 @@ impl CPU { #[inline] fn rst(&mut self, val: u8) -> u8 { // Make sure this is correct. - if self.debug || true { + if self.debug { println!("RST {:02X}", val); } self.call(val as u16); @@ -887,7 +887,7 @@ impl CPU { // println!("Handling vblank interrupt"); self.handle_interrupt(0x40, interconnect::INTERRUPT_DISPLAY_VBLANK); } else if e_pending & interconnect::INTERRUPT_DISPLAY_STAT > 0 { - println!("Handling display stat interrupt"); + // println!("Handling display stat interrupt"); self.handle_interrupt(0x48, interconnect::INTERRUPT_DISPLAY_STAT); } else if e_pending & interconnect::INTERRUPT_TIMER_OVERFLOW > 0{ println!("Handling timer interrupt"); @@ -985,7 +985,10 @@ impl CPU { 4 } - 0x10 => panic!("STOP 0 {:02X} not implemented.", self.load_args(1)[0]), + 0x10 => { + println!("STOP 0 {:02X} not implemented.", self.load_args(1)[0]); + 4 + }, 0x11 => self.ld_rr_vv(REG_N_D, REG_N_E), 0x12 => self.ld_dref_rr_a(REG_N_D, REG_N_E), 0x13 => self.inc_rr(REG_N_D, REG_N_E), @@ -1192,7 +1195,7 @@ impl CPU { if self.debug { println!("LD A, (HL-)"); } - let mut addr = self.get_pair_value(REG_N_H, REG_N_L); + let addr = self.get_pair_value(REG_N_H, REG_N_L); self.regs[REG_A] = self.interconnect.read_byte(addr); self.set_pair_value(REG_N_H, REG_N_L, addr.wrapping_sub(1)); 8 diff --git a/src/display.rs b/src/display.rs index 9992b9c..b7b7a9c 100644 --- a/src/display.rs +++ b/src/display.rs @@ -72,7 +72,6 @@ pub struct Display { pub event_pump: sdl2::EventPump, - vblank_fired: bool, vblank_interrupt: bool, stat_interrupt: bool, } @@ -83,7 +82,7 @@ impl Display { let video_ctx = sdl_ctx.video().unwrap(); let wnd = video_ctx.window("RustBoy", (GB_PIXELS_X * SCALE) as u32, (GB_PIXELS_Y * SCALE) as u32).position_centered().build().expect("Failed to create window :<"); let renderer = wnd.renderer().build().expect("Could not build renderer"); - let mut event_pump = sdl_ctx.event_pump().expect("Getting event pump failed"); + let event_pump = sdl_ctx.event_pump().expect("Getting event pump failed"); Display { control: 0, @@ -106,7 +105,6 @@ impl Display { event_pump: event_pump, - vblank_fired: false, vblank_interrupt: false, stat_interrupt: false, } @@ -401,8 +399,8 @@ impl Display { false => 8 }; for x_o in 0 .. limit { - let mut b1: bool; - let mut b2: bool; + let b1: bool; + let b2: bool; let mut factor = 0; if wide_mode && x_o > 7 { b1 = (tile_line_3 & 1 << (14 - x_o)) > 0; diff --git a/src/interconnect.rs b/src/interconnect.rs index de0cc28..c483a71 100644 --- a/src/interconnect.rs +++ b/src/interconnect.rs @@ -193,6 +193,9 @@ impl Interconnect { }, 0xD000 ... 0xDFFF => { self.ram[(addr - 0xD000) as usize + self.wram_bank as usize * 0x1000] + }, + 0xE000 ... 0xEFFF => { + self.ram[(addr - 0xE000) as usize] } 0xFF00 => { if self.joy_switch & KEY_REGULAR == 0 { @@ -201,7 +204,7 @@ impl Interconnect { self.joy_special_keys } else { println!("Reading none from joystick?"); - 0xFF + 0x3F } } 0xFF01 ... 0xFF02 => self.serial.read_byte(addr), @@ -238,7 +241,8 @@ impl Interconnect { self.interrupt } _ => { - panic!("Read from {:04X} not supported.", addr); + println!("Read from {:04X} not supported.", addr); + 0 } } } diff --git a/src/main.rs b/src/main.rs index b9a02de..fff59b7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,8 @@ mod interconnect; mod sound; mod timer; mod serial; +mod mbc; + fn main() { let bios_path = env::args().nth(1).unwrap(); diff --git a/src/mbc/mbc.rs b/src/mbc/mbc.rs new file mode 100644 index 0000000..84b43af --- /dev/null +++ b/src/mbc/mbc.rs @@ -0,0 +1,40 @@ +pub trait MBC { + fn read_byte(&self, addr: u16) -> u8; + fn write_byte(&mut self, addr: u16, val: u8); +} + +pub struct NoMBC { + rom: Box<[u8]>, + ram: Box<[u8]>, +} + +impl NoMBC { + pub fn new(rom: Box<[u8]>, ram: Box<[u8]>) -> NoMBC { + + NoMBC { + rom: rom, + ram: ram, + } + } +} + +impl MBC for NoMBC { + fn write_byte(&mut self, addr: u16, val: u8) { + panic!("Writing not supported for cartridges without MBC."); + } + + fn read_byte(&self, addr: u16) -> u8 { + match addr { + 0x0000 ... 0x7FFF => self.rom[addr as usize], + 0xA000 ... 0xBFFF => { + // TODO: Check for ram + let addr = (addr as usize) - 0xA000; + + self.ram[addr] + } + _ => { + panic!("Cartride: Unable to read from {:04X}", addr); + } + } + } +} diff --git a/src/mbc/mbc3.rs b/src/mbc/mbc3.rs new file mode 100644 index 0000000..f1fe7d8 --- /dev/null +++ b/src/mbc/mbc3.rs @@ -0,0 +1,93 @@ +use super::mbc::MBC; + +pub struct MBC3 { + rom: Box<[u8]>, + ram: Box<[u8]>, + bank_no: u8, + ram_rtc_enabled: bool, + ram_bank_no: u8, + + rom_banks: u16, + + bank_mode: u8, + bank_no_high: u8, +} + +impl MBC3 { + pub fn new(rom: Box<[u8]>, ram: Box<[u8]>) -> MBC3 { + MBC3 { + rom: rom, + ram: ram, + bank_no: 0, + ram_rtc_enabled: false, + ram_bank_no: 0, + rom_banks: 0, + bank_mode: 0, + bank_no_high: 0, + } + } +} + +impl MBC for MBC3 { + fn read_byte(&self, addr: u16) -> u8 { + match addr { + 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 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 + } + } + _ => { + panic!("Cartride: Unable to read from {:04X}", addr); + } + } + } + + fn write_byte(&mut self, addr: u16, val: u8) { + 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) + } + }, + 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 MBC3 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; + } else { + println!("Ignoring RTC write"); + } + } + _ => panic!("MBC3: Writing {:02X} to {:04X} not supported", val, addr), + } + } +} diff --git a/src/mbc/mod.rs b/src/mbc/mod.rs new file mode 100644 index 0000000..14c0767 --- /dev/null +++ b/src/mbc/mod.rs @@ -0,0 +1,2 @@ +pub mod mbc; +pub mod mbc3;