Let emulator tell debugger to stop

This commit is contained in:
2025-01-04 01:04:21 -05:00
parent a5b5f8e80f
commit 11df670ff4
4 changed files with 392 additions and 246 deletions
+86 -2
View File
@@ -151,6 +151,7 @@ pub struct Emulator {
linked: Arc<AtomicBool>,
renderers: HashMap<SimId, TextureSink>,
messages: HashMap<SimId, mpsc::Sender<Toast>>,
debuggers: HashMap<SimId, DebugInfo>,
eye_contents: Vec<u8>,
audio_samples: Vec<f32>,
}
@@ -174,6 +175,7 @@ impl Emulator {
linked,
renderers: HashMap::new(),
messages: HashMap::new(),
debuggers: HashMap::new(),
eye_contents: vec![0u8; 384 * 224 * 2],
audio_samples: vec![0.0; EXPECTED_FRAME_SIZE],
})
@@ -288,6 +290,48 @@ impl Emulator {
Ok(())
}
fn start_debugging(&mut self, sim_id: SimId, sender: DebugSender) {
let debug = DebugInfo {
sender,
stop_reason: Some(DebugStopReason::Trapped),
};
self.debuggers.insert(sim_id, debug);
self.state
.store(EmulatorState::Debugging, Ordering::Release);
}
fn stop_debugging(&mut self, sim_id: SimId) {
self.debuggers.remove(&sim_id);
if self.debuggers.is_empty() {
self.state.store(EmulatorState::Running, Ordering::Release);
}
}
fn debug_interrupt(&mut self, sim_id: SimId) {
let Some(debugger) = self.debuggers.get_mut(&sim_id) else {
self.stop_debugging(sim_id);
return;
};
if !matches!(debugger.stop_reason, Some(DebugStopReason::Trapped)) {
debugger.stop_reason = Some(DebugStopReason::Trapped);
if debugger
.sender
.send(DebugEvent::Stopped(DebugStopReason::Trapped))
.is_err()
{
self.stop_debugging(sim_id);
}
}
}
fn debug_continue(&mut self, sim_id: SimId) {
let Some(debugger) = self.debuggers.get_mut(&sim_id) else {
self.stop_debugging(sim_id);
return;
};
debugger.stop_reason = None;
}
pub fn run(&mut self) {
loop {
let idle = self.tick();
@@ -320,8 +364,14 @@ impl Emulator {
let p1_state = self.sim_state[SimId::Player1.to_index()].load(Ordering::Acquire);
let p2_state = self.sim_state[SimId::Player2.to_index()].load(Ordering::Acquire);
let state = self.state.load(Ordering::Acquire);
let p1_running = state == EmulatorState::Running && p1_state == SimState::Ready;
let p2_running = state == EmulatorState::Running && p2_state == SimState::Ready;
// Don't emulate if the state is "paused", or if any sim is paused in the debugger
let running = match state {
EmulatorState::Paused => false,
EmulatorState::Running => true,
EmulatorState::Debugging => self.debuggers.values().all(|d| d.stop_reason.is_none()),
};
let p1_running = running && p1_state == SimState::Ready;
let p2_running = running && p2_state == SimState::Ready;
let mut idle = !p1_running && !p2_running;
if p1_running && p2_running {
Sim::emulate_many(&mut self.sims);
@@ -405,6 +455,18 @@ impl Emulator {
EmulatorCommand::Resume => {
self.resume_sims();
}
EmulatorCommand::StartDebugging(sim_id, debugger) => {
self.start_debugging(sim_id, debugger);
}
EmulatorCommand::StopDebugging(sim_id) => {
self.stop_debugging(sim_id);
}
EmulatorCommand::DebugInterrupt(sim_id) => {
self.debug_interrupt(sim_id);
}
EmulatorCommand::DebugContinue(sim_id) => {
self.debug_continue(sim_id);
}
EmulatorCommand::ReadRegister(sim_id, register, done) => {
let Some(sim) = self.sims.get_mut(sim_id.to_index()) else {
return;
@@ -476,6 +538,10 @@ pub enum EmulatorCommand {
StopSecondSim,
Pause,
Resume,
StartDebugging(SimId, DebugSender),
StopDebugging(SimId),
DebugInterrupt(SimId),
DebugContinue(SimId),
ReadRegister(SimId, VBRegister, oneshot::Sender<u32>),
ReadMemory(SimId, Range<u32>, Vec<u8>, oneshot::Sender<Vec<u8>>),
SetAudioEnabled(bool, bool),
@@ -499,6 +565,24 @@ pub enum SimState {
pub enum EmulatorState {
Paused,
Running,
Debugging,
}
type DebugSender = tokio::sync::mpsc::UnboundedSender<DebugEvent>;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DebugStopReason {
// The debugger told us to pause
Trapped,
}
struct DebugInfo {
sender: DebugSender,
stop_reason: Option<DebugStopReason>,
}
pub enum DebugEvent {
Stopped(DebugStopReason),
}
#[derive(Clone)]