mirror of
https://github.com/transistorfet/moa.git
synced 2024-06-02 15:41:47 +00:00
cff6a48cc7
I'm trying to extract the memory/bus interface, and pass it in at the start of each cycle instead of having the BusPort permanently embedded, which will allow migrating to emulator-hal. The functional way would be argument drilling; passing an extra argument to each function in the entire execution core. The problem is that it's messy, so a solution that is still functional is to implement all of the execution logic on a newtype that contains a reference to the mutable state and the owned cycle data, and at the end of the cycle, decompose the M68kCycleGuard that holds the reference, and keep the cycle data for debugging purposes.
90 lines
2.7 KiB
Rust
90 lines
2.7 KiB
Rust
|
|
use moa_core::{System, Error, Address, Addressable, Debuggable};
|
|
|
|
use super::state::M68k;
|
|
use super::decode::M68kDecoder;
|
|
use super::execute::M68kCycleGuard;
|
|
|
|
#[derive(Clone, Default)]
|
|
pub struct StackTracer {
|
|
pub calls: Vec<u32>,
|
|
}
|
|
|
|
impl StackTracer {
|
|
pub fn push_return(&mut self, addr: u32) {
|
|
self.calls.push(addr);
|
|
}
|
|
|
|
pub fn pop_return(&mut self) {
|
|
self.calls.pop();
|
|
}
|
|
}
|
|
|
|
|
|
#[derive(Clone, Default)]
|
|
pub struct M68kDebugger {
|
|
pub(crate) skip_breakpoint: usize,
|
|
pub(crate) breakpoints: Vec<u32>,
|
|
pub(crate) step_until_return: Option<usize>,
|
|
pub(crate) stack_tracer: StackTracer,
|
|
}
|
|
|
|
impl Debuggable for M68k {
|
|
fn add_breakpoint(&mut self, addr: Address) {
|
|
self.debugger.breakpoints.push(addr as u32);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
fn print_current_step(&mut self, _system: &System) -> Result<(), Error> {
|
|
// TODO this is called by the debugger, but should be called some other way
|
|
//let _ = self.decoder.decode_at(&mut self.port, true, self.state.pc);
|
|
//self.decoder.dump_decoded(&mut self.port);
|
|
//self.dump_state();
|
|
Ok(())
|
|
}
|
|
|
|
fn print_disassembly(&mut self, addr: Address, count: usize) {
|
|
let mut decoder = M68kDecoder::new(self.cputype, true, 0);
|
|
decoder.dump_disassembly(&mut self.port, addr as u32, count as u32);
|
|
}
|
|
|
|
fn run_command(&mut self, system: &System, args: &[&str]) -> Result<bool, Error> {
|
|
match args[0] {
|
|
"ds" | "stack" | "dumpstack" => {
|
|
println!("Stack:");
|
|
for addr in &self.debugger.stack_tracer.calls {
|
|
println!(" {:08x}", self.port.port.read_beu32(system.clock, *addr as Address)?);
|
|
}
|
|
},
|
|
"so" | "stepout" => {
|
|
self.debugger.step_until_return = Some(self.debugger.stack_tracer.calls.len() - 1);
|
|
},
|
|
_ => { return Ok(true); },
|
|
}
|
|
Ok(false)
|
|
}
|
|
}
|
|
|
|
impl<'a> M68kCycleGuard<'a> {
|
|
pub fn check_breakpoints(&mut self) -> Result<(), Error> {
|
|
for breakpoint in &self.debugger.breakpoints {
|
|
if *breakpoint == self.state.pc {
|
|
if self.debugger.skip_breakpoint > 0 {
|
|
self.debugger.skip_breakpoint -= 1;
|
|
return Ok(());
|
|
} else {
|
|
self.debugger.skip_breakpoint = 1;
|
|
return Err(Error::breakpoint(format!("breakpoint reached: {:08x}", *breakpoint)));
|
|
}
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|