mirror of
https://github.com/transistorfet/moa.git
synced 2024-11-17 07:08:41 +00:00
Added better processing of debug commands, and timers
This commit is contained in:
parent
bc7fee5221
commit
dd21771bb3
@ -34,6 +34,7 @@ impl MC68010 {
|
|||||||
pub fn check_breakpoints(&mut self) {
|
pub fn check_breakpoints(&mut self) {
|
||||||
for breakpoint in &self.debugger.breakpoints {
|
for breakpoint in &self.debugger.breakpoints {
|
||||||
if *breakpoint == self.state.pc {
|
if *breakpoint == self.state.pc {
|
||||||
|
println!("Breakpoint reached: {:08x}", *breakpoint);
|
||||||
self.debugger.use_tracing = true;
|
self.debugger.use_tracing = true;
|
||||||
self.debugger.use_debugger = true;
|
self.debugger.use_debugger = true;
|
||||||
break;
|
break;
|
||||||
@ -43,19 +44,52 @@ impl MC68010 {
|
|||||||
|
|
||||||
pub fn run_debugger(&mut self, space: &mut AddressSpace) {
|
pub fn run_debugger(&mut self, space: &mut AddressSpace) {
|
||||||
self.dump_state(space);
|
self.dump_state(space);
|
||||||
let mut buffer = String::new();
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
let mut buffer = String::new();
|
||||||
std::io::stdin().read_line(&mut buffer).unwrap();
|
std::io::stdin().read_line(&mut buffer).unwrap();
|
||||||
match buffer.as_ref() {
|
let args: Vec<&str> = buffer.split_whitespace().collect();
|
||||||
"dump\n" => space.dump_memory(self.state.msp as Address, (0x200000 - self.state.msp) as Address),
|
match self.run_debugger_command(space, args) {
|
||||||
"continue\n" => {
|
Ok(true) => return,
|
||||||
self.debugger.use_debugger = false;
|
Ok(false) => { },
|
||||||
return;
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
|
use crate::timers::CpuTimer;
|
||||||
use crate::memory::{Address, AddressSpace};
|
use crate::memory::{Address, AddressSpace};
|
||||||
|
|
||||||
use super::debugger::M68kDebugger;
|
use super::debugger::M68kDebugger;
|
||||||
@ -81,6 +82,7 @@ pub struct MC68010 {
|
|||||||
pub state: MC68010State,
|
pub state: MC68010State,
|
||||||
pub decoder: M68kDecoder,
|
pub decoder: M68kDecoder,
|
||||||
pub debugger: M68kDebugger,
|
pub debugger: M68kDebugger,
|
||||||
|
pub timer: CpuTimer,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MC68010 {
|
impl MC68010 {
|
||||||
@ -89,6 +91,7 @@ impl MC68010 {
|
|||||||
state: MC68010State::new(),
|
state: MC68010State::new(),
|
||||||
decoder: M68kDecoder::new(0),
|
decoder: M68kDecoder::new(0),
|
||||||
debugger: M68kDebugger::new(),
|
debugger: M68kDebugger::new(),
|
||||||
|
timer: CpuTimer::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,8 +137,15 @@ impl MC68010 {
|
|||||||
Status::Init => self.init(space),
|
Status::Init => self.init(space),
|
||||||
Status::Stopped => Err(Error::new("CPU stopped")),
|
Status::Stopped => Err(Error::new("CPU stopped")),
|
||||||
Status::Running => {
|
Status::Running => {
|
||||||
|
let timer = self.timer.cycle.start();
|
||||||
self.decode_next(space)?;
|
self.decode_next(space)?;
|
||||||
self.execute_current(space)?;
|
self.execute_current(space)?;
|
||||||
|
self.timer.cycle.end(timer);
|
||||||
|
|
||||||
|
if (self.timer.cycle.events % 500) == 0 {
|
||||||
|
println!("{}", self.timer);
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -144,7 +154,9 @@ impl MC68010 {
|
|||||||
pub fn decode_next(&mut self, space: &mut AddressSpace) -> Result<(), Error> {
|
pub fn decode_next(&mut self, space: &mut AddressSpace) -> Result<(), Error> {
|
||||||
self.check_breakpoints();
|
self.check_breakpoints();
|
||||||
|
|
||||||
|
let timer = self.timer.decode.start();
|
||||||
self.decoder = M68kDecoder::decode_at(space, self.state.pc)?;
|
self.decoder = M68kDecoder::decode_at(space, self.state.pc)?;
|
||||||
|
self.timer.decode.end(timer);
|
||||||
|
|
||||||
if self.debugger.use_tracing {
|
if self.debugger.use_tracing {
|
||||||
// Print instruction bytes for debugging
|
// Print instruction bytes for debugging
|
||||||
@ -164,6 +176,7 @@ impl MC68010 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute_current(&mut self, space: &mut AddressSpace) -> Result<(), Error> {
|
pub fn execute_current(&mut self, space: &mut AddressSpace) -> Result<(), Error> {
|
||||||
|
let timer = self.timer.decode.start();
|
||||||
match self.decoder.instruction {
|
match self.decoder.instruction {
|
||||||
Instruction::ADD(src, dest, size) => {
|
Instruction::ADD(src, dest, size) => {
|
||||||
let value = self.get_target_value(space, src, size)?;
|
let value = self.get_target_value(space, src, size)?;
|
||||||
@ -526,6 +539,7 @@ impl MC68010 {
|
|||||||
_ => { return Err(Error::new("Unsupported instruction")); },
|
_ => { return Err(Error::new("Unsupported instruction")); },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.timer.execute.end(timer);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod error;
|
mod error;
|
||||||
mod memory;
|
mod memory;
|
||||||
|
mod timers;
|
||||||
mod cpus;
|
mod cpus;
|
||||||
mod devices;
|
mod devices;
|
||||||
|
|
||||||
@ -26,10 +27,10 @@ fn main() {
|
|||||||
space.insert(0x00700000, Box::new(serial));
|
space.insert(0x00700000, Box::new(serial));
|
||||||
|
|
||||||
let mut cpu = MC68010::new();
|
let mut cpu = MC68010::new();
|
||||||
cpu.enable_tracing();
|
//cpu.enable_tracing();
|
||||||
|
|
||||||
//cpu.add_breakpoint(0x0c94);
|
//cpu.add_breakpoint(0x0c94);
|
||||||
//cpu.add_breakpoint(0x0cf2);
|
cpu.add_breakpoint(0x103220);
|
||||||
|
|
||||||
while cpu.is_running() {
|
while cpu.is_running() {
|
||||||
match cpu.step(&mut space) {
|
match cpu.step(&mut space) {
|
||||||
|
72
src/timers.rs
Normal file
72
src/timers.rs
Normal 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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user