diff --git a/src/device.rs b/src/device.rs index a62cf51..42b54b0 100644 --- a/src/device.rs +++ b/src/device.rs @@ -72,7 +72,7 @@ pub fn run_game(rom_contents: Vec, device: &mut Device) { ui::input::close(&mut device.ui); ui::video::close(&device.ui); ui::audio::close(&mut device.ui); - ui::storage::write_saves(&device.ui, &device.netplay); + ui::storage::write_saves(device); } fn swap_rom(contents: Vec) -> Vec { @@ -298,19 +298,18 @@ impl Device { }, cart: cart::Cart { rom: Vec::new(), - is_viewer_buffer: [0; 0xFFFF], + is_viewer_buffer: vec![0; 0xFFFF], pal: false, latch: 0, cic_seed: 0, - cic_type: cart::CicType::CicNus6102, - rdram_size_offset: 0, rtc: cart::AfRtc { control: 0x0200 }, sc64: cart::sc64::Sc64 { regs: [0; cart::sc64::SC64_REGS_COUNT as usize], regs_locked: true, cfg: [0; cart::sc64::SC64_CFG_COUNT as usize], sector: 0, - buffer: [0; 8192], + buffer: vec![0; 8192], + writeback_sector: vec![0; 256], }, flashram: cart::sram::Flashram { status: 0, diff --git a/src/device/cart.rs b/src/device/cart.rs index 2734638..157ee36 100644 --- a/src/device/cart.rs +++ b/src/device/cart.rs @@ -45,13 +45,10 @@ fn byte2bcd(mut n: u32) -> u8 { pub struct Cart { #[serde(skip)] pub rom: Vec, - #[serde(with = "serde_big_array::BigArray")] - pub is_viewer_buffer: [u8; 0xFFFF], + pub is_viewer_buffer: Vec, pub pal: bool, pub latch: u32, - pub cic_type: CicType, pub cic_seed: u8, - pub rdram_size_offset: usize, pub rtc: AfRtc, pub sc64: sc64::Sc64, pub flashram: sram::Flashram, @@ -125,7 +122,7 @@ pub fn process(device: &mut device::Device, channel: usize) { } } -fn format_eeprom(device: &mut device::Device) { +pub fn format_eeprom(device: &mut device::Device) { if device.ui.saves.eeprom.data.len() < EEPROM_MAX_SIZE { device.ui.saves.eeprom.data.resize(EEPROM_MAX_SIZE, 0xFF) } diff --git a/src/device/cart/rom.rs b/src/device/cart/rom.rs index ad5fd58..b74f31b 100644 --- a/src/device/cart/rom.rs +++ b/src/device/cart/rom.rs @@ -4,16 +4,12 @@ use sha2::{Digest, Sha256}; const CART_MASK: usize = 0xFFFFFFF; fn read_cart_word(device: &mut device::Device, address: usize) -> u32 { - let mut data: [u8; 4] = device.cart.rom[address..address + 4].try_into().unwrap(); + let mut data: [u8; 4] = [0; 4]; for i in 0..4 { - if device - .ui - .saves - .romsave - .data - .contains_key(&(address as u32 + i)) - { - data[i as usize] = device.ui.saves.romsave.data[&(address as u32 + i)]; + if let Some(value) = device.ui.saves.romsave.data.get(&(address as u32 + i)) { + data[i as usize] = *value; + } else { + data[i as usize] = *device.cart.rom.get(address + i as usize).unwrap_or(&0); } } u32::from_be_bytes(data) @@ -46,7 +42,9 @@ pub fn read_mem( } pub fn write_mem(device: &mut device::Device, address: u64, value: u32, mask: u32) { - if device.cart.sc64.cfg[device::cart::sc64::SC64_ROM_WRITE_ENABLE as usize] != 0 { + if device.cart.sc64.cfg[device::cart::sc64::SC64_ROM_WRITE_ENABLE as usize] != 0 + && device.cart.sc64.cfg[device::cart::sc64::SC64_BOOTLOADER_SWITCH as usize] == 0 + { let masked_address = address as usize & CART_MASK; let mut data = read_cart_word(device, masked_address); device::memory::masked_write_32(&mut data, value, mask); @@ -79,20 +77,19 @@ pub fn dma_read( mut dram_addr: u32, length: u32, ) -> u64 { - if device.cart.sc64.cfg[device::cart::sc64::SC64_ROM_WRITE_ENABLE as usize] != 0 { + if device.cart.sc64.cfg[device::cart::sc64::SC64_ROM_WRITE_ENABLE as usize] != 0 + && device.cart.sc64.cfg[device::cart::sc64::SC64_BOOTLOADER_SWITCH as usize] == 0 + { dram_addr &= device::rdram::RDRAM_MASK as u32; cart_addr &= CART_MASK as u32; for i in 0..length { - if cart_addr + i < device.cart.rom.len() as u32 { - device.ui.saves.romsave.data.insert( - cart_addr + i, - device.rdram.mem[(dram_addr + i) as usize ^ device.byte_swap], - ); - - device.ui.saves.romsave.written = true; - } + device.ui.saves.romsave.data.insert( + cart_addr + i, + device.rdram.mem[(dram_addr + i) as usize ^ device.byte_swap], + ); } + device.ui.saves.romsave.written = true; } device::pi::calculate_cycles(device, 1, length) @@ -109,24 +106,23 @@ pub fn dma_write( cart_addr &= CART_MASK as u32; let mut i = dram_addr; let mut j = cart_addr; - while i < dram_addr + length && j < device.cart.rom.len() as u32 { + while i < dram_addr + length { if device.ui.saves.romsave.data.contains_key(&j) { device.rdram.mem[i as usize ^ device.byte_swap] = device.ui.saves.romsave.data[&j]; } else { - device.rdram.mem[i as usize ^ device.byte_swap] = device.cart.rom[j as usize]; + device.rdram.mem[i as usize ^ device.byte_swap] = + *device.cart.rom.get(j as usize).unwrap_or(&0); } i += 1; j += 1; } - while i < dram_addr + length { - // DMAs that extend past the end of the ROM return 0's for the portion that extends past the ROM length - device.rdram.mem[i as usize ^ device.byte_swap] = 0; - i += 1; - } + device::pi::calculate_cycles(device, 1, length) } pub fn init(device: &mut device::Device, rom_file: Vec) { + device.cart.sc64.cfg[device::cart::sc64::SC64_BOOTLOADER_SWITCH as usize] = 1; + device.cart.rom = rom_file; device.cart.pal = is_system_pal(device.cart.rom[0x3E]); set_cic(device); @@ -153,40 +149,27 @@ fn set_cic(device: &mut device::Device) { let hash = calculate_hash(&device.cart.rom[0x40..0x1000]); match hash.as_str() { "B99F06C4802C2377E31E388435955EF3E99C618A6D55D24699D828EB1075F1EB" => { - device.cart.cic_type = device::cart::CicType::CicNus6101; - device.cart.cic_seed = 0x3F; - device.cart.rdram_size_offset = 0x318; + device.cart.cic_seed = 0x3F; // CicNus6101 } "61E88238552C356C23D19409FE5570EE6910419586BC6FC740F638F761ADC46E" => { - device.cart.cic_type = device::cart::CicType::CicNus6102; - device.cart.cic_seed = 0x3F; - device.cart.rdram_size_offset = 0x318; + device.cart.cic_seed = 0x3F; // CicNus6102 } "BF3620D30817007091EBE9BDDD1B88C23B8A0052170B3309CDE5B6B4238E45E7" => { - device.cart.cic_type = device::cart::CicType::CicNus6103; - device.cart.cic_seed = 0x78; - device.cart.rdram_size_offset = 0x318; + device.cart.cic_seed = 0x78; // CicNus6103 } "04B7BC6717A9F0EB724CF927E74AD3876C381CBB280D841736FC5E55580B756B" => { - device.cart.cic_type = device::cart::CicType::CicNus6105; - device.cart.cic_seed = 0x91; - device.cart.rdram_size_offset = 0x3F0; + device.cart.cic_seed = 0x91; // CicNus6105 } "36ADC40148AF56F0D78CD505EB6A90117D1FD6F11C6309E52ED36BC4C6BA340E" => { - device.cart.cic_type = device::cart::CicType::CicNus6106; - device.cart.cic_seed = 0x85; - device.cart.rdram_size_offset = 0x318; + device.cart.cic_seed = 0x85; // CicNus6106 } "53C0088FB777870D0AF32F0251E964030E2E8B72E830C26042FD191169508C05" => { - device.cart.cic_type = device::cart::CicType::CicNus5167; - device.cart.cic_seed = 0xdd; - device.cart.rdram_size_offset = 0x318; + device.cart.cic_seed = 0xdd; // CicNus5167 device.cart.sc64.cfg[device::cart::sc64::SC64_ROM_WRITE_ENABLE as usize] = 1; + device.cart.sc64.cfg[device::cart::sc64::SC64_BOOTLOADER_SWITCH as usize] = 0; } _ => { - device.cart.cic_type = device::cart::CicType::CicNus6102; - device.cart.cic_seed = 0x3F; - device.cart.rdram_size_offset = 0x318; + device.cart.cic_seed = 0x3F; // CicNus6102 println!("unknown IPL3 {}", hash) } } diff --git a/src/device/cart/sc64.rs b/src/device/cart/sc64.rs index b4e5728..f1f8440 100644 --- a/src/device/cart/sc64.rs +++ b/src/device/cart/sc64.rs @@ -1,4 +1,5 @@ use crate::device; +use crate::ui; pub const SDCARD_SIZE: usize = 0x4000000; @@ -11,19 +12,22 @@ const SC64_KEY_REG: u32 = 4; //const SC64_AUX_REG: u32 = 6; pub const SC64_REGS_COUNT: u32 = 7; +pub const SC64_BOOTLOADER_SWITCH: u32 = 0; pub const SC64_ROM_WRITE_ENABLE: u32 = 1; +pub const SC64_SAVE_TYPE: u32 = 6; pub const SC64_CFG_COUNT: u32 = 15; const SC64_BUFFER_MASK: usize = 0x1FFF; +const SC64_EEPROM_MASK: usize = 0xFFF; #[derive(serde::Serialize, serde::Deserialize)] pub struct Sc64 { - #[serde(with = "serde_big_array::BigArray")] - pub buffer: [u8; 8192], + pub buffer: Vec, pub regs: [u32; SC64_REGS_COUNT as usize], pub regs_locked: bool, pub cfg: [u32; SC64_CFG_COUNT as usize], pub sector: u32, + pub writeback_sector: Vec, } fn format_sdcard(device: &mut device::Device) { @@ -74,6 +78,11 @@ pub fn write_regs(device: &mut device::Device, address: u64, value: u32, mask: u SC64_SCR_REG => { if !device.cart.sc64.regs_locked { match char::from_u32(value & mask).unwrap() { + 'V' => { + // get version + device.cart.sc64.regs[SC64_DATA0_REG as usize] = (2 << 16) | 20; + device.cart.sc64.regs[SC64_DATA1_REG as usize] = 2; + } 'c' => { // get config device.cart.sc64.regs[SC64_DATA1_REG as usize] = device.cart.sc64.cfg @@ -81,6 +90,35 @@ pub fn write_regs(device: &mut device::Device, address: u64, value: u32, mask: u } 'C' => { // set config + if device.cart.sc64.regs[SC64_DATA0_REG as usize] == SC64_SAVE_TYPE { + // if save type is being written, we are probably booting a game using the flash cart menu + // we shouldn't write saves to disk in this case (they are written to the SD card) + device.ui.saves.write_to_disk = false; + device.ui.save_type = + match device.cart.sc64.regs[SC64_DATA1_REG as usize] { + 0 => { + vec![] + } + 1 => { + vec![ui::storage::SaveTypes::Eeprom4k] + } + 2 => { + vec![ui::storage::SaveTypes::Eeprom16k] + } + 3 => { + vec![ui::storage::SaveTypes::Sram] + } + 4 => { + vec![ui::storage::SaveTypes::Flash] + } + _ => { + panic!( + "unknown sc64 save type: {}", + device.cart.sc64.regs[SC64_DATA1_REG as usize] + ) + } + } + } std::mem::swap( &mut device.cart.sc64.cfg [device.cart.sc64.regs[SC64_DATA0_REG as usize] as usize], @@ -165,8 +203,24 @@ pub fn write_regs(device: &mut device::Device, address: u64, value: u32, mask: u } device.ui.saves.sdcard.written = true; } - 'U' => {} // USB_WRITE_STATUS, ignored - 'M' => {} // USB_WRITE, ignored + 'U' | 'u' => {} // USB status, ignored + 'M' | 'm' => {} // USB read/write, ignored + 'w' => { + // SD card writeback pending + device.cart.sc64.regs[SC64_DATA0_REG as usize] = 0; + } + 'W' => { + let writeback_sectors_address = + device.cart.sc64.regs[SC64_DATA0_REG as usize] as u64; + for i in 0..256 { + device.cart.sc64.writeback_sector[i] = device::memory::data_read( + device, + writeback_sectors_address + (i * 4) as u64, + device::memory::AccessSize::Word, + false, + ); + } + } _ => { panic!( "unknown sc64 command: {}", @@ -190,24 +244,48 @@ pub fn read_mem( address: u64, _access_size: device::memory::AccessSize, ) -> u32 { - let masked_address = address as usize & SC64_BUFFER_MASK; - u32::from_be_bytes( - device.cart.sc64.buffer[masked_address..masked_address + 4] - .try_into() - .unwrap(), - ) + if address & 0x2000 != 0 { + device::cart::format_eeprom(device); + let masked_address = address as usize & SC64_EEPROM_MASK; + u32::from_be_bytes( + device.ui.saves.eeprom.data[masked_address..masked_address + 4] + .try_into() + .unwrap(), + ) + } else { + let masked_address = address as usize & SC64_BUFFER_MASK; + u32::from_be_bytes( + device.cart.sc64.buffer[masked_address..masked_address + 4] + .try_into() + .unwrap(), + ) + } } pub fn write_mem(device: &mut device::Device, address: u64, value: u32, mask: u32) { - let masked_address = address as usize & SC64_BUFFER_MASK; - let mut data = u32::from_be_bytes( + if address & 0x2000 != 0 { + device::cart::format_eeprom(device); + let masked_address = address as usize & SC64_EEPROM_MASK; + let mut data = u32::from_be_bytes( + device.ui.saves.eeprom.data[masked_address..masked_address + 4] + .try_into() + .unwrap(), + ); + device::memory::masked_write_32(&mut data, value, mask); + device.ui.saves.eeprom.data[masked_address..masked_address + 4] + .copy_from_slice(&data.to_be_bytes()); + device.ui.saves.eeprom.written = true + } else { + let masked_address = address as usize & SC64_BUFFER_MASK; + let mut data = u32::from_be_bytes( + device.cart.sc64.buffer[masked_address..masked_address + 4] + .try_into() + .unwrap(), + ); + device::memory::masked_write_32(&mut data, value, mask); device.cart.sc64.buffer[masked_address..masked_address + 4] - .try_into() - .unwrap(), - ); - device::memory::masked_write_32(&mut data, value, mask); - device.cart.sc64.buffer[masked_address..masked_address + 4] - .copy_from_slice(&data.to_be_bytes()); + .copy_from_slice(&data.to_be_bytes()); + } } pub fn dma_read( @@ -217,12 +295,20 @@ pub fn dma_read( length: u32, ) -> u64 { dram_addr &= device::rdram::RDRAM_MASK as u32; - cart_addr &= SC64_BUFFER_MASK as u32; + let buffer = if cart_addr & 0x2000 != 0 { + device::cart::format_eeprom(device); + cart_addr &= SC64_EEPROM_MASK as u32; + device.ui.saves.eeprom.written = true; + &mut device.ui.saves.eeprom.data + } else { + cart_addr &= SC64_BUFFER_MASK as u32; + &mut device.cart.sc64.buffer + }; let mut i = dram_addr; let mut j = cart_addr; while i < dram_addr + length && i < device.rdram.size { - device.cart.sc64.buffer[j as usize] = device.rdram.mem[i as usize ^ device.byte_swap]; + buffer[j as usize] = device.rdram.mem[i as usize ^ device.byte_swap]; i += 1; j += 1; } @@ -237,12 +323,19 @@ pub fn dma_write( length: u32, ) -> u64 { dram_addr &= device::rdram::RDRAM_MASK as u32; - cart_addr &= SC64_BUFFER_MASK as u32; + let buffer = if cart_addr & 0x2000 != 0 { + device::cart::format_eeprom(device); + cart_addr &= SC64_EEPROM_MASK as u32; + &device.ui.saves.eeprom.data + } else { + cart_addr &= SC64_BUFFER_MASK as u32; + &device.cart.sc64.buffer + }; let mut i = dram_addr; let mut j = cart_addr; while i < dram_addr + length && i < device.rdram.size { - device.rdram.mem[i as usize ^ device.byte_swap] = device.cart.sc64.buffer[j as usize]; + device.rdram.mem[i as usize ^ device.byte_swap] = buffer[j as usize]; i += 1; j += 1; } diff --git a/src/device/memory.rs b/src/device/memory.rs index 3b87d7c..9cdf3e7 100644 --- a/src/device/memory.rs +++ b/src/device/memory.rs @@ -153,13 +153,13 @@ pub fn init(device: &mut device::Device) { } else if (MM_DOM2_ADDR2 >> 16..=(MM_DOM2_ADDR2 + 0x1FFFF) >> 16).contains(&i) { device.memory.memory_map_read[i] = device::cart::sram::read_mem; device.memory.memory_map_write[i] = device::cart::sram::write_mem; - } else if i >= MM_CART_ROM >> 16 && i <= (MM_CART_ROM + device.cart.rom.len() - 1) >> 16 { - device.memory.fast_read[i] = device::cart::rom::read_mem_fast; - device.memory.memory_map_read[i] = device::cart::rom::read_mem; - device.memory.memory_map_write[i] = device::cart::rom::write_mem; } else if i >= MM_IS_VIEWER >> 16 && i <= (MM_IS_VIEWER + 0xFFFF) >> 16 { device.memory.memory_map_read[i] = device::is_viewer::read_mem; device.memory.memory_map_write[i] = device::is_viewer::write_mem; + } else if (MM_CART_ROM >> 16..=(MM_CART_ROM + 0x0FBFFFFF) >> 16).contains(&i) { + device.memory.fast_read[i] = device::cart::rom::read_mem_fast; + device.memory.memory_map_read[i] = device::cart::rom::read_mem; + device.memory.memory_map_write[i] = device::cart::rom::write_mem; } else if i >= MM_PIF_MEM >> 16 && i <= (MM_PIF_MEM + 0xFFFF) >> 16 { device.memory.memory_map_read[i] = device::pif::read_mem; device.memory.memory_map_write[i] = device::pif::write_mem; diff --git a/src/device/rdram.rs b/src/device/rdram.rs index 71cf496..04ef5a4 100644 --- a/src/device/rdram.rs +++ b/src/device/rdram.rs @@ -106,13 +106,12 @@ pub fn init(device: &mut device::Device) { unsafe { Vec::from_raw_parts(ptr, device.rdram.size as usize, device.rdram.size as usize) }; // hack, skip RDRAM initialization - device.rdram.mem[device.cart.rdram_size_offset..device.cart.rdram_size_offset + 4] - .copy_from_slice(&device.rdram.size.to_ne_bytes()); + device.rdram.mem[0x318..0x318 + 4].copy_from_slice(&device.rdram.size.to_ne_bytes()); + // hack, skip RDRAM initialization + device.rdram.mem[0x3f0..0x3f0 + 4].copy_from_slice(&device.rdram.size.to_ne_bytes()); device.ri.regs[device::ri::RI_MODE_REG as usize] = 0x0e; device.ri.regs[device::ri::RI_CONFIG_REG as usize] = 0x40; - device.ri.regs[device::ri::RI_SELECT_REG as usize] = 0x14; - device.ri.regs[device::ri::RI_REFRESH_REG as usize] = 0x00063634; } pub fn rdram_calculate_cycles(length: u64) -> u64 { diff --git a/src/device/ri.rs b/src/device/ri.rs index b6b5cec..f501a91 100644 --- a/src/device/ri.rs +++ b/src/device/ri.rs @@ -22,17 +22,24 @@ pub fn read_regs( _access_size: device::memory::AccessSize, ) -> u32 { device::cop0::add_cycles(device, 20); - if ((address & 0xFFFF) >> 2) as u32 == RI_SELECT_REG && !device.ri.ram_init { - device::cop0::add_cycles(device, device.cpu.clock_rate / 2); // hack, simulate RDRAM initialization - device.ri.ram_init = true; + let reg = (address & 0xFFFF) >> 2; + match reg as u32 { + RI_SELECT_REG => { + if !device.ri.ram_init { + device::cop0::add_cycles(device, device.cpu.clock_rate / 2); // hack, simulate RDRAM initialization + device.ri.ram_init = true; + } + 0x14 // hack, skip RDRAM initialization + } + RI_REFRESH_REG => 0x00063634, // hack, skip RDRAM initialization + _ => device.ri.regs[reg as usize], } - device.ri.regs[((address & 0xFFFF) >> 2) as usize] } pub fn write_regs(device: &mut device::Device, address: u64, value: u32, mask: u32) { - device::memory::masked_write_32( - &mut device.ri.regs[((address & 0xFFFF) >> 2) as usize], - value, - mask, - ); + let reg = (address & 0xFFFF) >> 2; + if reg as u32 == RI_SELECT_REG { + device.ri.ram_init = false; + } + device::memory::masked_write_32(&mut device.ri.regs[reg as usize], value, mask); } diff --git a/src/ui.rs b/src/ui.rs index 29ffad8..7a9ccea 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -122,6 +122,7 @@ impl Ui { savestate_file_path: std::path::PathBuf::new(), }, saves: storage::Saves { + write_to_disk: true, eeprom: storage::Save { data: Vec::new(), written: false, diff --git a/src/ui/audio.rs b/src/ui/audio.rs index 2b8ecd9..d47d899 100644 --- a/src/ui/audio.rs +++ b/src/ui/audio.rs @@ -14,15 +14,20 @@ pub struct EventAudio { pub fn init(ui: &mut ui::Ui, frequency: u64) { ui::sdl_init(sdl3_sys::init::SDL_INIT_AUDIO); - let audio_spec = sdl3_sys::audio::SDL_AudioSpec { + let game_audio_spec = sdl3_sys::audio::SDL_AudioSpec { format: sdl3_sys::audio::SDL_AUDIO_S16LE, freq: frequency as i32, channels: 2, }; + let device_audio_spec = sdl3_sys::audio::SDL_AudioSpec { + format: sdl3_sys::audio::SDL_AUDIO_S16LE, + freq: 48000, + channels: 2, + }; ui.audio_device = unsafe { sdl3_sys::audio::SDL_OpenAudioDevice( sdl3_sys::audio::SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, - &audio_spec, + &device_audio_spec, ) }; if ui.audio_device == 0 { @@ -36,7 +41,7 @@ pub fn init(ui: &mut ui::Ui, frequency: u64) { panic!("Could not get audio device format"); } - ui.audio_stream = unsafe { sdl3_sys::audio::SDL_CreateAudioStream(&audio_spec, &dst) }; + ui.audio_stream = unsafe { sdl3_sys::audio::SDL_CreateAudioStream(&game_audio_spec, &dst) }; if ui.audio_stream.is_null() { return; } diff --git a/src/ui/storage.rs b/src/ui/storage.rs index b5bc764..77598d9 100644 --- a/src/ui/storage.rs +++ b/src/ui/storage.rs @@ -1,4 +1,4 @@ -use crate::{netplay, ui}; +use crate::{device, netplay, ui}; use std::io::Read; use std::io::Write; @@ -45,6 +45,7 @@ pub struct Saves { pub mempak: Save, pub sdcard: Save, pub romsave: RomSave, + pub write_to_disk: bool, } fn get_save_type(rom: &[u8], game_id: &str) -> Vec { @@ -317,25 +318,61 @@ fn write_rom_save(ui: &ui::Ui) { std::fs::write(ui.paths.romsave_file_path.clone(), data).unwrap(); } -pub fn write_saves(ui: &ui::Ui, netplay: &Option) { - if netplay.is_none() || netplay.as_ref().unwrap().player_number == 0 { - if ui.saves.eeprom.written { - write_save(ui, SaveTypes::Eeprom16k) +fn writeback_sdcard(device: &mut device::Device) { + let length; + let save_data: &[u8]; + if device.ui.saves.eeprom.written { + if device + .ui + .save_type + .contains(&ui::storage::SaveTypes::Eeprom4k) + { + length = 1; + } else { + length = 4; } - if ui.saves.sram.written { - write_save(ui, SaveTypes::Sram) + save_data = device.ui.saves.eeprom.data.as_ref(); + } else if device.ui.saves.sram.written { + length = device.ui.saves.sram.data.len() / 512; + save_data = device.ui.saves.sram.data.as_ref(); + } else if device.ui.saves.flash.written { + length = device.ui.saves.flash.data.len() / 512; + save_data = device.ui.saves.flash.data.as_ref(); + } else { + return; + } + + for i in 0..length { + let offset = device.cart.sc64.writeback_sector[i] as usize * 512; + device.ui.saves.sdcard.data[offset..offset + 512] + .copy_from_slice(&save_data[i * 512..(i + 1) * 512]); + } + device.ui.saves.sdcard.written = true; +} + +pub fn write_saves(device: &mut device::Device) { + if device.netplay.is_none() || device.netplay.as_ref().unwrap().player_number == 0 { + if device.ui.saves.write_to_disk { + if device.ui.saves.eeprom.written { + write_save(&device.ui, SaveTypes::Eeprom16k) + } + if device.ui.saves.sram.written { + write_save(&device.ui, SaveTypes::Sram) + } + if device.ui.saves.flash.written { + write_save(&device.ui, SaveTypes::Flash) + } + if device.ui.saves.romsave.written { + write_save(&device.ui, SaveTypes::Romsave) + } + } else { + writeback_sdcard(device) } - if ui.saves.flash.written { - write_save(ui, SaveTypes::Flash) + if device.ui.saves.mempak.written { + write_save(&device.ui, SaveTypes::Mempak) } - if ui.saves.mempak.written { - write_save(ui, SaveTypes::Mempak) - } - if ui.saves.sdcard.written { - write_save(ui, SaveTypes::Sdcard) - } - if ui.saves.romsave.written { - write_save(ui, SaveTypes::Romsave) + if device.ui.saves.sdcard.written { + write_save(&device.ui, SaveTypes::Sdcard) } } }