From 8f9922473ee5ef3d1a9413b164347c65c6e10805 Mon Sep 17 00:00:00 2001 From: Simon Gellis Date: Mon, 1 Sep 2025 00:07:55 -0400 Subject: [PATCH] Support arbitrary markers --- src/emulator/shrooms_vb_core.rs | 49 +++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/src/emulator/shrooms_vb_core.rs b/src/emulator/shrooms_vb_core.rs index b00e9b6..ffe98e7 100644 --- a/src/emulator/shrooms_vb_core.rs +++ b/src/emulator/shrooms_vb_core.rs @@ -300,7 +300,7 @@ extern "C" fn on_read( extern "C" fn on_write( sim: *mut VB, address: u32, - _type: VBDataType, + typ_: VBDataType, value: *mut i32, _cycles: *mut u32, _cancel: *mut c_int, @@ -317,6 +317,29 @@ extern "C" fn on_write( } } + // If we have profiling enabled, track custom markers + if data.monitor.enabled { + let normalized_hw_address = address & 0x0700003f; + if normalized_hw_address == 0x02000038 && matches!(typ_, VBDataType::S32) { + assert!(data.monitor.queued_event.is_none()); + // The game has written the address of a null-terminated string + // (whose length is at most 64 bytes). Read that string. + let str_address = unsafe { *value } as u32; + let mut bytes = [0u8; 64]; + let mut len = 0; + for (dst, src_address) in bytes.iter_mut().zip(str_address..str_address + 64) { + let char = unsafe { vb_read(sim, src_address, VBDataType::U8) } as u8; + if char == 0 { + break; + } + *dst = char; + len += 1; + } + let name = String::from_utf8_lossy(&bytes[..len]).into_owned(); + data.monitor.queued_event = Some(SimEvent::Marker(Cow::Owned(name))); + } + } + if let Some(start) = data.write_watchpoints.start_of_range_containing(address) { let watch = if data.read_watchpoints.contains(address) { VBWatchpointType::Access @@ -465,6 +488,10 @@ impl VBState { || !self.read_watchpoints.is_empty() || !self.write_watchpoints.is_empty() } + + fn needs_write_callback(&self) -> bool { + self.stdout.is_some() || self.monitor.enabled || !self.write_watchpoints.is_empty() + } } pub enum StopReason { @@ -529,12 +556,18 @@ impl Sim { unsafe { vb_set_execute_callback(self.sim, Some(on_execute)) }; unsafe { vb_set_exception_callback(self.sim, Some(on_exception)) }; unsafe { vb_set_fetch_callback(self.sim, Some(on_fetch)) }; + unsafe { vb_set_write_callback(self.sim, Some(on_write)) }; } else { - if !state.needs_execute_callback() { + let needs_execute = state.needs_execute_callback(); + let needs_write = state.needs_write_callback(); + if !needs_execute { unsafe { vb_set_execute_callback(self.sim, None) }; } unsafe { vb_set_exception_callback(self.sim, None) }; unsafe { vb_set_fetch_callback(self.sim, None) }; + if !needs_write { + unsafe { vb_set_write_callback(self.sim, None) }; + } } } @@ -776,9 +809,10 @@ impl Sim { fn remove_write_watchpoint(&mut self, address: u32, length: usize) { let state = self.get_state(); state.write_watchpoints.remove(address, length); + let needs_write = state.needs_write_callback(); let needs_execute = state.needs_execute_callback(); if state.write_watchpoints.is_empty() { - if state.stdout.is_none() { + if !needs_write { unsafe { vb_set_write_callback(self.sim, None) }; } if !needs_execute { @@ -802,12 +836,15 @@ impl Sim { data.breakpoints.clear(); data.read_watchpoints.clear(); data.write_watchpoints.clear(); - let needs_write = data.stdout.is_some(); + let needs_write = data.needs_write_callback(); + let needs_execute = data.needs_execute_callback(); unsafe { vb_set_read_callback(self.sim, None) }; if !needs_write { unsafe { vb_set_write_callback(self.sim, None) }; } - unsafe { vb_set_execute_callback(self.sim, None) }; + if !needs_execute { + unsafe { vb_set_execute_callback(self.sim, None) }; + } } pub fn watch_stdout(&mut self, watch: bool) { @@ -819,7 +856,7 @@ impl Sim { } } else { data.stdout.take(); - if data.write_watchpoints.is_empty() { + if !data.needs_write_callback() { unsafe { vb_set_write_callback(self.sim, None) }; } }