Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/mes-core/src/bus/ppu.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
bus::Bus,
cartridge::Mirroring,
mappers::{Mapper, MapperChip},
rom::Mirroring,
utils::{Clock, Reset},
};

Expand Down
2 changes: 1 addition & 1 deletion crates/mes-core/src/features/json.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{cartridge::Header, error::Error};
use crate::{error::Error, rom::ines::Header};

pub fn serialize_rom_header(bytes: &[u8]) -> Result<String, Error> {
let header = Header::try_from_bytes(bytes)?;
Expand Down
2 changes: 1 addition & 1 deletion crates/mes-core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
pub mod apu;
pub mod bus;
pub mod cartridge;
pub mod controller;
pub mod cpu;
pub mod error;
pub mod mappers;
pub mod ppu;
pub mod rom;
pub mod utils;

mod features;
Expand Down
5 changes: 4 additions & 1 deletion crates/mes-core/src/mappers/mapper_000.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

use super::Mapper;
use crate::{
cartridge::{Cartridge, ChrPage, Mirroring, PrgPage},
rom::{
cartridge::{Cartridge, ChrPage, PrgPage},
Mirroring,
},
utils::Reset,
};

Expand Down
7 changes: 5 additions & 2 deletions crates/mes-core/src/mappers/mapper_001.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

use super::Mapper;
use crate::{
cartridge::{Cartridge, ChrPage, Mirroring, PrgPage},
rom::{
cartridge::{Cartridge, ChrPage, PrgPage},
Mirroring,
},
utils::{BitFlag, Reset},
};

Expand Down Expand Up @@ -102,7 +105,7 @@ impl Mapper for SxRom {
}
}

