add mbc5
This commit is contained in:
parent
97f39e9c5d
commit
30d9ddc713
|
@ -1,7 +1,7 @@
|
||||||
use crate::processor::memory::Address;
|
use crate::processor::memory::Address;
|
||||||
use std::str::from_utf8_unchecked;
|
use std::str::from_utf8_unchecked;
|
||||||
|
|
||||||
use self::mbcs::{Mbc, Mbc1, None};
|
use self::mbcs::{Mbc, Mbc1, Mbc5, None};
|
||||||
|
|
||||||
mod mbcs;
|
mod mbcs;
|
||||||
|
|
||||||
|
@ -32,6 +32,12 @@ impl Rom {
|
||||||
println!("MBC1 w/battery - battery not implemented!");
|
println!("MBC1 w/battery - battery not implemented!");
|
||||||
Box::new(Mbc1::init(data, rom_size, ram_size, None))
|
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]),
|
_ => panic!("unimplemented mbc: {:#X}", data[0x147]),
|
||||||
};
|
};
|
||||||
Self { title, mbc }
|
Self { title, mbc }
|
||||||
|
|
|
@ -1,14 +1,52 @@
|
||||||
use crate::processor::memory::Address;
|
use crate::processor::memory::Address;
|
||||||
|
|
||||||
mod mbc1;
|
mod mbc1;
|
||||||
|
mod mbc5;
|
||||||
mod none;
|
mod none;
|
||||||
pub use mbc1::Mbc1;
|
pub use mbc1::Mbc1;
|
||||||
|
pub use mbc5::Mbc5;
|
||||||
pub use none::None;
|
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 {
|
pub(super) trait Mbc {
|
||||||
|
// addresses 0x0000 - 0x7FFF
|
||||||
fn get(&self, address: Address) -> u8;
|
fn get(&self, address: Address) -> u8;
|
||||||
|
// addresses 0xA000 - 0xBFFF
|
||||||
fn get_ram(&self, address: Address) -> u8;
|
fn get_ram(&self, address: Address) -> u8;
|
||||||
fn set(&mut self, address: Address, data: u8);
|
fn set(&mut self, address: Address, data: u8);
|
||||||
fn set_ram(&mut self, address: Address, data: u8);
|
fn set_ram(&mut self, address: Address, data: u8);
|
||||||
fn mbc_type(&self) -> String;
|
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<usize> {
|
||||||
|
match ram_size {
|
||||||
|
0x00 => None,
|
||||||
|
0x01 => Some(2),
|
||||||
|
0x02 => Some(8),
|
||||||
|
0x03 => Some(32),
|
||||||
|
0x04 => Some(128),
|
||||||
|
0x05 => Some(64),
|
||||||
|
_ => panic!("unacceptable ram size"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
use crate::processor::memory::Address;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
@ -18,37 +18,11 @@ pub struct Mbc1 {
|
||||||
bank_mode: BankingMode,
|
bank_mode: BankingMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
const KB: usize = 1024;
|
|
||||||
const ROM_BANK_SIZE: usize = 16 * KB;
|
|
||||||
const RAM_BANK_SIZE: usize = 8 * KB;
|
|
||||||
|
|
||||||
impl Mbc1 {
|
impl Mbc1 {
|
||||||
pub fn init(data: Vec<u8>, rom_size: u8, ram_size: u8, _save_file: Option<Vec<u8>>) -> Self {
|
pub fn init(data: Vec<u8>, rom_size: u8, ram_size: u8, _save_file: Option<Vec<u8>>) -> Self {
|
||||||
let rom_len = match rom_size {
|
let rom_len = rom_banks(rom_size) * ROM_BANK_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
|
// in kb
|
||||||
let ram = match ram_size {
|
let ram = ram_size_kb(ram_size).map(|s| vec![0; s * KB]);
|
||||||
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 {
|
Self {
|
||||||
data,
|
data,
|
||||||
rom_len,
|
rom_len,
|
||||||
|
|
91
src/processor/memory/rom/mbcs/mbc5.rs
Normal file
91
src/processor/memory/rom/mbcs/mbc5.rs
Normal file
|
@ -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<u8>,
|
||||||
|
rom_bank: u16,
|
||||||
|
rom_size: usize,
|
||||||
|
ram: Option<Vec<u8>>,
|
||||||
|
ram_bank: u8,
|
||||||
|
ram_enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Mbc5 {
|
||||||
|
pub fn init(data: Vec<u8>, 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue