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
This commit is contained in:
transistor 2021-12-20 19:53:12 -08:00
parent 5095aee531
commit cbf91309d9
8 changed files with 57 additions and 27 deletions

View File

@ -28,6 +28,7 @@ impl StackTracer {
pub struct M68kDebugger {
pub enabled: bool,
pub breakpoints: Vec<u32>,
pub use_tracing: bool,
pub step_until_return: Option<usize>,
@ -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();
}
}

View File

@ -28,8 +28,7 @@ use super::state::{M68k, M68kType, Status, Flags, Exceptions, InterruptPriority}
impl Steppable for M68k {
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
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<ClockElapsed, Error> {
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<ClockElapsed, Error> {
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<ClockElapsed, Error> {
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)?;

View File

@ -8,25 +8,37 @@ use super::decode::Z80Decoder;
pub struct Z80Debugger {
pub enabled: bool,
pub breakpoints: Vec<u16>,
}
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();
}
}

View File

@ -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<u8, Error> {
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<u16, Error> {
let word = device.read_leu16(self.end as Address)?;
self.end += 2;
self.execution_time += 8;
Ok(word)
}

View File

@ -23,10 +23,13 @@ enum RotateType {
impl Steppable for Z80 {
fn step(&mut self, system: &System) -> Result<ClockElapsed, Error> {
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<u16, Error> {
self.state.pc = 0;
self.state.status = Status::Running;
Ok(4)
Ok(16)
}
pub fn reset(&mut self) -> Result<u16, Error> {
@ -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 {

View File

@ -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 {

View File

@ -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);

View File

@ -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() {