Added better processing of debug commands, and timers

This commit is contained in:
transistor 2021-10-03 20:45:50 -07:00
parent bc7fee5221
commit dd21771bb3
4 changed files with 130 additions and 9 deletions

View File

@ -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<bool, Error> {
if args.len() <= 0 {
return Ok(true);
}
match args[0] {
"b" | "break" | "breakpoint" => {
if args.len() != 2 {
println!("Usage: breakpoint <addr>");
} 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)
}
}

View File

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

View File

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

72
src/timers.rs Normal file
View File

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