Let emulator tell debugger to stop
This commit is contained in:
+86
-2
@@ -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)]
|
||||
|
||||
Reference in New Issue
Block a user