From 09b66ccda165095475da73d5af819dd0af8097ac Mon Sep 17 00:00:00 2001 From: JakeBreath Date: Fri, 7 Aug 2026 21:19:33 -0500 Subject: [PATCH] implemented working Cartridge for NROm/Mapper 0 --- Cargo.lock | 7 ++++ src/bus.rs | 0 src/cartridge.rs | 85 ++++++++++++++++++++++++++++++++++++++++++++++++ src/cpu.rs | 0 src/main.rs | 2 ++ 5 files changed, 94 insertions(+) create mode 100644 Cargo.lock create mode 100644 src/bus.rs create mode 100644 src/cartridge.rs create mode 100644 src/cpu.rs diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..333a95b --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "rnes" +version = "0.1.0" diff --git a/src/bus.rs b/src/bus.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/cartridge.rs b/src/cartridge.rs new file mode 100644 index 0000000..76204fc --- /dev/null +++ b/src/cartridge.rs @@ -0,0 +1,85 @@ + +pub enum Mirroring { Horizontal, Vertical, FourScreen } + +pub struct Cartridge { + prg_rom: Vec, + chr_rom: Vec, + mirroring: Mirroring, + battery: bool, + trainer: bool, + four_screen: bool, + mapper: u8, +} + +impl Cartridge { + pub fn from_file(path: &str) -> Result { + let data: Vec = std::fs::read(path).map_err(|e| format!("couldn't read {path}: {e}"))?; + if data.len() < 16 { + return Err("file is too short to be an iNES ROM".to_string()) + } + + if &data[0..4] != b"NES\x1a" { + return Err("not a valid iNES ROM (bad magic numbers)".to_string()) + } + + // Extract the bytes we care about + let prg_banks: u8 = data[4]; + let chr_banks: u8 = data[5]; + let flags6: u8 = data[6]; + let flags7: u8 = data[7]; + + // Decode bits from the bytes on the ROM + let mirroring: Mirroring = if flags6 & 0b0001 != 0 { Mirroring::Vertical} else { Mirroring::Horizontal }; + let battery: bool = flags6 & 0b0010 != 0; + let trainer: bool = flags6 & 0b0100 != 0; + let four_screen: bool = flags6 & 0b1000 != 0; // this is meant to override mirroring but both will be stored + let mapper: u8 = ((flags7 & 0xF0) >> 4) << 4 | ((flags6 & 0xF0) >> 4); + + // Gate for Mapper as we are going NROM-only for now + + if mapper != 0 { + return Err(format!("mapper {mapper} not supported yet, this is temporal")); + } + + // Compute the ROM offsets for future use + + let prg_start: usize = 16 + if trainer { 512 } else { 0 }; // i'd like to call this padding but on the spec it gets called a "Trainer" so it stays like that + let prg_len: usize = (prg_banks as usize) * 0x4000; + let chr_start: usize = prg_start + prg_len; + let chr_len: usize = (chr_banks as usize) * 0x2000; + + if prg_start + prg_len > data.len() || chr_start + chr_len > data.len() { + return Err("ROM data truncated or changed".to_string()); + } + + // Construct and return a valid Cartridge + + Ok(Cartridge { + prg_rom: data[prg_start..prg_start + prg_len].to_vec(), + chr_rom: if chr_len == 0 { vec![0u8; 0x2000] } else { data[chr_start..chr_start + chr_len].to_vec() }, // Vector of 8KB filled with 0's or the actual CHR ROM data + mirroring, + battery, + trainer, + four_screen, + mapper, + }) + } + + // read_* operations are for the CPU to work with, letting it read the ROM chips on the emulated cartridge + pub fn read_prg(&self, address: u16) -> u8 { + debug_assert!(address >= 0x8000, "PRG read outside of $8000-$FFFF; Address from CPU: {address:#06X}"); // #06X makes the Address readable similar to $1FFF + let mut offset: u16 = address - 0x8000; + if self.prg_rom.len() == 0x4000 { + offset %= 0x4000; + } + self.prg_rom[offset as usize] + } + pub fn read_chr(&self, address: u16) -> u8 { + debug_assert!(address < 0x2000, "CHR reads outside $0000-$1FFF; Address from CPU: {address:#06X}"); + self.chr_rom[address as usize] + } + pub fn write_chr(&mut self, address: u16, value: u8) { + debug_assert!(address < 0x2000, "CHR writes outside $0000-$1FFF; Address from CPU: {address:#06X}"); + self.chr_rom[address as usize] = value + } +} \ No newline at end of file diff --git a/src/cpu.rs b/src/cpu.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/main.rs b/src/main.rs index e7a11a9..ed3eee0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +mod cartridge; + fn main() { println!("Hello, world!"); }