From cbf91309d91d236f6c182880820469982f445601 Mon Sep 17 00:00:00 2001 From: transistor Date: Mon, 20 Dec 2021 19:53:12 -0800 Subject: [PATCH] Fixed debugger to easier debug one cpu at a time Previously it would show a dump of whatever device was next scheduled to step, if it was Debuggable, but now each debuggable device has a flag for whether that device is being debugging, and a system flag to disable it entirely. When the system flag is set, it will try to enable debugging on the device labelled "cpu". I need to also add a way of setting a breakpoint on a named device, which will enable debugging of that device --- src/cpus/m68k/debugger.rs | 12 ++++++++++++ src/cpus/m68k/execute.rs | 19 +++++++++---------- src/cpus/z80/debugger.rs | 12 ++++++++++++ src/cpus/z80/decode.rs | 5 +++++ src/cpus/z80/execute.rs | 20 ++++++-------------- src/debugger.rs | 1 + src/devices.rs | 2 ++ src/system.rs | 13 ++++++++++--- 8 files changed, 57 insertions(+), 27 deletions(-) diff --git a/src/cpus/m68k/debugger.rs b/src/cpus/m68k/debugger.rs index f0d1e05..a0a7d5b 100644 --- a/src/cpus/m68k/debugger.rs +++ b/src/cpus/m68k/debugger.rs @@ -28,6 +28,7 @@ impl StackTracer { pub struct M68kDebugger { + pub enabled: bool, pub breakpoints: Vec, pub use_tracing: bool, pub step_until_return: Option, @@ -37,6 +38,7 @@ pub struct M68kDebugger { impl M68kDebugger { pub fn new() -> M68kDebugger { M68kDebugger { + enabled: false, breakpoints: vec!(), use_tracing: false, step_until_return: None, @@ -46,13 +48,23 @@ impl M68kDebugger { } impl Debuggable for M68k { + fn debugging_enabled(&mut self) -> bool { + self.debugger.enabled + } + + fn set_debugging(&mut self, enable: bool) { + self.debugger.enabled = enable; + } + fn add_breakpoint(&mut self, addr: Address) { self.debugger.breakpoints.push(addr as u32); + self.debugger.enabled = true; } fn remove_breakpoint(&mut self, addr: Address) { if let Some(index) = self.debugger.breakpoints.iter().position(|a| *a == addr as u32) { self.debugger.breakpoints.remove(index); + self.debugger.enabled = !self.debugger.breakpoints.is_empty(); } } diff --git a/src/cpus/m68k/execute.rs b/src/cpus/m68k/execute.rs index b1b9839..afd4a2a 100644 --- a/src/cpus/m68k/execute.rs +++ b/src/cpus/m68k/execute.rs @@ -28,8 +28,7 @@ use super::state::{M68k, M68kType, Status, Flags, Exceptions, InterruptPriority} impl Steppable for M68k { fn step(&mut self, system: &System) -> Result { - self.step_internal(system)?; - Ok((1_000_000_000 / self.frequency as u64) * self.timing.calculate_clocks(false, 1) as ClockElapsed) + self.step_internal(system) } fn on_error(&mut self, system: &System) { @@ -60,18 +59,18 @@ impl M68k { self.state.status != Status::Stopped } - pub fn step_internal(&mut self, system: &System) -> Result<(), Error> { + pub fn step_internal(&mut self, system: &System) -> Result { match self.state.status { Status::Init => self.init(), Status::Stopped => Err(Error::new("CPU stopped")), Status::Running => { match self.cycle_one(system) { - Ok(()) => Ok(()), + Ok(diff) => Ok(diff), //Err(Error { err: ErrorType::Processor, native, .. }) => { // TODO match arm conditional is temporary: illegal instructions generate a top level error in order to debug and fix issues with decode Err(Error { err: ErrorType::Processor, native, .. }) if native != Exceptions::IllegalInstruction as u32 => { self.exception(native as u8, false)?; - Ok(()) + Ok(4) }, Err(err) => Err(err), } @@ -79,14 +78,14 @@ impl M68k { } } - pub fn init(&mut self) -> Result<(), Error> { + pub fn init(&mut self) -> Result { self.state.ssp = self.port.read_beu32(0)?; self.state.pc = self.port.read_beu32(4)?; self.state.status = Status::Running; - Ok(()) + Ok(16) } - pub fn cycle_one(&mut self, system: &System) -> Result<(), Error> { + pub fn cycle_one(&mut self, system: &System) -> Result { self.timer.cycle.start(); self.decode_next()?; self.execute_current()?; @@ -98,7 +97,7 @@ impl M68k { self.check_pending_interrupts(system)?; self.check_breakpoints(system); - Ok(()) + Ok((1_000_000_000 / self.frequency as u64) * self.timing.calculate_clocks(false, 1) as ClockElapsed) } pub fn check_pending_interrupts(&mut self, system: &System) -> Result<(), Error> { @@ -114,7 +113,7 @@ impl M68k { let priority_mask = ((self.state.sr & Flags::IntMask as u16) >> 8) as u8; if (pending_ipl > priority_mask || pending_ipl == 7) && pending_ipl >= current_ipl { - debug!("{} interrupt: {} {}", DEV_NAME, pending_ipl, priority_mask); + debug!("{} interrupt: {} @ {} ns", DEV_NAME, pending_ipl, system.clock); self.state.current_ipl = self.state.pending_ipl; let ack_num = system.get_interrupt_controller().acknowledge(self.state.current_ipl as u8)?; self.exception(ack_num, true)?; diff --git a/src/cpus/z80/debugger.rs b/src/cpus/z80/debugger.rs index 045ab6a..48c2fa5 100644 --- a/src/cpus/z80/debugger.rs +++ b/src/cpus/z80/debugger.rs @@ -8,25 +8,37 @@ use super::decode::Z80Decoder; pub struct Z80Debugger { + pub enabled: bool, pub breakpoints: Vec, } impl Z80Debugger { pub fn new() -> Self { Self { + enabled: false, breakpoints: vec!(), } } } impl Debuggable for Z80 { + fn debugging_enabled(&mut self) -> bool { + self.debugger.enabled + } + + fn set_debugging(&mut self, enable: bool) { + self.debugger.enabled = enable; + } + fn add_breakpoint(&mut self, addr: Address) { self.debugger.breakpoints.push(addr as u16); + self.debugger.enabled = true; } fn remove_breakpoint(&mut self, addr: Address) { if let Some(index) = self.debugger.breakpoints.iter().position(|a| *a == addr as u16) { self.debugger.breakpoints.remove(index); + self.debugger.enabled = !self.debugger.breakpoints.is_empty(); } } diff --git a/src/cpus/z80/decode.rs b/src/cpus/z80/decode.rs index eccea53..5960f84 100644 --- a/src/cpus/z80/decode.rs +++ b/src/cpus/z80/decode.rs @@ -177,6 +177,7 @@ pub struct Z80Decoder { pub start: u16, pub end: u16, pub instruction: Instruction, + pub execution_time: u16, } impl Z80Decoder { @@ -185,6 +186,7 @@ impl Z80Decoder { start: 0, end: 0, instruction: Instruction::NOP, + execution_time: 0, } } } @@ -193,6 +195,7 @@ impl Z80Decoder { pub fn decode_at(&mut self, memory: &mut dyn Addressable, start: u16) -> Result<(), Error> { self.start = start; self.end = start; + self.execution_time = 0; self.instruction = self.decode_one(memory)?; Ok(()) } @@ -674,12 +677,14 @@ impl Z80Decoder { fn read_instruction_byte(&mut self, device: &mut dyn Addressable) -> Result { let byte = device.read_u8(self.end as Address)?; self.end += 1; + self.execution_time += 4; Ok(byte) } fn read_instruction_word(&mut self, device: &mut dyn Addressable) -> Result { let word = device.read_leu16(self.end as Address)?; self.end += 2; + self.execution_time += 8; Ok(word) } diff --git a/src/cpus/z80/execute.rs b/src/cpus/z80/execute.rs index 91fadfe..ec4f3e2 100644 --- a/src/cpus/z80/execute.rs +++ b/src/cpus/z80/execute.rs @@ -23,10 +23,13 @@ enum RotateType { impl Steppable for Z80 { fn step(&mut self, system: &System) -> Result { let clocks = if self.reset.get() { +//println!("RESET"); self.reset()? } else if self.bus_request.get() { - 1 +//println!("BUS REQ"); + 4 } else { +//println!("RUNNING {:?}", self.decoder.instruction); self.step_internal(system)? }; @@ -77,7 +80,7 @@ impl Z80 { pub fn init(&mut self) -> Result { self.state.pc = 0; self.state.status = Status::Running; - Ok(4) + Ok(16) } pub fn reset(&mut self) -> Result { @@ -90,7 +93,7 @@ impl Z80 { self.execute_current()?; //self.check_pending_interrupts(system)?; self.check_breakpoints(system); - Ok(4) + Ok(self.decoder.execution_time) } pub fn decode_next(&mut self) -> Result<(), Error> { @@ -878,17 +881,6 @@ fn sub_words(operand1: u16, operand2: u16) -> (u16, bool, bool) { (result, carry, overflow) } - -#[inline(always)] -fn get_msb_byte(value: u8) -> bool { - (value & 0x80) != 0 -} - -#[inline(always)] -fn get_msb_word(value: u16) -> bool { - (value & 0x8000) != 0 -} - #[inline(always)] fn get_msb(value: u16, size: Size) -> bool { match size { diff --git a/src/debugger.rs b/src/debugger.rs index 3531729..f0df4e8 100644 --- a/src/debugger.rs +++ b/src/debugger.rs @@ -29,6 +29,7 @@ impl Debugger { pub fn run_debugger(&mut self, system: &System, target: TransmutableBox) -> Result<(), Error> { let mut target = target.borrow_mut(); let debug_obj = target.as_debuggable().unwrap(); + println!("@ {} ns", system.clock); debug_obj.print_current_step(system)?; if self.trace_only { diff --git a/src/devices.rs b/src/devices.rs index 951bc4d..b916c81 100644 --- a/src/devices.rs +++ b/src/devices.rs @@ -162,6 +162,8 @@ pub fn write_leu32(data: &mut [u8], value: u32) -> &mut [u8] { /// A device (cpu) that can debugged using the built-in debugger pub trait Debuggable { + fn debugging_enabled(&mut self) -> bool; + fn set_debugging(&mut self, enable: bool); fn add_breakpoint(&mut self, addr: Address); fn remove_breakpoint(&mut self, addr: Address); diff --git a/src/system.rs b/src/system.rs index 9779c12..034ace4 100644 --- a/src/system.rs +++ b/src/system.rs @@ -76,6 +76,7 @@ impl System { pub fn enable_debugging(&self) { self.debug_enabled.set(true); + self.devices.get("cpu").map(|result| result.try_borrow_mut().map(|mut borrow| borrow.as_debuggable().map(|debug| debug.set_debugging(true)))); self.debugger.borrow_mut().breakpoint_occurred(); } @@ -98,9 +99,7 @@ impl System { } pub fn step(&mut self) -> Result<(), Error> { - if self.debug_enabled.get() && self.event_queue[self.event_queue.len() - 1].device.borrow_mut().as_debuggable().is_some() { - self.debugger.borrow_mut().run_debugger(&self, self.event_queue[self.event_queue.len() - 1].device.clone()).unwrap(); - } + self.check_debugger(); match self.process_one_event() { Ok(()) => { } @@ -151,6 +150,14 @@ impl System { } } + fn check_debugger(&mut self) { + if self.debug_enabled.get() { + let top = self.event_queue[self.event_queue.len() - 1].device.clone(); + if top.borrow_mut().as_debuggable().map(|debug| debug.debugging_enabled()).unwrap_or(false) { + self.debugger.borrow_mut().run_debugger(&self, top.clone()).unwrap(); + } + } + } fn try_queue_device(&mut self, device: TransmutableBox) { if device.borrow_mut().as_steppable().is_some() {