diff --git a/frontends/libretro/src/lib.rs b/frontends/libretro/src/lib.rs index 7027c30b5987132ae4c66c8c89821256eea50a70..3893b0d27d15c49fd12a6fab91f92160fe17d413 100644 --- a/frontends/libretro/src/lib.rs +++ b/frontends/libretro/src/lib.rs @@ -439,7 +439,9 @@ pub unsafe extern "C" fn retro_cheat_set(_index: c_uint, enabled: bool, code: *c let emulator = EMULATOR.as_mut().unwrap(); let code_c = CStr::from_ptr(code); let code_s = code_c.to_string_lossy().into_owned(); - emulator.add_cheat_code(&code_s).unwrap(); + if let Err(err) = emulator.add_cheat_code(&code_s) { + warnln!("Failed to add cheat code ({}): {}", code_s, err); + } } #[no_mangle] diff --git a/src/cheats/shark.rs b/src/cheats/shark.rs index e62deacdab5139552ab283bd44279ecb41120493..5ce6d2eaddb379d2429d5ca375af40c7d41569d5 100644 --- a/src/cheats/shark.rs +++ b/src/cheats/shark.rs @@ -37,31 +37,12 @@ impl GameShark { self.codes.clear(); } - pub fn contains_addr(&self, addr: u16, ram_bank: u8) -> bool { - // runs the check to see if the code is registered - // for the provided (RAM) address - if !self.codes.contains_key(&addr) { - return false; - } - - // in case the code is for internal RAM then we don't - // need to check the RAM bank - if addr <= 0xd000 { - return true; - } - - // this access is for the external RAM so we need to check - // that the RAM bank matches - let code = self.get_addr(addr); - code.ram_bank == ram_bank - } - pub fn get_addr(&self, addr: u16) -> &GameSharkCode { self.codes.get(&addr).unwrap() } pub fn add_code(&mut self, code: &str) -> Result<&GameSharkCode, String> { - let genie_code = match GameSharkCode::from_code(code, None) { + let genie_code = match GameSharkCode::from_code(code) { Ok(genie_code) => genie_code, Err(message) => return Err(message), }; @@ -70,17 +51,20 @@ impl GameShark { Ok(self.get_addr(addr)) } - pub fn writes(&self) -> Vec<(u16, u8)> { + pub fn writes(&self) -> Vec<(u16, u16, u8)> { let mut writes = vec![]; for code in self.codes.values() { // calculates the real RAM address using both // he base RAM address the RAM bank offset - let addr = if code.addr <= 0xd000 { - code.addr - 0xc000 + let (base_addr, addr) = if code.addr <= 0xc000 { + ( + 0xa000, + code.addr - 0xa000 + (0x1000 * (code.ram_bank - 1) as u16), + ) } else { - code.addr - 0xc000 + (0x1000 * (code.ram_bank - 1) as u16) + (0xc000, code.addr - 0xc000) }; - writes.push((addr, code.new_data)); + writes.push((base_addr, addr, code.new_data)); } writes } @@ -111,7 +95,7 @@ pub struct GameSharkCode { impl GameSharkCode { /// Creates a new GameShark code structure from the provided string /// in the ABCDGHEF format. - pub fn from_code(code: &str, _handle_additive: Option<bool>) -> Result<Self, String> { + pub fn from_code(code: &str) -> Result<Self, String> { let code_length = code.len(); if code_length != 8 { @@ -124,13 +108,21 @@ impl GameSharkCode { let code_u = code.to_uppercase(); let ram_bank_slice = &code_u[0..=1]; - let ram_bank = u8::from_str_radix(ram_bank_slice, 16).unwrap(); + let ram_bank = u8::from_str_radix(ram_bank_slice, 16) + .map_err(|e| format!("Invalid RAM bank: {}", e))? + & 0x0f; let new_data_slice = &code_u[2..=3]; - let new_data = u8::from_str_radix(new_data_slice, 16).unwrap(); + let new_data = u8::from_str_radix(new_data_slice, 16) + .map_err(|e| format!("Invalid new data: {}", e))?; let addr_slice = format!("{}{}", &code_u[6..=7], &code_u[4..=5]); - let addr = u16::from_str_radix(&addr_slice, 16).unwrap(); + let addr = + u16::from_str_radix(&addr_slice, 16).map_err(|e| format!("Invalid address: {}", e))?; + + if addr < 0xa000 || addr > 0xdfff { + return Err(format!("Invalid cheat address: 0x{:04x}", addr)); + } Ok(Self { code: code_u, diff --git a/src/mmu.rs b/src/mmu.rs index 8220ec3ebb7083b86f3cc2d70fb5b37ed41f079f..4e03d0457202399af1d5bb8515cb8ae251a4e0c4 100644 --- a/src/mmu.rs +++ b/src/mmu.rs @@ -172,8 +172,12 @@ impl Mmu { pub fn vblank(&mut self) { let writes = self.rom.vblank(); if let Some(writes) = writes { - for (addr, value) in writes { - self.ram[addr as usize] = value; + for (base_addr, addr, value) in writes { + match base_addr { + 0xa000 => self.rom.ram_data_mut()[addr as usize] = value, + 0xc000 => self.ram[addr as usize] = value, + _ => panic!("Invalid base address for write: 0x{:04x}", base_addr), + } } } } diff --git a/src/rom.rs b/src/rom.rs index bac315157ed17a0bcac60e038324902b1c420a8b..b9fa6643391303cfac69fe8c490e95ae0d423e54 100644 --- a/src/rom.rs +++ b/src/rom.rs @@ -389,7 +389,7 @@ impl Cartridge { self.rumble_cb = |_| {}; } - pub fn vblank(&mut self) -> Option<Vec<(u16, u8)>> { + pub fn vblank(&mut self) -> Option<Vec<(u16, u16, u8)>> { if let Some(game_shark) = &mut self.game_shark { return Some(game_shark.writes()); } @@ -757,9 +757,17 @@ impl Cartridge { &self.rom_data } + pub fn rom_data_mut(&mut self) -> &mut Vec<u8> { + &mut self.rom_data + } + pub fn ram_data(&self) -> &Vec<u8> { &self.ram_data } + + pub fn ram_data_mut(&mut self) -> &mut Vec<u8> { + &mut self.ram_data + } } impl Default for Cartridge {