mirror of
https://github.com/transistorfet/moa.git
synced 2024-09-27 01:54:50 +00:00
125 lines
4.3 KiB
Rust
125 lines
4.3 KiB
Rust
|
|
use femtos::{Instant, Duration};
|
|
use emulator_hal::bus;
|
|
|
|
use moa_core::{System, Error, Address, Steppable, Interruptable, Addressable, Debuggable, Transmutable};
|
|
|
|
use crate::state::{M68k, M68kError};
|
|
use crate::decode::M68kDecoder;
|
|
use crate::execute::M68kCycle;
|
|
|
|
impl Steppable for M68k {
|
|
fn step(&mut self, system: &System) -> Result<Duration, Error> {
|
|
let cycle = M68kCycle::new(self, system.clock);
|
|
|
|
let mut bus = system.bus.borrow_mut();
|
|
let mut adapter: bus::BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error> = bus::BusAdapter::new(
|
|
&mut *bus,
|
|
|addr| addr as u64,
|
|
|err| err.try_into().unwrap(),
|
|
);
|
|
|
|
let mut executor = cycle.begin(self, &mut adapter);
|
|
executor.check_breakpoints()?;
|
|
executor.step()?;
|
|
|
|
let interrupt = system.get_interrupt_controller().check();
|
|
if let (priority, Some(ack)) = executor.check_pending_interrupts(interrupt)? {
|
|
log::debug!("interrupt: {:?} @ {} ns", priority, system.clock.as_duration().as_nanos());
|
|
system.get_interrupt_controller().acknowledge(priority as u8)?;
|
|
}
|
|
|
|
self.cycle = Some(executor.end());
|
|
Ok(self.last_cycle_duration())
|
|
}
|
|
|
|
fn on_error(&mut self, _system: &System) {
|
|
let mut output = String::with_capacity(256);
|
|
self.dump_state(&mut output);
|
|
println!("{}", output);
|
|
}
|
|
}
|
|
|
|
impl Interruptable for M68k { }
|
|
|
|
impl Transmutable for M68k {
|
|
fn as_steppable(&mut self) -> Option<&mut dyn Steppable> {
|
|
Some(self)
|
|
}
|
|
|
|
fn as_interruptable(&mut self) -> Option<&mut dyn Interruptable> {
|
|
Some(self)
|
|
}
|
|
|
|
fn as_debuggable(&mut self) -> Option<&mut dyn Debuggable> {
|
|
Some(self)
|
|
}
|
|
}
|
|
|
|
impl<BusError> From<Error> for M68kError<BusError> {
|
|
fn from(err: Error) -> Self {
|
|
match err {
|
|
Error::Processor(ex) => M68kError::Interrupt(ex as u8),
|
|
Error::Breakpoint(msg) => M68kError::Breakpoint,
|
|
Error::Other(msg) | Error::Assertion(msg) | Error::Emulator(_, msg) => M68kError::Other(format!("{}", msg)),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<BusError: bus::Error> From<M68kError<BusError>> for Error {
|
|
fn from(err: M68kError<BusError>) -> Self {
|
|
match err {
|
|
M68kError::Halted => Self::Other("cpu halted".to_string()),
|
|
M68kError::Exception(ex) => Self::Processor(ex as u32),
|
|
M68kError::Interrupt(num) => Self::Processor(num as u32),
|
|
M68kError::Breakpoint => Self::Breakpoint("breakpoint".to_string()),
|
|
M68kError::InvalidTarget(target) => Self::new(target.to_string()),
|
|
M68kError::BusError(msg) => Self::Other(format!("{:?}", msg)),
|
|
M68kError::Other(msg) => Self::Other(msg),
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
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.bus, true, self.state.pc);
|
|
//self.decoder.dump_decoded(&mut self.bus);
|
|
//self.dump_state();
|
|
Ok(())
|
|
}
|
|
|
|
fn print_disassembly(&mut self, addr: Address, count: usize) {
|
|
let mut decoder = M68kDecoder::new(self.info.chip, true, 0);
|
|
//decoder.dump_disassembly(&mut self.bus, self.cycle.memory, 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}", system.bus.borrow_mut().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)
|
|
}
|
|
}
|
|
|