From 24f6aa2e013e064caa299c30db46574b04d5d23a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com> Date: Sat, 19 Aug 2023 00:54:31 +0100 Subject: [PATCH] chore: improved support for cheat errors Handling of GameShark RAM banks differently. Added parsing integer value errors. --- frontends/libretro/src/lib.rs | 4 ++- src/cheats/shark.rs | 50 +++++++++++++++-------------------- src/mmu.rs | 8 ++++-- src/rom.rs | 10 ++++++- 4 files changed, 39 insertions(+), 33 deletions(-) diff --git a/frontends/libretro/src/lib.rs b/frontends/libretro/src/lib.rs index 7027c30b..3893b0d2 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 e62deacd..5ce6d2ea 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 8220ec3e..4e03d045 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 bac31515..b9fa6643 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 { -- GitLab