diff --git a/src/snes/cartridge.rs b/src/snes/cartridge.rs index eb5e446..444d5aa 100644 --- a/src/snes/cartridge.rs +++ b/src/snes/cartridge.rs @@ -5,7 +5,8 @@ use num_traits::FromPrimitive; use serde::{Deserialize, Serialize}; use strum::Display; -use crate::snes::bus::{Address, BusMember}; +use super::bus::{Address, BusMember}; +use super::coprocessor::dspx::DSPx; const HDR_TITLE_OFFSET: usize = 0x00; const HDR_TITLE_SIZE: usize = 21; @@ -36,6 +37,16 @@ pub enum Chipset { RomCoBat = 6, } +#[derive(Debug, Clone, Copy, Eq, PartialEq, FromPrimitive)] +pub enum CoProcessor { + DSPx = 0, + SuperFX = 1, + OBC1 = 2, + SA1 = 3, + SDD1 = 4, + SRTC = 5, +} + #[derive(Debug, Clone, Copy, Eq, PartialEq, FromPrimitive)] pub enum MapMode { LoROM = 0, @@ -55,6 +66,12 @@ pub struct Cartridge { /// RAM address mask, to properly emulate mirroring ram_mask: usize, + + /// ROM address mask + rom_mask: usize, + + /// DSP-x co-processor + co_dspx: Option, } impl Cartridge { @@ -93,6 +110,16 @@ impl Cartridge { (1 << self.rom[self.header_offset + HDR_RAMSIZE_OFFSET]) * 1024 } + fn get_coprocessor(&self) -> Option { + match self.get_chipset() { + Chipset::RomCo | Chipset::RomRamCo | Chipset::RomRamCoBat | Chipset::RomCoBat => Some( + CoProcessor::from_u8(self.rom[self.header_offset + HDR_CHIPSET_OFFSET] & 0xF0) + .unwrap(), + ), + _ => None, + } + } + pub fn get_video_format(&self) -> VideoFormat { match self.rom[self.header_offset + HDR_DESTINATION_OFFSET] { 0x00 // Japan @@ -149,8 +176,20 @@ impl Cartridge { hirom: false, header_offset: header_offset.expect("Could not locate header"), ram_mask: 0, + rom_mask: (rom.len() - load_offset - 1), + co_dspx: None, }; + // Detect / initialize co-processor + match c.get_coprocessor() { + Some(CoProcessor::DSPx) => { + println!("DSP-x co-processor detected"); + c.co_dspx = Some(DSPx::new()); + } + Some(c) => println!("Warning: unimplemented co-processor: {:?}", c), + None => (), + } + // TODO refactor header to its own struct c.hirom = match c.get_map() { MapMode::HiROM => true, @@ -168,6 +207,8 @@ impl Cartridge { hirom, header_offset: 0, ram_mask: RAM_SIZE - 1, + rom_mask: rom.len() - 1, + co_dspx: None, } } @@ -180,6 +221,8 @@ impl Cartridge { hirom: false, header_offset: 0, ram_mask: RAM_SIZE - 1, + rom_mask: usize::MAX, + co_dspx: None, } } } @@ -206,8 +249,9 @@ impl BusMember
for Cartridge { match (bank, addr) { // HiROM (mirrors in LoROM banks) (0x00..=0x3F | 0x80..=0xBF, 0x8000..=0xFFFF) if self.hirom => { - Some(self.rom[addr - 0x0000 + (bank & !0x80) * 0x10000]) + Some(self.rom[(addr - 0x0000 + (bank & !0x80) * 0x10000) & self.rom_mask]) } + // LoROM (0x00..=0x3F | 0x80..=0xFF, 0x8000..=0xFFFF) if !self.hirom => { Some(self.rom[addr - 0x8000 + (bank & !0x80) * 0x8000]) @@ -220,7 +264,7 @@ impl BusMember
for Cartridge { // HiROM (0x40..=0x6F, _) if self.hirom => { - Some(self.rom[(addr + ((bank - 0x40) * 0x10000)) % self.rom.len()]) + Some(self.rom[(addr + ((bank - 0x40) * 0x10000)) & self.rom_mask]) } // LoROM SRAM @@ -229,7 +273,15 @@ impl BusMember
for Cartridge { } // HiROM - (0xC0..=0xFF, _) if self.hirom => Some(self.rom[addr + ((bank - 0xC0) * 0x10000)]), + (0xC0..=0xFF, _) if self.hirom => { + Some(self.rom[(addr + ((bank - 0xC0) * 0x10000)) & self.rom_mask]) + } + + // DSP-x co-processor + (0x00..=0xDF, 0x6000..=0x7FFF) if self.co_dspx.is_some() => { + let dspx = self.co_dspx.as_ref().unwrap(); + dspx.read(fulladdr) + } _ => None, } @@ -249,6 +301,12 @@ impl BusMember
for Cartridge { Some(self.ram[(bank - 0x70) * 0x8000 + addr & self.ram_mask] = val) } + // DSP-x co-processor + (0x00..=0xDF, 0x6000..=0x7FFF) if self.co_dspx.is_some() => { + let dspx = self.co_dspx.as_mut().unwrap(); + dspx.write(fulladdr, val) + } + _ => None, } } diff --git a/src/snes/coprocessor/dspx.rs b/src/snes/coprocessor/dspx.rs new file mode 100644 index 0000000..36fd78e --- /dev/null +++ b/src/snes/coprocessor/dspx.rs @@ -0,0 +1,39 @@ +use serde::{Deserialize, Serialize}; + +use crate::snes::bus::{Address, BusMember}; + +/// DSP-x co-processor +#[derive(Serialize, Deserialize)] +pub struct DSPx {} + +impl DSPx { + pub fn new() -> Self { + Self {} + } +} + +impl BusMember
for DSPx { + fn read(&self, fulladdr: Address) -> Option { + let (bank, addr) = ((fulladdr >> 16) as usize, (fulladdr & 0xFFFF) as usize); + + match addr { + 0x7000 => { + // SR (LSB) + Some(0) + } + 0x7001 => { + // SR (MSB) + Some(0x80) + } + _ => None, + } + } + + fn write(&mut self, fulladdr: Address, val: u8) -> Option<()> { + let (bank, addr) = ((fulladdr >> 16) as usize, (fulladdr & 0xFFFF) as usize); + + match addr { + _ => None, + } + } +} diff --git a/src/snes/coprocessor/mod.rs b/src/snes/coprocessor/mod.rs new file mode 100644 index 0000000..8379670 --- /dev/null +++ b/src/snes/coprocessor/mod.rs @@ -0,0 +1 @@ +pub mod dspx; diff --git a/src/snes/mod.rs b/src/snes/mod.rs index af953e0..c61b6a1 100644 --- a/src/snes/mod.rs +++ b/src/snes/mod.rs @@ -1,6 +1,7 @@ pub mod apu; pub mod bus; pub mod cartridge; +pub mod coprocessor; pub mod cpu_65816; pub mod cpu_spc700; pub mod joypad;