Compare commits
2 Commits
8b78b2943e
...
1f8fa48168
Author | SHA1 | Date |
---|---|---|
Rekai Nyangadzayi Musuka | 1f8fa48168 | |
Rekai Nyangadzayi Musuka | c6fbb79189 |
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"matklad.rust-analyzer",
|
||||||
|
"tamasfe.even-better-toml",
|
||||||
|
"serayuzgur.crates",
|
||||||
|
"vadimcn.vscode-lldb",
|
||||||
|
]
|
||||||
|
}
|
112
src/cartridge.rs
112
src/cartridge.rs
|
@ -33,18 +33,19 @@ impl Cartridge {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn detect_mbc(memory: &[u8]) -> Box<dyn MBCIo> {
|
fn detect_mbc(memory: &[u8]) -> Box<dyn MBCIo> {
|
||||||
let ram_size = Self::detect_ram_size(memory);
|
let ram_info = Self::detect_ram_info(memory);
|
||||||
let rom_size = Self::detect_rom_size(memory);
|
let rom_info = Self::detect_rom_info(memory);
|
||||||
let mbc_kind = Self::find_mbc(memory);
|
let mbc_kind = Self::find_mbc(memory);
|
||||||
|
let ram_size = ram_info.size();
|
||||||
|
|
||||||
eprintln!("Cartridge Ram Size: {} bytes", ram_size.len());
|
eprintln!("Cartridge Ram Size: {} bytes", ram_size);
|
||||||
eprintln!("Cartridge ROM Size: {} bytes", rom_size.size());
|
eprintln!("Cartridge ROM Size: {} bytes", rom_info.size());
|
||||||
eprintln!("MBC Type: {:?}", mbc_kind);
|
eprintln!("MBC Type: {:?}", mbc_kind);
|
||||||
|
|
||||||
match mbc_kind {
|
match mbc_kind {
|
||||||
MBCKind::None => Box::new(NoMBC),
|
MBCKind::None => Box::new(NoMBC),
|
||||||
MBCKind::MBC1 => Box::new(MBC1::new(ram_size, rom_size)),
|
MBCKind::MBC1 => Box::new(MBC1::new(ram_info, rom_info)),
|
||||||
MBCKind::MBC1WithBattery => Box::new(MBC1::new(ram_size, rom_size)), // TODO: Implement Saving
|
MBCKind::MBC1WithBattery => Box::new(MBC1::new(ram_info, rom_info)), // TODO: Implement Saving
|
||||||
MBCKind::MBC3 => Box::new(MBC3::new(ram_size)),
|
MBCKind::MBC3 => Box::new(MBC3::new(ram_size)),
|
||||||
MBCKind::MBC3WithBattery => Box::new(MBC3::new(ram_size)), // TODO: Implement Saving
|
MBCKind::MBC3WithBattery => Box::new(MBC3::new(ram_size)), // TODO: Implement Saving
|
||||||
MBCKind::MBC5 => Box::new(MBC5::new(ram_size)),
|
MBCKind::MBC5 => Box::new(MBC5::new(ram_size)),
|
||||||
|
@ -67,13 +68,13 @@ impl Cartridge {
|
||||||
self.title.as_deref()
|
self.title.as_deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn detect_ram_size(memory: &[u8]) -> RamSize {
|
fn detect_ram_info(memory: &[u8]) -> RamInfo {
|
||||||
let id = memory[RAM_SIZE_ADDRESS];
|
let id = memory[RAM_SIZE_ADDRESS];
|
||||||
id.into()
|
id.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn detect_rom_size(memory: &[u8]) -> RomSize {
|
fn detect_rom_info(memory: &[u8]) -> RomInfo {
|
||||||
let id = memory[ROM_SIZE_ADDRESS];
|
let id = dbg!(memory[ROM_SIZE_ADDRESS]);
|
||||||
id.into()
|
id.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,17 +114,17 @@ struct MBC1 {
|
||||||
/// 2-bit number
|
/// 2-bit number
|
||||||
ram_bank: u8,
|
ram_bank: u8,
|
||||||
mode: bool,
|
mode: bool,
|
||||||
ram_size: RamSize,
|
ram_size: RamInfo,
|
||||||
memory: Vec<u8>,
|
memory: Vec<u8>,
|
||||||
rom_size: RomSize,
|
rom_size: RomInfo,
|
||||||
mem_enabled: bool,
|
mem_enabled: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MBC1 {
|
impl MBC1 {
|
||||||
fn new(ram_size: RamSize, rom_size: RomSize) -> Self {
|
fn new(ram_size: RamInfo, rom_size: RomInfo) -> Self {
|
||||||
Self {
|
Self {
|
||||||
rom_bank: 0x01,
|
rom_bank: 0x01,
|
||||||
memory: vec![0; ram_size.len() as usize],
|
memory: vec![0; ram_size.size() as usize],
|
||||||
ram_size,
|
ram_size,
|
||||||
rom_size,
|
rom_size,
|
||||||
ram_bank: Default::default(),
|
ram_bank: Default::default(),
|
||||||
|
@ -133,7 +134,7 @@ impl MBC1 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zero_bank(&self) -> u8 {
|
fn zero_bank(&self) -> u8 {
|
||||||
use RomSize::*;
|
use RomInfo::*;
|
||||||
|
|
||||||
match self.rom_size {
|
match self.rom_size {
|
||||||
None | Four | Eight | Sixteen | ThirtyTwo => 0x00,
|
None | Four | Eight | Sixteen | ThirtyTwo => 0x00,
|
||||||
|
@ -144,7 +145,7 @@ impl MBC1 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _mbcm_zero_bank(&self) -> u8 {
|
fn _mbcm_zero_bank(&self) -> u8 {
|
||||||
use RomSize::*;
|
use RomInfo::*;
|
||||||
|
|
||||||
match self.rom_size {
|
match self.rom_size {
|
||||||
None | Four | Eight | Sixteen | ThirtyTwo => 0x00,
|
None | Four | Eight | Sixteen | ThirtyTwo => 0x00,
|
||||||
|
@ -155,7 +156,7 @@ impl MBC1 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn high_bank(&self) -> u8 {
|
fn high_bank(&self) -> u8 {
|
||||||
use RomSize::*;
|
use RomInfo::*;
|
||||||
|
|
||||||
let base = self.rom_bank & self.rom_size_mask();
|
let base = self.rom_bank & self.rom_size_mask();
|
||||||
|
|
||||||
|
@ -168,7 +169,7 @@ impl MBC1 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rom_size_mask(&self) -> u8 {
|
fn rom_size_mask(&self) -> u8 {
|
||||||
use RomSize::*;
|
use RomInfo::*;
|
||||||
|
|
||||||
match self.rom_size {
|
match self.rom_size {
|
||||||
None => 0b00000001,
|
None => 0b00000001,
|
||||||
|
@ -181,11 +182,11 @@ impl MBC1 {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ram_addr(&self, addr: u16) -> u16 {
|
fn ram_addr(&self, addr: u16) -> u16 {
|
||||||
use RamSize::*;
|
use RamInfo::*;
|
||||||
|
|
||||||
match self.ram_size {
|
match self.ram_size {
|
||||||
Two | Eight => (addr - 0xA000) % self.ram_size.len() as u16,
|
Unused | One => (addr - 0xA000) % self.ram_size.size() as u16,
|
||||||
ThirtyTwo => {
|
Four => {
|
||||||
if self.mode {
|
if self.mode {
|
||||||
0x2000 * self.ram_bank as u16 + (addr - 0xA000)
|
0x2000 * self.ram_bank as u16 + (addr - 0xA000)
|
||||||
} else {
|
} else {
|
||||||
|
@ -269,9 +270,9 @@ struct MBC3 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MBC3 {
|
impl MBC3 {
|
||||||
fn new(ram_size: RamSize) -> Self {
|
fn new(ram_size: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
memory: vec![0; ram_size.len() as usize],
|
memory: vec![0; ram_size],
|
||||||
rom_bank: Default::default(),
|
rom_bank: Default::default(),
|
||||||
ram_bank: Default::default(),
|
ram_bank: Default::default(),
|
||||||
devs_enabled: Default::default(),
|
devs_enabled: Default::default(),
|
||||||
|
@ -356,10 +357,10 @@ struct MBC5 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MBC5 {
|
impl MBC5 {
|
||||||
fn new(ram_size: RamSize) -> Self {
|
fn new(ram_size: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
rom_bank: 0x01,
|
rom_bank: 0x01,
|
||||||
memory: vec![0; ram_size.len() as usize],
|
memory: vec![0; ram_size],
|
||||||
ram_bank: Default::default(),
|
ram_bank: Default::default(),
|
||||||
mem_enabled: Default::default(),
|
mem_enabled: Default::default(),
|
||||||
}
|
}
|
||||||
|
@ -440,54 +441,54 @@ impl Default for MBCKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum RamSize {
|
enum RamInfo {
|
||||||
None = 0x00,
|
None = 0x00,
|
||||||
Two = 0x01,
|
Unused = 0x01,
|
||||||
Eight = 0x02,
|
One = 0x02,
|
||||||
ThirtyTwo = 0x03, // Split into 4 RAM banks
|
Four = 0x03,
|
||||||
OneHundredTwentyEight = 0x04, // Split into 16 RAM banks
|
Sixteen = 0x04,
|
||||||
SixtyFour = 0x05, // Split into 8 RAm Banks
|
Eight = 0x05,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RamSize {
|
impl RamInfo {
|
||||||
fn len(&self) -> u32 {
|
fn size(&self) -> usize {
|
||||||
use RamSize::*;
|
use RamInfo::*;
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
None => 0,
|
None => 0,
|
||||||
Two => 2_048,
|
Unused => 0x800,
|
||||||
Eight => 8_192,
|
One => 0x2000,
|
||||||
ThirtyTwo => 32_768,
|
Four => 0x8000,
|
||||||
OneHundredTwentyEight => 131_072,
|
Sixteen => 0x20000,
|
||||||
SixtyFour => 65_536,
|
Eight => 0x10000,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RamSize {
|
impl Default for RamInfo {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::None
|
Self::None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u8> for RamSize {
|
impl From<u8> for RamInfo {
|
||||||
fn from(byte: u8) -> Self {
|
fn from(byte: u8) -> Self {
|
||||||
use RamSize::*;
|
use RamInfo::*;
|
||||||
|
|
||||||
match byte {
|
match byte {
|
||||||
0x00 => None,
|
0x00 => None,
|
||||||
0x01 => Two,
|
0x01 => Unused,
|
||||||
0x02 => Eight,
|
0x02 => One,
|
||||||
0x03 => ThirtyTwo,
|
0x03 => Four,
|
||||||
0x04 => OneHundredTwentyEight,
|
0x04 => Sixteen,
|
||||||
0x05 => SixtyFour,
|
0x05 => Eight,
|
||||||
_ => unreachable!("{:#04X} is not a valid value for RAMSize", byte),
|
_ => unreachable!("{:#04X} is not a valid value for RAMSize", byte),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum RomSize {
|
enum RomInfo {
|
||||||
None = 0x00, // 32KB (also called Two)
|
None = 0x00, // 32KB (also called Two)
|
||||||
Four = 0x01, // 64KB
|
Four = 0x01, // 64KB
|
||||||
Eight = 0x02, // 128KB
|
Eight = 0x02, // 128KB
|
||||||
|
@ -502,24 +503,23 @@ enum RomSize {
|
||||||
NinetySix = 0x54, // 1.5MB
|
NinetySix = 0x54, // 1.5MB
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RomSize {
|
impl RomInfo {
|
||||||
// https://hacktix.github.io/GBEDG/mbcs/#rom-size
|
// https://hacktix.github.io/GBEDG/mbcs/#rom-size
|
||||||
fn size(&self) -> u32 {
|
fn size(&self) -> u32 {
|
||||||
use RomSize::*;
|
use RomInfo::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
None | Four | Eight | Sixteen | ThirtyTwo | SixtyFour | OneTwentyEight
|
SeventyTwo => 0x120000,
|
||||||
| TwoFiftySix | FiveHundredTwelve => 2 << (14 + *self as u8),
|
Eighty => 0x140000,
|
||||||
SeventyTwo => 1_179_648,
|
NinetySix => 0x180000,
|
||||||
Eighty => 1_310_720,
|
_ => 0x8000 << *self as u8,
|
||||||
NinetySix => 1_572_864,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u8> for RomSize {
|
impl From<u8> for RomInfo {
|
||||||
fn from(byte: u8) -> Self {
|
fn from(byte: u8) -> Self {
|
||||||
use RomSize::*;
|
use RomInfo::*;
|
||||||
|
|
||||||
match byte {
|
match byte {
|
||||||
0x00 => None,
|
0x00 => None,
|
||||||
|
|
Loading…
Reference in New Issue