fn get_mirroring(&self) -> crate::cartridge::Mirroring {
fn get_mirroring(&self) -> crate::rom::Mirroring {
match self.control & 0b11 {
2 => Mirroring::Vertical,
3 => Mirroring::Horizontal,
Expand Down
5 changes: 4 additions & 1 deletion crates/mes-core/src/mappers/mapper_002.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

use super::Mapper;
use crate::{
cartridge::{Cartridge, ChrPage, Mirroring, PrgPage},
rom::{
cartridge::{Cartridge, ChrPage, PrgPage},
Mirroring,
},
utils::Reset,
};

Expand Down
5 changes: 4 additions & 1 deletion crates/mes-core/src/mappers/mapper_003.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

use super::Mapper;
use crate::{
cartridge::{Cartridge, ChrPage, Mirroring, PrgPage},
rom::{
cartridge::{Cartridge, ChrPage, PrgPage},
Mirroring,
},
utils::Reset,
};

Expand Down
6 changes: 3 additions & 3 deletions crates/mes-core/src/mappers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ mod mapper_003;
use self::{mapper_000::NRom, mapper_001::SxRom, mapper_002::UxRom, mapper_003::CnRom};

use crate::{
cartridge::{Cartridge, Mirroring},
error::Error,
rom::{cartridge::Cartridge, Mirroring},
utils::{MemoryObserver, Reset},
};

Expand All @@ -26,7 +26,7 @@ pub struct MapperBuilder {
impl MapperBuilder {
pub fn new(cartridge: &[u8]) -> Result<Self, Error> {
Ok(Self {
cartridge: Cartridge::try_from_bytes(cartridge)?,
cartridge: Cartridge::try_from_ines(cartridge)?,
})
}

Expand Down Expand Up @@ -58,7 +58,7 @@ impl MapperChip {
}

pub fn try_from_bytes(bytes: &[u8]) -> Result<Self, Error> {
Cartridge::try_from_bytes(bytes).and_then(MapperChip::try_from)
Cartridge::try_from_ines(bytes).and_then(MapperChip::try_from)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,81 +1,14 @@
// https://www.nesdev.org/wiki/INES
use crate::{error::Error, utils::MemoryObserver};

use crate::{
error::Error,
utils::{BitFlag, MemoryObserver},
use super::{
ines::{Header, INES_HEADER_SIZE, TRAINER_SIZE},
Mirroring,
};

#[cfg(feature = "json")]
use serde::Serialize;

const INES_ASCII: [u8; 4] = [0x4E, 0x45, 0x53, 0x1A];
const INES_HEADER_SIZE: usize = 16;
const TRAINER_SIZE: usize = 512;
const PRG_ROM_PAGE_SIZE: usize = 16384;
const PRG_RAM_SIZE: usize = 8192;
const CHR_ROM_PAGE_SIZE: usize = 8192;
const CHR_RAM_PAGE_SIZE: usize = 8192;

pub fn is_ines_file(bytes: &[u8]) -> bool {
bytes[0..4] == INES_ASCII
}

#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "json", derive(Serialize))]
pub enum Mirroring {
Vertical,
Horizontal,
OneScreen,
FourScreen,
}

#[derive(Debug)]
#[cfg_attr(feature = "json", derive(Serialize))]
pub struct Header {
pub prg_rom_pages: u8,
pub chr_rom_pages: u8,
pub prg_ram_pages: u8,
pub mirroring: Mirroring,
pub battery: bool,
pub trainer: bool,
pub mapper: u8,
}

impl Header {
pub fn try_from_bytes(bytes: &[u8]) -> Result<Self, Error> {
if !is_ines_file(bytes) {
return Err(Error::UnsupportedFileFormat);
}

let prg_rom_pages = *bytes.get(4).ok_or(Error::eof("PRG ROM pages", 1))?;
let chr_rom_pages = *bytes.get(5).ok_or(Error::eof("CHR ROM pages", 1))?;
let flags_6 = bytes.get(6).ok_or(Error::eof("Flags 6", 1))?;
let flags_7 = bytes.get(7).ok_or(Error::eof("Flags 7", 1))?;
let prg_ram_pages = *bytes.get(8).ok_or(Error::eof("PRG RAM pages", 1))?;

let battery = flags_6.contains(1);
let trainer = flags_6.contains(2);
let mapper = (flags_7 & 0xF0) | (flags_6 >> 4);
let is_vertical_mirroring = flags_6.contains(0);
let is_four_screen = flags_6.contains(3);

let mirroring = match (is_four_screen, is_vertical_mirroring) {
(true, _) => Mirroring::FourScreen,
(false, true) => Mirroring::Vertical,
(false, false) => Mirroring::Horizontal,
};

Ok(Self {
prg_rom_pages,
prg_ram_pages,
chr_rom_pages,
mirroring,
battery,
trainer,
mapper,
})
}
}
pub const PRG_ROM_PAGE_SIZE: usize = 16384;
pub const PRG_RAM_SIZE: usize = 8192;
pub const CHR_ROM_PAGE_SIZE: usize = 8192;
pub const CHR_RAM_PAGE_SIZE: usize = 8192;

pub enum ChrPage {
Index4(u8),
Expand Down Expand Up @@ -104,7 +37,7 @@ impl std::fmt::Debug for Cartridge {
}

impl Cartridge {
pub fn try_from_bytes(bytes: &[u8]) -> Result<Self, Error> {
pub fn try_from_ines(bytes: &[u8]) -> Result<Self, Error> {
let header = Header::try_from_bytes(bytes)?;

let prg_rom_size = header.prg_rom_pages as usize * PRG_ROM_PAGE_SIZE;
Expand All @@ -113,8 +46,7 @@ impl Cartridge {
let chr_rom_start = prg_rom_start + prg_rom_size;
let prg_rom = bytes[prg_rom_start..prg_rom_start + prg_rom_size].to_vec();
let chr_rom = bytes[chr_rom_start..chr_rom_start + chr_rom_size].to_vec();
let prg_ram_size = PRG_RAM_SIZE;
let prg_ram = vec![0_u8; prg_ram_size];
let prg_ram = vec![0_u8; PRG_RAM_SIZE];
let chr_ram_size = (header.chr_rom_pages == 0) as usize * CHR_RAM_PAGE_SIZE;
let chr_ram = vec![0_u8; chr_ram_size];

Expand Down Expand Up @@ -207,7 +139,7 @@ mod tests {

#[test]
fn test_load_rom() {
let rom = Cartridge::try_from_bytes(&NESTEST_ROM);
let rom = Cartridge::try_from_ines(&NESTEST_ROM);

assert!(rom.is_ok());
}
Expand Down
Empty file added crates/mes-core/src/rom/fds.rs
Empty file.
62 changes: 62 additions & 0 deletions crates/mes-core/src/rom/ines.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#[cfg(feature = "json")]
use serde::Serialize;

use crate::{error::Error, utils::BitFlag};

use super::Mirroring;

pub const INES_ASCII: [u8; 4] = [0x4E, 0x45, 0x53, 0x1A];
pub const INES_HEADER_SIZE: usize = 16;
pub const TRAINER_SIZE: usize = 512;

pub fn is_ines_file(bytes: &[u8]) -> bool {
bytes[0..4] == INES_ASCII
}

#[derive(Debug)]
#[cfg_attr(feature = "json", derive(Serialize))]
pub struct Header {
pub prg_rom_pages: u8,
pub chr_rom_pages: u8,
pub prg_ram_pages: u8,
pub mirroring: Mirroring,
pub battery: bool,
pub trainer: bool,
pub mapper: u8,
}

impl Header {
pub fn try_from_bytes(bytes: &[u8]) -> Result<Self, Error> {
if !is_ines_file(bytes) {
return Err(Error::UnsupportedFileFormat);
}

let prg_rom_pages = *bytes.get(4).ok_or(Error::eof("PRG ROM pages", 1))?;
let chr_rom_pages = *bytes.get(5).ok_or(Error::eof("CHR ROM pages", 1))?;
let flags_6 = bytes.get(6).ok_or(Error::eof("Flags 6", 1))?;
let flags_7 = bytes.get(7).ok_or(Error::eof("Flags 7", 1))?;
let prg_ram_pages = *bytes.get(8).ok_or(Error::eof("PRG RAM pages", 1))?;

let battery = flags_6.contains(1);
let trainer = flags_6.contains(2);
let mapper = (flags_7 & 0xF0) | (flags_6 >> 4);
let is_vertical_mirroring = flags_6.contains(0);
let is_four_screen = flags_6.contains(3);

let mirroring = match (is_four_screen, is_vertical_mirroring) {
(true, _) => Mirroring::FourScreen,
(false, true) => Mirroring::Vertical,
(false, false) => Mirroring::Horizontal,
};

Ok(Self {
prg_rom_pages,
prg_ram_pages,
chr_rom_pages,
mirroring,
battery,
trainer,
mapper,
})
}
}
17 changes: 17 additions & 0 deletions crates/mes-core/src/rom/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// https://www.nesdev.org/wiki/INES

pub mod cartridge;
pub mod fds;
pub mod ines;

#[cfg(feature = "json")]
use serde::Serialize;

#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "json", derive(Serialize))]
pub enum Mirroring {
Vertical,
Horizontal,
OneScreen,
FourScreen,
}