parse rom header
This commit is contained in:
parent
d3fb042451
commit
605d4b2abd
|
@ -7,7 +7,9 @@ pub use crate::processor::memory::mmio::gpu::Colour;
|
|||
pub use crate::processor::memory::mmio::joypad::{JoypadButtons, JoypadState};
|
||||
pub use crate::processor::memory::mmio::serial::{SerialTarget, StdoutType};
|
||||
use crate::processor::memory::rom::sram_save::SaveDataLocation;
|
||||
pub use crate::processor::memory::rom::CgbRomType;
|
||||
pub use crate::processor::memory::rom::{
|
||||
licensee::LicenseeCode, CartridgeType, CgbRomType, RamSize, RomHeader, RomHeaderError, RomSize,
|
||||
};
|
||||
pub use crate::processor::memory::Rom;
|
||||
pub use crate::{HEIGHT, WIDTH};
|
||||
use async_ringbuf::{AsyncHeapConsumer, AsyncHeapProducer, AsyncHeapRb};
|
||||
|
|
|
@ -1,16 +1,19 @@
|
|||
use self::{
|
||||
mbcs::{Mbc, Mbc1, Mbc2, Mbc3, Mbc5, None},
|
||||
licensee::LicenseeCode,
|
||||
mbcs::{Mbc, Mbc1, Mbc2, Mbc3, Mbc5, None, KB, ROM_BANK_SIZE},
|
||||
sram_save::SaveDataLocation,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::str::from_utf8;
|
||||
use thiserror::Error;
|
||||
|
||||
use super::addresses::{CartRamAddress, RomAddress};
|
||||
|
||||
pub(crate) mod licensee;
|
||||
mod mbcs;
|
||||
pub mod sram_save;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
pub enum CgbRomType {
|
||||
Dmg,
|
||||
CgbOptional,
|
||||
|
@ -23,8 +26,173 @@ pub struct Rom {
|
|||
pub rom_type: CgbRomType,
|
||||
}
|
||||
|
||||
impl Rom {
|
||||
pub(crate) fn load(data: Vec<u8>, sram_location: Option<SaveDataLocation>) -> Self {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RomHeader {
|
||||
pub title: String,
|
||||
pub console_type: CgbRomType,
|
||||
pub licensee_code: LicenseeCode,
|
||||
pub sgb_flag: bool,
|
||||
pub cartridge_type: CartridgeType,
|
||||
pub rom_size: RomSize,
|
||||
pub ram_size: Option<RamSize>,
|
||||
pub mask_rom_version: u8,
|
||||
pub header_checksum: u8,
|
||||
pub cartridge_checksum: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum CartridgeType {
|
||||
NoMapper,
|
||||
Mbc1 { battery: bool },
|
||||
Mbc2 { battery: bool },
|
||||
Mmm01 { battery: bool },
|
||||
Mbc3 { timer: bool, battery: bool },
|
||||
Mbc5 { battery: bool, rumble: bool },
|
||||
Mbc6,
|
||||
Mbc7,
|
||||
PocketCamera,
|
||||
Tama5,
|
||||
HuC3,
|
||||
HuC1,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for CartridgeType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
CartridgeType::NoMapper => write!(f, "No mapper"),
|
||||
CartridgeType::Mbc1 { battery } => {
|
||||
write!(f, "MBC1{}", if *battery { " (battery)" } else { "" })
|
||||
}
|
||||
CartridgeType::Mbc2 { battery } => {
|
||||
write!(f, "MBC2{}", if *battery { " (battery)" } else { "" })
|
||||
}
|
||||
CartridgeType::Mmm01 { battery } => {
|
||||
write!(f, "MMM01{}", if *battery { " (battery)" } else { "" })
|
||||
}
|
||||
CartridgeType::Mbc3 {
|
||||
timer: false,
|
||||
battery: false,
|
||||
} => write!(f, "MBC3"),
|
||||
CartridgeType::Mbc3 { timer, battery } => write!(
|
||||
f,
|
||||
"MBC3 ({}{}{})",
|
||||
if *battery { "battery" } else { "" },
|
||||
if *battery && *timer { " + " } else { "" },
|
||||
if *timer { "RTC" } else { "" }
|
||||
),
|
||||
CartridgeType::Mbc5 {
|
||||
battery: false,
|
||||
rumble: false,
|
||||
} => write!(f, "MBC5"),
|
||||
CartridgeType::Mbc5 { battery, rumble } => write!(
|
||||
f,
|
||||
"MBC5 ({}{}{})",
|
||||
if *battery { "battery" } else { "" },
|
||||
if *battery && *rumble { " + " } else { "" },
|
||||
if *rumble { "Rumble" } else { "" }
|
||||
),
|
||||
CartridgeType::Mbc6 => write!(f, "MBC6"),
|
||||
CartridgeType::Mbc7 => write!(f, "MBC7"),
|
||||
CartridgeType::PocketCamera => write!(f, "Pocket Camera"),
|
||||
CartridgeType::Tama5 => write!(f, "Tama5"),
|
||||
CartridgeType::HuC3 => write!(f, "HuC3"),
|
||||
CartridgeType::HuC1 => write!(f, "HuC1"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum RomSize {
|
||||
B2,
|
||||
B4,
|
||||
B8,
|
||||
B16,
|
||||
B32,
|
||||
B64,
|
||||
B128,
|
||||
B256,
|
||||
B512,
|
||||
B72,
|
||||
B80,
|
||||
B96,
|
||||
}
|
||||
|
||||
impl RomSize {
|
||||
pub fn from(val: u8) -> Option<Self> {
|
||||
match val {
|
||||
0x00 => Some(Self::B2),
|
||||
0x01 => Some(Self::B4),
|
||||
0x02 => Some(Self::B8),
|
||||
0x03 => Some(Self::B16),
|
||||
0x04 => Some(Self::B32),
|
||||
0x05 => Some(Self::B64),
|
||||
0x06 => Some(Self::B128),
|
||||
0x07 => Some(Self::B256),
|
||||
0x08 => Some(Self::B512),
|
||||
0x52 => Some(Self::B72),
|
||||
0x53 => Some(Self::B80),
|
||||
0x54 => Some(Self::B96),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size_bytes(&self) -> usize {
|
||||
(match self {
|
||||
RomSize::B2 => 2,
|
||||
RomSize::B4 => 4,
|
||||
RomSize::B8 => 8,
|
||||
RomSize::B16 => 16,
|
||||
RomSize::B32 => 32,
|
||||
RomSize::B64 => 64,
|
||||
RomSize::B128 => 128,
|
||||
RomSize::B256 => 256,
|
||||
RomSize::B512 => 512,
|
||||
RomSize::B72 => 72,
|
||||
RomSize::B80 => 80,
|
||||
RomSize::B96 => 96,
|
||||
}) * ROM_BANK_SIZE
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum RamSize {
|
||||
B2,
|
||||
B8,
|
||||
B32,
|
||||
B64,
|
||||
B128,
|
||||
}
|
||||
|
||||
impl RamSize {
|
||||
pub fn from(val: u8) -> Result<Option<Self>, RomHeaderError> {
|
||||
match val {
|
||||
0x00 => Ok(None),
|
||||
0x01 => Ok(Some(Self::B2)),
|
||||
0x02 => Ok(Some(Self::B8)),
|
||||
0x03 => Ok(Some(Self::B32)),
|
||||
0x04 => Ok(Some(Self::B128)),
|
||||
0x05 => Ok(Some(Self::B64)),
|
||||
_ => Err(RomHeaderError::InvalidRamSize),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn size_bytes(&self) -> usize {
|
||||
match self {
|
||||
RamSize::B2 => 2 * KB,
|
||||
RamSize::B8 => 8 * KB,
|
||||
RamSize::B32 => 32 * KB,
|
||||
RamSize::B64 => 64 * KB,
|
||||
RamSize::B128 => 128 * KB,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RomHeader {
|
||||
pub fn parse(data: &[u8]) -> Result<Self, RomHeaderError> {
|
||||
if data.len() < 0x150 {
|
||||
return Err(RomHeaderError::SliceLength);
|
||||
}
|
||||
|
||||
let mut title_length = 0x143;
|
||||
for (i, val) in data.iter().enumerate().take(0x143).skip(0x134) {
|
||||
title_length = i;
|
||||
|
@ -32,38 +200,184 @@ impl Rom {
|
|||
break;
|
||||
}
|
||||
}
|
||||
let title = from_utf8(&data[0x134..title_length])
|
||||
.expect("Error parsing title")
|
||||
.to_string();
|
||||
let title = from_utf8(&data[0x134..title_length])?.to_string();
|
||||
|
||||
let console_type = match data[0x143] {
|
||||
0x80 => CgbRomType::CgbOptional,
|
||||
0xC0 => CgbRomType::CgbOnly,
|
||||
_ => CgbRomType::Dmg,
|
||||
};
|
||||
|
||||
let licensee_code = LicenseeCode::from_header(data[0x14B], [data[0x144], data[0x145]]);
|
||||
|
||||
let sgb_flag = data[0x146] == 0x03;
|
||||
let rom_size = RomSize::from(data[0x148]).ok_or(RomHeaderError::InvalidRomSize)?;
|
||||
let mut ram_size = RamSize::from(data[0x149])?;
|
||||
|
||||
let cartridge_type = match data[0x147] {
|
||||
0x00 => {
|
||||
ram_size = None;
|
||||
CartridgeType::NoMapper
|
||||
}
|
||||
0x01 => {
|
||||
ram_size = None;
|
||||
CartridgeType::Mbc1 { battery: false }
|
||||
}
|
||||
0x02 => CartridgeType::Mbc1 { battery: false },
|
||||
0x03 => CartridgeType::Mbc1 { battery: true },
|
||||
0x05 => {
|
||||
ram_size = None;
|
||||
CartridgeType::Mbc2 { battery: false }
|
||||
}
|
||||
0x06 => {
|
||||
ram_size = None;
|
||||
CartridgeType::Mbc2 { battery: true }
|
||||
}
|
||||
0x0B => {
|
||||
ram_size = None;
|
||||
CartridgeType::Mmm01 { battery: false }
|
||||
}
|
||||
0x0C => CartridgeType::Mmm01 { battery: false },
|
||||
0x0D => CartridgeType::Mmm01 { battery: true },
|
||||
0x0F => {
|
||||
ram_size = None;
|
||||
CartridgeType::Mbc3 {
|
||||
timer: true,
|
||||
battery: true,
|
||||
}
|
||||
}
|
||||
0x10 => CartridgeType::Mbc3 {
|
||||
timer: true,
|
||||
battery: true,
|
||||
},
|
||||
0x11 => {
|
||||
ram_size = None;
|
||||
CartridgeType::Mbc3 {
|
||||
timer: false,
|
||||
battery: false,
|
||||
}
|
||||
}
|
||||
0x12 => CartridgeType::Mbc3 {
|
||||
timer: false,
|
||||
battery: false,
|
||||
},
|
||||
0x13 => CartridgeType::Mbc3 {
|
||||
timer: false,
|
||||
battery: true,
|
||||
},
|
||||
0x19 => {
|
||||
ram_size = None;
|
||||
CartridgeType::Mbc5 {
|
||||
battery: false,
|
||||
rumble: false,
|
||||
}
|
||||
}
|
||||
0x1A => CartridgeType::Mbc5 {
|
||||
battery: false,
|
||||
rumble: false,
|
||||
},
|
||||
0x1B => CartridgeType::Mbc5 {
|
||||
battery: true,
|
||||
rumble: false,
|
||||
},
|
||||
0x1C => {
|
||||
ram_size = None;
|
||||
CartridgeType::Mbc5 {
|
||||
battery: false,
|
||||
rumble: true,
|
||||
}
|
||||
}
|
||||
0x1D => CartridgeType::Mbc5 {
|
||||
battery: false,
|
||||
rumble: true,
|
||||
},
|
||||
0x1E => CartridgeType::Mbc5 {
|
||||
battery: true,
|
||||
rumble: true,
|
||||
},
|
||||
0x20 => CartridgeType::Mbc6,
|
||||
0x22 => CartridgeType::Mbc7,
|
||||
0xFC => CartridgeType::PocketCamera,
|
||||
0xFD => CartridgeType::Tama5,
|
||||
0xFE => CartridgeType::HuC3,
|
||||
0xFF => CartridgeType::HuC1,
|
||||
_ => return Err(RomHeaderError::InvalidMBC),
|
||||
};
|
||||
|
||||
let mask_rom_version = data[0x14C];
|
||||
let header_checksum = data[0x14D];
|
||||
let cartridge_checksum = u16::from_be_bytes([data[0x14E], data[0x14F]]);
|
||||
|
||||
Ok(RomHeader {
|
||||
title,
|
||||
console_type,
|
||||
licensee_code,
|
||||
sgb_flag,
|
||||
cartridge_type,
|
||||
rom_size,
|
||||
ram_size,
|
||||
mask_rom_version,
|
||||
header_checksum,
|
||||
cartridge_checksum,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum RomHeaderError {
|
||||
#[error("slice not long enough for rom file")]
|
||||
SliceLength,
|
||||
#[error("parsing UTF-8")]
|
||||
Utf8(#[from] std::str::Utf8Error),
|
||||
#[error("invalid ROM size")]
|
||||
InvalidRomSize,
|
||||
#[error("invalid RAM size")]
|
||||
InvalidRamSize,
|
||||
#[error("invalid MBC")]
|
||||
InvalidMBC,
|
||||
}
|
||||
|
||||
impl Rom {
|
||||
pub(crate) fn load(data: Vec<u8>, sram_location: Option<SaveDataLocation>) -> Self {
|
||||
let header_data = RomHeader::parse(&data).unwrap();
|
||||
|
||||
let rom_type = get_cgb_rom_type(data[0x143]);
|
||||
|
||||
let _sgb_flag = data[0x146];
|
||||
let rom_size = data[0x148];
|
||||
let ram_size = data[0x149];
|
||||
let mbc: Box<dyn Mbc> = match data[0x147] {
|
||||
0x00 => Box::new(None::init(data)),
|
||||
0x01 => Box::new(Mbc1::init(data, rom_size, 0, None)),
|
||||
0x02 => Box::new(Mbc1::init(data, rom_size, ram_size, None)),
|
||||
0x03 => Box::new(Mbc1::init(data, rom_size, ram_size, sram_location)),
|
||||
0x05 => Box::new(Mbc2::init(data, rom_size, None)),
|
||||
0x06 => Box::new(Mbc2::init(data, rom_size, sram_location)),
|
||||
0x0F => Box::new(Mbc3::init(data, rom_size, 0, true, sram_location)),
|
||||
0x10 => Box::new(Mbc3::init(data, rom_size, ram_size, true, sram_location)),
|
||||
0x11 => Box::new(Mbc3::init(data, rom_size, 0, false, None)),
|
||||
0x12 => Box::new(Mbc3::init(data, rom_size, ram_size, false, None)),
|
||||
0x13 => Box::new(Mbc3::init(data, rom_size, ram_size, false, sram_location)),
|
||||
0x19 => Box::new(Mbc5::init(data, rom_size, 0, false, None)),
|
||||
0x1A => Box::new(Mbc5::init(data, rom_size, ram_size, false, None)),
|
||||
0x1B => Box::new(Mbc5::init(data, rom_size, ram_size, false, sram_location)),
|
||||
0x1C => Box::new(Mbc5::init(data, rom_size, 0, true, None)),
|
||||
0x1D => Box::new(Mbc5::init(data, rom_size, ram_size, true, None)),
|
||||
0x1E => Box::new(Mbc5::init(data, rom_size, ram_size, true, sram_location)),
|
||||
0xFC => todo!(),
|
||||
_ => panic!("unimplemented mbc: {:#X}", data[0x147]),
|
||||
let mbc: Box<dyn Mbc> = match header_data.cartridge_type {
|
||||
CartridgeType::NoMapper => Box::new(None::init(data)),
|
||||
CartridgeType::Mbc1 { battery } => Box::new(Mbc1::init(
|
||||
data,
|
||||
header_data.rom_size,
|
||||
header_data.ram_size,
|
||||
if battery { sram_location } else { None },
|
||||
)),
|
||||
CartridgeType::Mbc2 { battery } => Box::new(Mbc2::init(
|
||||
data,
|
||||
header_data.rom_size,
|
||||
if battery { sram_location } else { None },
|
||||
)),
|
||||
CartridgeType::Mbc3 { timer, battery } => Box::new(Mbc3::init(
|
||||
data,
|
||||
header_data.rom_size,
|
||||
header_data.ram_size,
|
||||
timer,
|
||||
if battery { sram_location } else { None },
|
||||
)),
|
||||
CartridgeType::Mbc5 { battery, rumble } => Box::new(Mbc5::init(
|
||||
data,
|
||||
header_data.rom_size,
|
||||
header_data.ram_size,
|
||||
rumble,
|
||||
if battery { sram_location } else { None },
|
||||
)),
|
||||
_ => todo!(
|
||||
"mapper {:?} not implemented yet!",
|
||||
header_data.cartridge_type
|
||||
),
|
||||
};
|
||||
|
||||
Self {
|
||||
title,
|
||||
title: header_data.title,
|
||||
mbc,
|
||||
rom_type,
|
||||
}
|
||||
|
|
351
lib/src/processor/memory/rom/licensee.rs
Normal file
351
lib/src/processor/memory/rom/licensee.rs
Normal file
|
@ -0,0 +1,351 @@
|
|||
#[derive(Debug, Clone)]
|
||||
pub enum LicenseeCode {
|
||||
None,
|
||||
Nintendo,
|
||||
Capcom,
|
||||
HotB,
|
||||
Jaleco,
|
||||
Coconuts,
|
||||
EliteSystems,
|
||||
ElectronicArts,
|
||||
Hudsonsoft,
|
||||
ItcEntertainment,
|
||||
Yanoman,
|
||||
Clary,
|
||||
Virgin,
|
||||
PcmComplete,
|
||||
SanX,
|
||||
KotobukiSystems,
|
||||
Seta,
|
||||
Infogrames,
|
||||
Bandai,
|
||||
Konami,
|
||||
Hector,
|
||||
Banpresto,
|
||||
EntertainmentI,
|
||||
Gremlin,
|
||||
Ubisoft,
|
||||
Atlus,
|
||||
Malibu,
|
||||
Angel,
|
||||
SpectrumHoloby,
|
||||
Irem,
|
||||
USGold,
|
||||
Absolute,
|
||||
Acclaim,
|
||||
Activision,
|
||||
AmericanSammy,
|
||||
Gametek,
|
||||
ParkPlace,
|
||||
Ljn,
|
||||
Matchbox,
|
||||
MiltonBradley,
|
||||
Mindscape,
|
||||
Romstar,
|
||||
NaxatSoft,
|
||||
Tradewest,
|
||||
Titus,
|
||||
Ocean,
|
||||
ElectroBrain,
|
||||
Interplay,
|
||||
Broderbund,
|
||||
SculpturedSoft,
|
||||
TheSalesCurve,
|
||||
Thq,
|
||||
Accolade,
|
||||
TriffixEntertainment,
|
||||
Microprose,
|
||||
Kemco,
|
||||
MisawaEntertainment,
|
||||
Lozc,
|
||||
TokumaShotenIntermedia,
|
||||
BulletProofSoftware,
|
||||
VicTokai,
|
||||
Ape,
|
||||
IMax,
|
||||
ChunSoft,
|
||||
VideoSystem,
|
||||
Tsuburava,
|
||||
Varie,
|
||||
YonezawaSpal,
|
||||
Kaneko,
|
||||
Arc,
|
||||
NihonBussan,
|
||||
Tecmo,
|
||||
Imagineer,
|
||||
Nova,
|
||||
HoriElectric,
|
||||
Kawada,
|
||||
Takara,
|
||||
TechnosJapan,
|
||||
ToeiAnimation,
|
||||
Toho,
|
||||
Namco,
|
||||
AsciiNexoft,
|
||||
Enix,
|
||||
Hal,
|
||||
Snk,
|
||||
PonyCanyon,
|
||||
CultureBrain,
|
||||
Sunsoft,
|
||||
SonyImagesoft,
|
||||
Sammy,
|
||||
Taito,
|
||||
Squaresoft,
|
||||
DataEast,
|
||||
TonkinHouse,
|
||||
Koei,
|
||||
Ufl,
|
||||
Ultra,
|
||||
Vap,
|
||||
Use,
|
||||
Meldac,
|
||||
Sofel,
|
||||
Quest,
|
||||
SigmaEnterprises,
|
||||
AskKodansha,
|
||||
CopyaSystems,
|
||||
Tomy,
|
||||
Ncs,
|
||||
Human,
|
||||
Altron,
|
||||
Towachiki,
|
||||
Uutaka,
|
||||
Epoch,
|
||||
Athena,
|
||||
Asmik,
|
||||
Natsume,
|
||||
KingRecords,
|
||||
EpicSonyRecords,
|
||||
Igs,
|
||||
AWave,
|
||||
ExtremeEntertainment,
|
||||
BAi,
|
||||
Kss,
|
||||
Pow,
|
||||
Viacom,
|
||||
OceanAcclaim,
|
||||
HiTechEntertainment,
|
||||
Mattel,
|
||||
Lucasarts,
|
||||
Sci,
|
||||
TsukudaOri,
|
||||
PackInSoft,
|
||||
}
|
||||
|
||||
impl LicenseeCode {
|
||||
pub fn from_header(old_licensee_code: u8, new_code: [u8; 2]) -> Self {
|
||||
match old_licensee_code {
|
||||
0x00 => Self::None,
|
||||
0x01 => Self::Nintendo,
|
||||
0x08 => Self::Capcom,
|
||||
0x09 => Self::HotB,
|
||||
0x0A => Self::Jaleco,
|
||||
0x0B => Self::Coconuts,
|
||||
0x0C => Self::EliteSystems,
|
||||
0x13 => Self::ElectronicArts,
|
||||
0x18 => Self::Hudsonsoft,
|
||||
0x19 => Self::ItcEntertainment,
|
||||
0x1A => Self::Yanoman,
|
||||
0x1D => Self::Clary,
|
||||
0x1F => Self::Virgin,
|
||||
0x24 => Self::PcmComplete,
|
||||
0x25 => Self::SanX,
|
||||
0x28 => Self::KotobukiSystems,
|
||||
0x29 => Self::Seta,
|
||||
0x30 => Self::Infogrames,
|
||||
0x31 => Self::Nintendo,
|
||||
0x32 => Self::Bandai,
|
||||
0x33 => match &new_code {
|
||||
b"00" => Self::None,
|
||||
b"01" => Self::Nintendo,
|
||||
b"08" => Self::Capcom,
|
||||
b"13" => Self::ElectronicArts,
|
||||
b"18" => Self::Hudsonsoft,
|
||||
b"19" => Self::BAi,
|
||||
b"20" => Self::Kss,
|
||||
b"22" => Self::Pow,
|
||||
b"24" => Self::PcmComplete,
|
||||
b"25" => Self::SanX,
|
||||
b"28" => Self::Kemco,
|
||||
b"29" => Self::Seta,
|
||||
b"30" => Self::Viacom,
|
||||
b"31" => Self::Nintendo,
|
||||
b"32" => Self::Bandai,
|
||||
b"33" => Self::OceanAcclaim,
|
||||
b"34" => Self::Konami,
|
||||
b"35" => Self::Hector,
|
||||
b"37" => Self::Taito,
|
||||
b"38" => Self::Hudsonsoft,
|
||||
b"39" => Self::Banpresto,
|
||||
b"41" => Self::Ubisoft,
|
||||
b"42" => Self::Atlus,
|
||||
b"44" => Self::Malibu,
|
||||
b"46" => Self::Angel,
|
||||
b"47" => Self::BulletProofSoftware,
|
||||
b"49" => Self::Irem,
|
||||
b"50" => Self::Absolute,
|
||||
b"51" => Self::Acclaim,
|
||||
b"52" => Self::Activision,
|
||||
b"53" => Self::AmericanSammy,
|
||||
b"54" => Self::Konami,
|
||||
b"55" => Self::HiTechEntertainment,
|
||||
b"56" => Self::Ljn,
|
||||
b"57" => Self::Matchbox,
|
||||
b"58" => Self::Mattel,
|
||||
b"59" => Self::MiltonBradley,
|
||||
b"60" => Self::Titus,
|
||||
b"61" => Self::Virgin,
|
||||
b"64" => Self::Lucasarts,
|
||||
b"67" => Self::Ocean,
|
||||
b"69" => Self::ElectronicArts,
|
||||
b"70" => Self::Infogrames,
|
||||
b"71" => Self::Interplay,
|
||||
b"72" => Self::Broderbund,
|
||||
b"73" => Self::SculpturedSoft,
|
||||
b"75" => Self::Sci,
|
||||
b"78" => Self::Thq,
|
||||
b"79" => Self::Accolade,
|
||||
b"80" => Self::MisawaEntertainment,
|
||||
b"83" => Self::Lozc,
|
||||
b"86" => Self::TokumaShotenIntermedia,
|
||||
b"87" => Self::TsukudaOri,
|
||||
b"91" => Self::ChunSoft,
|
||||
b"92" => Self::VideoSystem,
|
||||
b"93" => Self::OceanAcclaim,
|
||||
b"95" => Self::Varie,
|
||||
b"96" => Self::YonezawaSpal,
|
||||
b"97" => Self::Kaneko,
|
||||
b"99" => Self::PackInSoft,
|
||||
_ => Self::None,
|
||||
},
|
||||
0x34 => Self::Konami,
|
||||
0x35 => Self::Hector,
|
||||
0x38 => Self::Capcom,
|
||||
0x39 => Self::Banpresto,
|
||||
0x3C => Self::EntertainmentI,
|
||||
0x3E => Self::Gremlin,
|
||||
0x41 => Self::Ubisoft,
|
||||
0x42 => Self::Atlus,
|
||||
0x44 => Self::Malibu,
|
||||
0x46 => Self::Angel,
|
||||
0x47 => Self::SpectrumHoloby,
|
||||
0x49 => Self::Irem,
|
||||
0x4A => Self::Virgin,
|
||||
0x4D => Self::Malibu,
|
||||
0x4F => Self::USGold,
|
||||
0x50 => Self::Absolute,
|
||||
0x51 => Self::Acclaim,
|
||||
0x52 => Self::Activision,
|
||||
0x53 => Self::AmericanSammy,
|
||||
0x54 => Self::Gametek,
|
||||
0x55 => Self::ParkPlace,
|
||||
0x56 => Self::Ljn,
|
||||
0x57 => Self::Matchbox,
|
||||
0x59 => Self::MiltonBradley,
|
||||
0x5A => Self::Mindscape,
|
||||
0x5B => Self::Romstar,
|
||||
0x5C => Self::NaxatSoft,
|
||||
0x5D => Self::Tradewest,
|
||||
0x60 => Self::Titus,
|
||||
0x61 => Self::Virgin,
|
||||
0x67 => Self::Ocean,
|
||||
0x69 => Self::ElectronicArts,
|
||||
0x6E => Self::EliteSystems,
|
||||
0x6F => Self::ElectroBrain,
|
||||
0x70 => Self::Infogrames,
|
||||
0x71 => Self::Interplay,
|
||||
0x72 => Self::Broderbund,
|
||||
0x73 => Self::SculpturedSoft,
|
||||
0x75 => Self::TheSalesCurve,
|
||||
0x78 => Self::Thq,
|
||||
0x79 => Self::Accolade,
|
||||
0x7A => Self::TriffixEntertainment,
|
||||
0x7C => Self::Microprose,
|
||||
0x7F => Self::Kemco,
|
||||
0x80 => Self::MisawaEntertainment,
|
||||
0x83 => Self::Lozc,
|
||||
0x86 => Self::TokumaShotenIntermedia,
|
||||
0x8B => Self::BulletProofSoftware,
|
||||
0x8C => Self::VicTokai,
|
||||
0x8E => Self::Ape,
|
||||
0x8F => Self::IMax,
|
||||
0x91 => Self::ChunSoft,
|
||||
0x92 => Self::VideoSystem,
|
||||
0x93 => Self::Tsuburava,
|
||||
0x95 => Self::Varie,
|
||||
0x96 => Self::YonezawaSpal,
|
||||
0x97 => Self::Kaneko,
|
||||
0x99 => Self::Arc,
|
||||
0x9A => Self::NihonBussan,
|
||||
0x9B => Self::Tecmo,
|
||||
0x9C => Self::Imagineer,
|
||||
0x9D => Self::Banpresto,
|
||||
0x9F => Self::Nova,
|
||||
0xA1 => Self::HoriElectric,
|
||||
0xA2 => Self::Bandai,
|
||||
0xA4 => Self::Konami,
|
||||
0xA6 => Self::Kawada,
|
||||
0xA7 => Self::Takara,
|
||||
0xA9 => Self::TechnosJapan,
|
||||
0xAA => Self::Broderbund,
|
||||
0xAC => Self::ToeiAnimation,
|
||||
0xAD => Self::Toho,
|
||||
0xAF => Self::Namco,
|
||||
0xB0 => Self::Acclaim,
|
||||
0xB1 => Self::AsciiNexoft,
|
||||
0xB2 => Self::Bandai,
|
||||
0xB4 => Self::Enix,
|
||||
0xB6 => Self::Hal,
|
||||
0xB7 => Self::Snk,
|
||||
0xB9 => Self::PonyCanyon,
|
||||
0xBA => Self::CultureBrain,
|
||||
0xBB => Self::Sunsoft,
|
||||
0xBD => Self::SonyImagesoft,
|
||||
0xBF => Self::Sammy,
|
||||
0xC0 => Self::Taito,
|
||||
0xC2 => Self::Kemco,
|
||||
0xC3 => Self::Squaresoft,
|
||||
0xC4 => Self::TokumaShotenIntermedia,
|
||||
0xC5 => Self::DataEast,
|
||||
0xC6 => Self::TonkinHouse,
|
||||
0xC8 => Self::Koei,
|
||||
0xC9 => Self::Ufl,
|
||||
0xCA => Self::Ultra,
|
||||
0xCB => Self::Vap,
|
||||
0xCC => Self::Use,
|
||||
0xCD => Self::Meldac,
|
||||
0xCE => Self::PonyCanyon,
|
||||
0xCF => Self::Angel,
|
||||
0xD0 => Self::Taito,
|
||||
0xD1 => Self::Sofel,
|
||||
0xD2 => Self::Quest,
|
||||
0xD3 => Self::SigmaEnterprises,
|
||||
0xD4 => Self::AskKodansha,
|
||||
0xD6 => Self::NaxatSoft,
|
||||
0xD7 => Self::CopyaSystems,
|
||||
0xD9 => Self::Banpresto,
|
||||
0xDA => Self::Tomy,
|
||||
0xDB => Self::Ljn,
|
||||
0xDD => Self::Ncs,
|
||||
0xDE => Self::Human,
|
||||
0xDF => Self::Altron,
|
||||
0xE0 => Self::Jaleco,
|
||||
0xE1 => Self::Towachiki,
|
||||
0xE2 => Self::Uutaka,
|
||||
0xE3 => Self::Varie,
|
||||
0xE5 => Self::Epoch,
|
||||
0xE7 => Self::Athena,
|
||||
0xE8 => Self::Asmik,
|
||||
0xE9 => Self::Natsume,
|
||||
0xEA => Self::KingRecords,
|
||||
0xEB => Self::Atlus,
|
||||
0xEC => Self::EpicSonyRecords,
|
||||
0xEE => Self::Igs,
|
||||
0xF0 => Self::AWave,
|
||||
0xF3 => Self::ExtremeEntertainment,
|
||||
0xFF => Self::Ljn,
|
||||
_ => Self::None,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,8 +13,8 @@ pub use mbc5::Mbc5;
|
|||
pub use none::None;
|
||||
|
||||
pub(super) const KB: usize = 1024;
|
||||
const ROM_BANK_SIZE: usize = 16 * KB;
|
||||
const RAM_BANK_SIZE: usize = 8 * KB;
|
||||
pub(super) const ROM_BANK_SIZE: usize = 16 * KB;
|
||||
pub(super) const RAM_BANK_SIZE: usize = 8 * KB;
|
||||
|
||||
pub(super) trait Mbc: Send {
|
||||
// addresses 0x0000 - 0x7FFF
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
||||
use super::{Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
||||
use crate::processor::memory::{
|
||||
addresses::{AddressMarker, CartRamAddress, RomAddress},
|
||||
rom::sram_save::{BufferedSramTrait, MaybeBufferedSram, SaveDataLocation},
|
||||
rom::{
|
||||
sram_save::{BufferedSramTrait, MaybeBufferedSram, SaveDataLocation},
|
||||
RamSize, RomSize,
|
||||
},
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
@ -25,13 +28,13 @@ pub struct Mbc1 {
|
|||
impl Mbc1 {
|
||||
pub fn init(
|
||||
data: Vec<u8>,
|
||||
rom_size: u8,
|
||||
ram_size: u8,
|
||||
rom_size: RomSize,
|
||||
ram_size: Option<RamSize>,
|
||||
save_file: Option<SaveDataLocation>,
|
||||
) -> Self {
|
||||
let rom_len = rom_banks(rom_size) * ROM_BANK_SIZE;
|
||||
let rom_len = rom_size.size_bytes();
|
||||
// in kb
|
||||
let ram = ram_size_kb(ram_size).map(|s| MaybeBufferedSram::new(save_file, s * KB));
|
||||
let ram = ram_size.map(|s| MaybeBufferedSram::new(save_file, s.size_bytes()));
|
||||
Self {
|
||||
data,
|
||||
rom_len,
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
use super::{rom_banks, Mbc, ROM_BANK_SIZE};
|
||||
use super::Mbc;
|
||||
use crate::processor::memory::{
|
||||
addresses::{AddressMarker, CartRamAddress, RomAddress},
|
||||
rom::sram_save::{BufferedSramTrait, MaybeBufferedSram, SaveDataLocation},
|
||||
rom::{
|
||||
sram_save::{BufferedSramTrait, MaybeBufferedSram, SaveDataLocation},
|
||||
RomSize,
|
||||
},
|
||||
};
|
||||
|
||||
pub struct Mbc2 {
|
||||
|
@ -13,8 +16,8 @@ pub struct Mbc2 {
|
|||
}
|
||||
|
||||
impl Mbc2 {
|
||||
pub fn init(data: Vec<u8>, rom_size: u8, save_file: Option<SaveDataLocation>) -> Self {
|
||||
let rom_len = rom_banks(rom_size) * ROM_BANK_SIZE;
|
||||
pub fn init(data: Vec<u8>, rom_size: RomSize, save_file: Option<SaveDataLocation>) -> Self {
|
||||
let rom_len = rom_size.size_bytes();
|
||||
let ram = MaybeBufferedSram::new(save_file, 512);
|
||||
|
||||
Self {
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
||||
use super::{Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
||||
use crate::{
|
||||
processor::memory::{
|
||||
addresses::{AddressMarker, CartRamAddress, RomAddress},
|
||||
rom::sram_save::{BufferedSramTrait, MaybeBufferedSram, SaveDataLocation},
|
||||
rom::{
|
||||
sram_save::{BufferedSramTrait, MaybeBufferedSram, SaveDataLocation},
|
||||
RamSize, RomSize,
|
||||
},
|
||||
},
|
||||
util::set_or_clear_bit,
|
||||
};
|
||||
|
@ -95,19 +98,21 @@ pub struct Mbc3 {
|
|||
impl Mbc3 {
|
||||
pub fn init(
|
||||
data: Vec<u8>,
|
||||
rom_size: u8,
|
||||
ram_size: u8,
|
||||
rom_size: RomSize,
|
||||
ram_size: Option<RamSize>,
|
||||
rtc: bool,
|
||||
save_file: Option<SaveDataLocation>,
|
||||
) -> Self {
|
||||
let ram = ram_size_kb(ram_size).map(|s| MaybeBufferedSram::new(save_file, s * KB));
|
||||
let ram = ram_size
|
||||
.as_ref()
|
||||
.map(|s| MaybeBufferedSram::new(save_file, s.size_bytes()));
|
||||
Self {
|
||||
data,
|
||||
rom_bank: 1,
|
||||
rom_size: rom_banks(rom_size) * ROM_BANK_SIZE,
|
||||
rom_size: rom_size.size_bytes(),
|
||||
ram,
|
||||
ram_bank: RamBank::Ram(0),
|
||||
ram_size: ram_size_kb(ram_size).map_or(1, |s| s * KB),
|
||||
ram_size: ram_size.map(|s| s.size_bytes()).unwrap_or(0),
|
||||
ram_enabled: false,
|
||||
rtc: if rtc { Some(Rtc::default()) } else { None },
|
||||
}
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
use crate::{
|
||||
processor::memory::{
|
||||
addresses::{AddressMarker, CartRamAddress, RomAddress},
|
||||
rom::sram_save::{BufferedSramTrait, MaybeBufferedSram, SaveDataLocation},
|
||||
rom::{
|
||||
sram_save::{BufferedSramTrait, MaybeBufferedSram, SaveDataLocation},
|
||||
RamSize, RomSize,
|
||||
},
|
||||
},
|
||||
util::get_bit,
|
||||
};
|
||||
|
||||
use super::{ram_size_kb, rom_banks, Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
||||
use super::{Mbc, KB, RAM_BANK_SIZE, ROM_BANK_SIZE};
|
||||
|
||||
pub struct Mbc5 {
|
||||
data: Vec<u8>,
|
||||
|
@ -23,19 +26,21 @@ pub struct Mbc5 {
|
|||
impl Mbc5 {
|
||||
pub fn init(
|
||||
data: Vec<u8>,
|
||||
rom_size: u8,
|
||||
ram_size: u8,
|
||||
rom_size: RomSize,
|
||||
ram_size: Option<RamSize>,
|
||||
rumble: bool,
|
||||
save_file: Option<SaveDataLocation>,
|
||||
) -> Self {
|
||||
let ram = ram_size_kb(ram_size).map(|s| MaybeBufferedSram::new(save_file, s * KB));
|
||||
let ram = ram_size
|
||||
.as_ref()
|
||||
.map(|s| MaybeBufferedSram::new(save_file, s.size_bytes()));
|
||||
Self {
|
||||
data,
|
||||
rom_bank: 1,
|
||||
rom_size: rom_banks(rom_size) * ROM_BANK_SIZE,
|
||||
rom_size: rom_size.size_bytes(),
|
||||
ram,
|
||||
ram_bank: 0,
|
||||
ram_size: ram_size_kb(ram_size).map_or(1, |s| s * KB),
|
||||
ram_size: ram_size.map(|s| s.size_bytes()).unwrap_or(0),
|
||||
ram_enabled: false,
|
||||
rumble,
|
||||
is_rumbling: false,
|
||||
|
|
Loading…
Reference in a new issue