use crate::{cheats, device, retroachievements, ui}; #[cfg(target_arch = "aarch64")] use device::__m128i; use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; use serde::ser::{Serialize, SerializeSeq, Serializer}; #[cfg(target_arch = "x86_64")] use std::arch::x86_64::*; struct M128iArrayVisitor; impl<'de, const N: usize> Visitor<'de> for M128iArrayVisitor { type Value = [__m128i; N]; fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { formatter.write_str(&format!("an array of {N} 128-bit integers")) } fn visit_seq(self, mut seq: A) -> Result where A: SeqAccess<'de>, { let mut arr: [__m128i; N] = [device::zero_m128i(); N]; for (index, item) in arr.iter_mut().enumerate().take(N) { match seq.next_element::()? { Some(value) => *item = unsafe { std::mem::transmute::(value) }, None => return Err(serde::de::Error::invalid_length(index, &self)), } } Ok(arr) } } pub fn deserialize_m128i_array<'de, D, const N: usize>( deserializer: D, ) -> Result<[__m128i; N], D::Error> where D: serde::Deserializer<'de>, { deserializer.deserialize_seq(M128iArrayVisitor) } pub fn serialize_m128i(data: &__m128i, serializer: S) -> Result where S: Serializer, { let bytes: u128 = unsafe { std::mem::transmute(*data) }; bytes.serialize(serializer) } pub fn deserialize_m128i<'de, D>(deserializer: D) -> Result<__m128i, D::Error> where D: Deserializer<'de>, { let bytes = u128::deserialize(deserializer)?; Ok(unsafe { std::mem::transmute::(bytes) }) } pub fn serialize_m128i_array(value: &[__m128i], serializer: S) -> Result where S: serde::Serializer, { let mut seq = serializer.serialize_seq(Some(value.len()))?; for item in value { let bytes: u128 = unsafe { std::mem::transmute(*item) }; seq.serialize_element(&bytes)?; } seq.end() } pub fn create_savestate(device: &device::Device) { let mut rdp_state: Vec = vec![0; ui::video::state_size()]; ui::video::save_state(rdp_state.as_mut_ptr()); let mut ra_state: Vec = vec![0; retroachievements::state_size()]; retroachievements::save_state(ra_state.as_mut_ptr()); let data: &[(&[u8], &str)] = &[ (&postcard::to_stdvec(device).unwrap(), "device"), ( &postcard::to_stdvec(&device.ui.storage.saves).unwrap(), "saves", ), (&rdp_state, "rdp_state"), (&ra_state, "ra_state"), ]; let save_path = device.ui.storage.paths.savestate_file_path.clone(); let compressed_file = ui::storage::compress_file(data); tokio::spawn(async move { tokio::fs::write(save_path, compressed_file).await.unwrap(); }); ui::video::onscreen_message( &device.ui, &format!( "Savestate created in slot {}", device.ui.storage.save_state_slot ), ); } pub fn load_savestate(device: &mut device::Device) { let savestate = std::fs::read(&device.ui.storage.paths.savestate_file_path); if let Ok(savestate) = &savestate { let device_bytes = ui::storage::decompress_file(savestate, "device"); let save_bytes = ui::storage::decompress_file(savestate, "saves"); let rdp_state = ui::storage::decompress_file(savestate, "rdp_state"); let ra_state = ui::storage::decompress_file(savestate, "ra_state"); if let Ok(state) = postcard::from_bytes::(&device_bytes) { device.ui.storage.saves = postcard::from_bytes(&save_bytes).unwrap(); device.cpu = state.cpu; device.pif = state.pif; let rom = device.cart.rom.clone(); device.cart = state.cart; device.cart.rom = rom; device.memory = state.memory; device.rsp = state.rsp; device.rdp = state.rdp; device.rdram = state.rdram; device.mi = state.mi; device.pi = state.pi; device.vi = state.vi; device.ai = state.ai; device.si = state.si; device.ri = state.ri; device.vru = state.vru; device.cheats = state.cheats; let mut tpak_rom = [vec![], vec![], vec![], vec![]]; for (i, item) in tpak_rom.iter_mut().enumerate() { *item = device.transferpaks[i].cart.rom.clone(); } device.transferpaks = state.transferpaks; for (i, item) in tpak_rom.iter().enumerate() { device.transferpaks[i].cart.rom = item.clone(); } device::memory::init(device); device::vi::set_expected_refresh_rate(device); device::cpu::map_instructions(device); device::cop0::map_instructions(device); device::cop1::map_instructions(device); device::cop2::map_instructions(device); device::rsp_cpu::map_instructions(device); let mut mem_addr = 0x1000; while mem_addr < 0x2000 { let data = u32::from_be_bytes(device.rsp.mem[mem_addr..mem_addr + 4].try_into().unwrap()); device.rsp.cpu.instructions[(mem_addr & 0xFFF) / 4].func = device::rsp_cpu::decode_opcode(device, data); device.rsp.cpu.instructions[(mem_addr & 0xFFF) / 4].opcode = data; mem_addr += 4; } for line_index in 0..512 { for i in 0..8 { device.memory.icache[line_index].instruction[i] = device::cpu::decode_opcode( device, device.memory.icache[line_index].words[i], ); } } device::pif::connect_pif_channels(device); for i in 0..4 { if device.pif.channels[i].pak_handler.is_some() { if device.pif.channels[i].pak_handler.unwrap().pak_type == device::controller::PakType::RumblePak { let rumblepak_handler = device::controller::PakHandler { read: device::controller::rumble::read, write: device::controller::rumble::write, pak_type: device::controller::PakType::RumblePak, }; device.pif.channels[i].pak_handler = Some(rumblepak_handler); } else if device.pif.channels[i].pak_handler.unwrap().pak_type == device::controller::PakType::MemPak { let mempak_handler = device::controller::PakHandler { read: device::controller::mempak::read, write: device::controller::mempak::write, pak_type: device::controller::PakType::MemPak, }; device.pif.channels[i].pak_handler = Some(mempak_handler); } else if device.pif.channels[i].pak_handler.unwrap().pak_type == device::controller::PakType::TransferPak { let tpak_handler = device::controller::PakHandler { read: device::controller::transferpak::read, write: device::controller::transferpak::write, pak_type: device::controller::PakType::TransferPak, }; device.pif.channels[i].pak_handler = Some(tpak_handler); } } } ui::audio::close_game_audio(&mut device.ui); ui::audio::init_game_audio(&mut device.ui, device.ai.freq); ui::video::load_state(device, rdp_state.as_ptr()); retroachievements::load_state(ra_state.as_ptr()); if device.cheats.enabled { cheats::execute_cheats(device, device.cheats.cheats.clone()); } ui::video::onscreen_message( &device.ui, &format!( "Savestate loaded from slot {}", device.ui.storage.save_state_slot ), ); } else { ui::video::onscreen_message( &device.ui, &format!( "Failed to load savestate from slot {}", device.ui.storage.save_state_slot ), ); } } else { ui::video::onscreen_message( &device.ui, &format!( "Could not find savestate in slot {}", device.ui.storage.save_state_slot ), ); } } pub fn default_pak_handler() -> fn(&mut device::Device, usize, u16, usize, usize) { device::controller::mempak::read } pub fn default_instruction() -> fn(&mut device::Device, u32) { device::cop0::reserved } pub fn default_instructions() -> [fn(&mut device::Device, u32); N] where [fn(&mut device::Device, u32); N]: Sized, { [device::cop0::reserved; N] } pub fn default_memory_read_fast() -> [fn(&device::Device, u64, device::memory::AccessSize) -> u32; 0x2000] { [device::unmapped::read_mem_fast; 0x2000] } pub fn default_memory_read() -> [fn(&mut device::Device, u64, device::memory::AccessSize) -> u32; 0x2000] { [device::unmapped::read_mem; 0x2000] } pub fn default_memory_write() -> [fn(&mut device::Device, u64, u32, u32); 0x2000] { [device::unmapped::write_mem; 0x2000] }