From dd21771bb302add0c70acb7bd1ce85dd289b3d8a Mon Sep 17 00:00:00 2001 From: transistor Date: Sun, 3 Oct 2021 20:45:50 -0700 Subject: [PATCH] Added better processing of debug commands, and timers --- src/cpus/m68k/debugger.rs | 48 ++++++++++++++++++++++---- src/cpus/m68k/execute.rs | 14 ++++++++ src/main.rs | 5 +-- src/timers.rs | 72 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 130 insertions(+), 9 deletions(-) create mode 100644 src/timers.rs diff --git a/src/cpus/m68k/debugger.rs b/src/cpus/m68k/debugger.rs index f889b1c..f6fd331 100644 --- a/src/cpus/m68k/debugger.rs +++ b/src/cpus/m68k/debugger.rs @@ -34,6 +34,7 @@ impl MC68010 { pub fn check_breakpoints(&mut self) { for breakpoint in &self.debugger.breakpoints { if *breakpoint == self.state.pc { + println!("Breakpoint reached: {:08x}", *breakpoint); self.debugger.use_tracing = true; self.debugger.use_debugger = true; break; @@ -43,19 +44,52 @@ impl MC68010 { pub fn run_debugger(&mut self, space: &mut AddressSpace) { self.dump_state(space); - let mut buffer = String::new(); loop { + let mut buffer = String::new(); std::io::stdin().read_line(&mut buffer).unwrap(); - match buffer.as_ref() { - "dump\n" => space.dump_memory(self.state.msp as Address, (0x200000 - self.state.msp) as Address), - "continue\n" => { - self.debugger.use_debugger = false; - return; + let args: Vec<&str> = buffer.split_whitespace().collect(); + match self.run_debugger_command(space, args) { + Ok(true) => return, + Ok(false) => { }, + Err(err) => { + println!("Error: {}", err.msg); }, - _ => { return; }, } } } + + pub fn run_debugger_command(&mut self, space: &mut AddressSpace, args: Vec<&str>) -> Result { + if args.len() <= 0 { + return Ok(true); + } + + match args[0] { + "b" | "break" | "breakpoint" => { + if args.len() != 2 { + println!("Usage: breakpoint "); + } else { + let addr = u32::from_str_radix(args[1], 16).map_err(|_| Error::new("Unable to parse breakpoint address"))?; + self.add_breakpoint(addr as Address); + println!("Breakpoint set for {:08x}", addr); + } + }, + "d" | "dump" => { + if args.len() > 1 { + let addr = u32::from_str_radix(args[1], 16).map_err(|_| Error::new("Unable to parse address"))?; + let len = if args.len() > 2 { u32::from_str_radix(args[2], 16).map_err(|_| Error::new("Unable to parse length"))? } else { 0x20 }; + space.dump_memory(addr as Address, len as Address); + } else { + space.dump_memory(self.state.msp as Address, 0x40 as Address); + } + }, + "c" | "continue" => { + self.debugger.use_debugger = false; + return Ok(true); + }, + _ => { return Ok(true); }, + } + Ok(false) + } } diff --git a/src/cpus/m68k/execute.rs b/src/cpus/m68k/execute.rs index 78d6f76..91728fa 100644 --- a/src/cpus/m68k/execute.rs +++ b/src/cpus/m68k/execute.rs @@ -1,5 +1,6 @@ use crate::error::Error; +use crate::timers::CpuTimer; use crate::memory::{Address, AddressSpace}; use super::debugger::M68kDebugger; @@ -81,6 +82,7 @@ pub struct MC68010 { pub state: MC68010State, pub decoder: M68kDecoder, pub debugger: M68kDebugger, + pub timer: CpuTimer, } impl MC68010 { @@ -89,6 +91,7 @@ impl MC68010 { state: MC68010State::new(), decoder: M68kDecoder::new(0), debugger: M68kDebugger::new(), + timer: CpuTimer::new(), } } @@ -134,8 +137,15 @@ impl MC68010 { Status::Init => self.init(space), Status::Stopped => Err(Error::new("CPU stopped")), Status::Running => { + let timer = self.timer.cycle.start(); self.decode_next(space)?; self.execute_current(space)?; + self.timer.cycle.end(timer); + + if (self.timer.cycle.events % 500) == 0 { + println!("{}", self.timer); + } + Ok(()) }, } @@ -144,7 +154,9 @@ impl MC68010 { pub fn decode_next(&mut self, space: &mut AddressSpace) -> Result<(), Error> { self.check_breakpoints(); + let timer = self.timer.decode.start(); self.decoder = M68kDecoder::decode_at(space, self.state.pc)?; + self.timer.decode.end(timer); if self.debugger.use_tracing { // Print instruction bytes for debugging @@ -164,6 +176,7 @@ impl MC68010 { } pub fn execute_current(&mut self, space: &mut AddressSpace) -> Result<(), Error> { + let timer = self.timer.decode.start(); match self.decoder.instruction { Instruction::ADD(src, dest, size) => { let value = self.get_target_value(space, src, size)?; @@ -526,6 +539,7 @@ impl MC68010 { _ => { return Err(Error::new("Unsupported instruction")); }, } + self.timer.execute.end(timer); Ok(()) } diff --git a/src/main.rs b/src/main.rs index b631a51..090e731 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ #[macro_use] mod error; mod memory; +mod timers; mod cpus; mod devices; @@ -26,10 +27,10 @@ fn main() { space.insert(0x00700000, Box::new(serial)); let mut cpu = MC68010::new(); - cpu.enable_tracing(); + //cpu.enable_tracing(); //cpu.add_breakpoint(0x0c94); - //cpu.add_breakpoint(0x0cf2); + cpu.add_breakpoint(0x103220); while cpu.is_running() { match cpu.step(&mut space) { diff --git a/src/timers.rs b/src/timers.rs new file mode 100644 index 0000000..e7e3d8e --- /dev/null +++ b/src/timers.rs @@ -0,0 +1,72 @@ + +use std::fmt; +use std::time::Instant; + +pub struct AverageTimer { + pub high: u32, + pub average: f32, + pub low: u32, + pub events: u32, +} + +impl AverageTimer { + pub fn new() -> AverageTimer { + AverageTimer { + high: 0, + average: 0.0, + low: u32::MAX, + events: 0, + } + } + + pub fn start(&self) -> Instant { + Instant::now() + } + + pub fn end(&mut self, timer: Instant) { + let time = timer.elapsed().as_nanos() as u32; + + self.events += 1; + if time > self.high { + self.high = time; + } + if time < self.low { + self.low = time; + } + self.average = (self.average + time as f32) / 2.0; + } +} + +impl fmt::Display for AverageTimer { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "H: {:8} A: {:4} L: {:8} over {} events", self.high, self.average as u32, self.low, self.events) + } +} + + +pub struct CpuTimer { + pub decode: AverageTimer, + pub execute: AverageTimer, + pub cycle: AverageTimer, +} + +impl CpuTimer { + pub fn new() -> CpuTimer { + CpuTimer { + decode: AverageTimer::new(), + execute: AverageTimer::new(), + cycle: AverageTimer::new(), + } + } +} + +impl fmt::Display for CpuTimer { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Decode: {}\n", self.decode)?; + write!(f, "Execute: {}\n", self.execute)?; + write!(f, "Cycle: {}\n", self.cycle)?; + Ok(()) + } +} + +