From 30d9ddc713b8fc43adc33d708af24e58a512f1a4 Mon Sep 17 00:00:00 2001 From: Alex Janka Date: Thu, 23 Feb 2023 11:00:29 +1100 Subject: [PATCH] add mbc5 --- src/processor/memory/rom.rs | 8 ++- src/processor/memory/rom/mbcs.rs | 38 +++++++++++ src/processor/memory/rom/mbcs/mbc1.rs | 32 +--------- src/processor/memory/rom/mbcs/mbc5.rs | 91 +++++++++++++++++++++++++++ 4 files changed, 139 insertions(+), 30 deletions(-) create mode 100644 src/processor/memory/rom/mbcs/mbc5.rs diff --git a/src/processor/memory/rom.rs b/src/processor/memory/rom.rs index 6de87ef..791c66c 100644 --- a/src/processor/memory/rom.rs +++ b/src/processor/memory/rom.rs @@ -1,7 +1,7 @@ use crate::processor::memory::Address; use std::str::from_utf8_unchecked; -use self::mbcs::{Mbc, Mbc1, None}; +use self::mbcs::{Mbc, Mbc1, Mbc5, None}; mod mbcs; @@ -32,6 +32,12 @@ impl Rom { println!("MBC1 w/battery - battery not implemented!"); Box::new(Mbc1::init(data, rom_size, ram_size, None)) } + 0x19 => Box::new(Mbc5::init(data, rom_size, 0)), + 0x1A => Box::new(Mbc5::init(data, rom_size, ram_size)), + 0x1B => { + println!("MBC5 w/battery - battery not implemented!"); + Box::new(Mbc5::init(data, rom_size, ram_size)) + } _ => panic!("unimplemented mbc: {:#X}", data[0x147]), }; Self { title, mbc } diff --git a/src/processor/memory/rom/mbcs.rs b/src/processor/memory/rom/mbcs.rs index cc0af68..9270f27 100644 --- a/src/processor/memory/rom/mbcs.rs +++ b/src/processor/memory/rom/mbcs.rs @@ -1,14 +1,52 @@ use crate::processor::memory::Address; mod mbc1; +mod mbc5; mod none; pub use mbc1::Mbc1; +pub use mbc5::Mbc5; pub use none::None; +const KB: usize = 1024; +const ROM_BANK_SIZE: usize = 16 * KB; +const RAM_BANK_SIZE: usize = 8 * KB; + pub(super) trait Mbc { + // addresses 0x0000 - 0x7FFF fn get(&self, address: Address) -> u8; + // addresses 0xA000 - 0xBFFF fn get_ram(&self, address: Address) -> u8; fn set(&mut self, address: Address, data: u8); fn set_ram(&mut self, address: Address, data: u8); fn mbc_type(&self) -> String; } + +fn rom_banks(rom_size: u8) -> usize { + 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"), + } +} + +fn ram_size_kb(ram_size: u8) -> Option { + match ram_size { + 0x00 => None, + 0x01 => Some(2), + 0x02 => Some(8), + 0x03 => Some(32), + 0x04 => Some(128), + 0x05 => Some(64), + _ => panic!("unacceptable ram size"), + } +} diff --git a/src/processor/memory/rom/mbcs/mbc1.rs b/src/processor/memory/rom/mbcs/mbc1.rs index 4f9387a..94d37c3 100644 --- a/src/processor/memory/rom/mbcs/mbc1.rs +++ b/src/processor/memory/rom/mbcs/mbc1.rs @@ -1,4 +1,4 @@ -use super::Mbc; +use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE}; use crate::processor::memory::Address; #[derive(Clone, Copy)] @@ -18,37 +18,11 @@ pub struct Mbc1 { 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; + let rom_len = rom_banks(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"), - }; + let ram = ram_size_kb(ram_size).map(|s| vec![0; s * KB]); Self { data, rom_len, diff --git a/src/processor/memory/rom/mbcs/mbc5.rs b/src/processor/memory/rom/mbcs/mbc5.rs new file mode 100644 index 0000000..5c63078 --- /dev/null +++ b/src/processor/memory/rom/mbcs/mbc5.rs @@ -0,0 +1,91 @@ +use crate::processor::memory::Address; + +use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE}; + +pub struct Mbc5 { + data: Vec, + rom_bank: u16, + rom_size: usize, + ram: Option>, + ram_bank: u8, + ram_enabled: bool, +} + +impl Mbc5 { + pub fn init(data: Vec, rom_size: u8, ram_size: u8) -> Self { + let ram = ram_size_kb(ram_size).map(|s| vec![0; s * KB]); + Self { + data, + rom_bank: 1, + rom_size: rom_banks(rom_size) * ROM_BANK_SIZE, + ram, + ram_bank: 0, + ram_enabled: false, + } + } + + fn get_rom_addr(&self, address: Address) -> usize { + (match address { + 0x0..0x4000 => address as usize, + 0x4000..0x8000 => { + let internal_addr = address as usize - 0x4000; + internal_addr + (ROM_BANK_SIZE * self.rom_bank as usize) + } + _ => panic!("address {address} incompatible with MBC5"), + } % self.rom_size) + } + + fn get_ram_addr(&self, address: Address) -> usize { + address as usize + (RAM_BANK_SIZE * self.ram_bank as usize) + } +} + +impl Mbc for Mbc5 { + 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 { + ram[self.get_ram_addr(address)] + } else { + 0xFF + } + } + + fn set(&mut self, address: Address, data: u8) { + match address { + 0x0..0x2000 => { + if data == 0xA { + self.ram_enabled = true + } else { + self.ram_enabled = false + } + } + 0x2000..0x3000 => self.rom_bank = (self.rom_bank & 0x100) | (data as u16), + 0x3000..0x4000 => self.rom_bank = (self.rom_bank & 0xFF) | ((data as u16 & 0b1) << 8), + 0x4000..0x6000 => self.ram_bank = data & 0xF, + 0x6000..0x8000 => {} + _ => panic!("address {address} incompatible with MBC5"), + } + } + + fn set_ram(&mut self, address: Address, data: u8) { + let real_addr = self.get_ram_addr(address); + if self.ram_enabled && let Some(ram) = &mut self.ram { + ram[real_addr] = data; + } + } + + fn mbc_type(&self) -> String { + if let Some(ram) = &self.ram { + format!( + "{}KB MBC5 with {}KB RAM", + self.rom_size / KB, + ram.len() / KB + ) + } else { + format!("{}KB MBC5", self.rom_size / KB) + } + } +}