From 545f339fe2714cc648bd4a01506518a13c1faf39 Mon Sep 17 00:00:00 2001 From: transistor Date: Wed, 13 Mar 2024 21:49:04 -0700 Subject: [PATCH] Separated moa-core dependency into an optional feature flag --- Cargo.lock | 2 + Cargo.toml | 2 + docs/log.txt | 5 + emulator/core/src/error.rs | 2 + emulator/core/src/interrupts.rs | 6 +- emulator/core/src/lib.rs | 2 +- emulator/core/src/memory.rs | 32 ++- emulator/cpus/m68k/Cargo.toml | 6 +- emulator/cpus/m68k/src/assembler.rs | 20 +- emulator/cpus/m68k/src/debugger.rs | 54 +--- emulator/cpus/m68k/src/decode.rs | 14 +- emulator/cpus/m68k/src/execute.rs | 262 ++++++------------ emulator/cpus/m68k/src/lib.rs | 3 + emulator/cpus/m68k/src/memory.rs | 134 ++++++--- emulator/cpus/m68k/src/moa.rs | 124 +++++++++ emulator/cpus/m68k/src/state.rs | 51 +++- emulator/cpus/m68k/src/tests.rs | 162 ++++++----- emulator/cpus/m68k/tests/decode_tests.rs | 25 +- emulator/cpus/m68k/tests/execute_tests.rs | 16 +- .../cpus/m68k/tests/musashi_timing_tests.rs | 13 +- emulator/cpus/m68k/tests/timing_tests.rs | 13 +- emulator/frontends/common/src/tty.rs | 15 +- emulator/frontends/console/Cargo.toml | 4 +- emulator/frontends/console/src/lib.rs | 7 +- emulator/libraries/parsing/src/lib.rs | 48 ++-- emulator/systems/computie/Cargo.toml | 2 +- emulator/systems/computie/src/system.rs | 4 +- emulator/systems/genesis/Cargo.toml | 2 +- emulator/systems/genesis/src/system.rs | 2 +- emulator/systems/macintosh/Cargo.toml | 2 +- emulator/systems/macintosh/src/system.rs | 2 +- tests/harte_tests/Cargo.toml | 2 +- tests/harte_tests/latest.txt | 92 +----- todo.txt | 4 + 34 files changed, 622 insertions(+), 512 deletions(-) create mode 100644 emulator/cpus/m68k/src/moa.rs diff --git a/Cargo.lock b/Cargo.lock index 1c2f7d1..38dd4a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -774,6 +774,8 @@ dependencies = [ "log", "moa-common", "moa-core", + "moa-debugger", + "moa-host", "moa-m68k", "moa-peripherals-generic", "moa-peripherals-motorola", diff --git a/Cargo.toml b/Cargo.toml index 7450c3d..a235837 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,5 @@ [workspace] +resolver = "2" members = [ "emulator/core", "emulator/frontends/common", @@ -18,5 +19,6 @@ opt-level = 3 [profile.release] debug = true +# TODO there are many overflow errors, which could be bugs #overflow-checks = true diff --git a/docs/log.txt b/docs/log.txt index b335bdc..b15f51c 100644 --- a/docs/log.txt +++ b/docs/log.txt @@ -479,3 +479,8 @@ General Work - So far it's going quite well. I really like the pattern of making the cycle be like a transaction, and making it possible to decompose it, especially for testing. I still need to fix the tests - next step is to push System up from the interrupt handling code + +2024-03-10 +- the emulator-hal conversion is going well. I'm thinking it makes more sense for the Address of + BusAccess to be a generic instead of an associated type, but I'll need to finish converting + everything to get a better sense of it. There's a lot of cleanup to do diff --git a/emulator/core/src/error.rs b/emulator/core/src/error.rs index cdc5ea8..d438343 100644 --- a/emulator/core/src/error.rs +++ b/emulator/core/src/error.rs @@ -3,6 +3,8 @@ use std::fmt; use std::error::{Error as StdError}; use moa_host::HostError; +use emulator_hal::bus; + #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum EmulatorErrorKind { Misc, diff --git a/emulator/core/src/interrupts.rs b/emulator/core/src/interrupts.rs index e668807..bcec953 100644 --- a/emulator/core/src/interrupts.rs +++ b/emulator/core/src/interrupts.rs @@ -26,11 +26,11 @@ impl InterruptController { Ok(()) } - pub fn check(&mut self) -> (bool, u8) { + pub fn check(&mut self) -> (bool, u8, u8) { if self.highest > 0 { - (true, self.highest) + (true, self.highest, self.interrupts[self.highest as usize].1) } else { - (false, 0) + (false, 0, 0) } } diff --git a/emulator/core/src/lib.rs b/emulator/core/src/lib.rs index 69c5571..d3f38f9 100644 --- a/emulator/core/src/lib.rs +++ b/emulator/core/src/lib.rs @@ -11,7 +11,7 @@ pub use crate::devices::{Address, Addressable, Steppable, Interruptable, Debugga pub use crate::devices::{read_beu16, read_beu32, read_leu16, read_leu32, write_beu16, write_beu32, write_leu16, write_leu32, wrap_transmutable}; pub use crate::error::Error; pub use crate::interrupts::InterruptController; -pub use crate::memory::{MemoryBlock, AddressTranslator, AddressRepeater, Bus, BusPort, dump_slice}; +pub use crate::memory::{MemoryBlock, AddressTranslator, AddressRepeater, Bus, BusPort, dump_slice, dump_memory}; pub use crate::system::System; pub use emulator_hal::bus::{BusAccess}; diff --git a/emulator/core/src/memory.rs b/emulator/core/src/memory.rs index dd411f7..09c44da 100644 --- a/emulator/core/src/memory.rs +++ b/emulator/core/src/memory.rs @@ -358,20 +358,46 @@ pub fn dump_slice(data: &[u8], mut count: usize) { } } +pub fn dump_memory(bus: &mut Bus, clock: Instant, addr: Address, count: Address) +where + Bus: BusAccess, + Address: From + Into + Copy, + Instant: Copy, +{ + let mut addr = addr.into(); + let mut count = count.into(); + while count > 0 { + let mut line = format!("{:#010x}: ", addr); + + let to = if count < 16 { count / 2 } else { 8 }; + for _ in 0..to { + let word = bus.read_beu16(clock, Address::from(addr)); + if word.is_err() { + println!("{}", line); + return; + } + write!(line, "{:#06x} ", word.unwrap()).unwrap(); + addr += 2; + count -= 2; + } + println!("{}", line); + } +} + use emulator_hal::bus::{self, BusAccess}; impl bus::Error for Error {} -impl BusAccess for BusPort { +impl BusAccess for &mut dyn Addressable { type Error = Error; fn read(&mut self, now: Instant, addr: Address, data: &mut [u8]) -> Result { - ::read(self, now, addr, data)?; + (*self).read(now, addr, data)?; Ok(data.len()) } fn write(&mut self, now: Instant, addr: Address, data: &[u8]) -> Result { - ::write(self, now, addr, data)?; + (*self).write(now, addr, data)?; Ok(data.len()) } } diff --git a/emulator/cpus/m68k/Cargo.toml b/emulator/cpus/m68k/Cargo.toml index 6124799..12bcfe0 100644 --- a/emulator/cpus/m68k/Cargo.toml +++ b/emulator/cpus/m68k/Cargo.toml @@ -7,6 +7,10 @@ edition = "2021" log = "0.4" thiserror = "1.0" femtos = "0.1" -moa-core = { path = "../../core" } moa-parsing = { path = "../../libraries/parsing" } emulator-hal = { path = "../../libraries/emulator-hal/emulator-hal" } + +moa-core = { path = "../../core", optional = true } + +[features] +moa = [] diff --git a/emulator/cpus/m68k/src/assembler.rs b/emulator/cpus/m68k/src/assembler.rs index 249c601..8d48a65 100644 --- a/emulator/cpus/m68k/src/assembler.rs +++ b/emulator/cpus/m68k/src/assembler.rs @@ -1,12 +1,26 @@ use std::collections::HashMap; -use moa_core::Error; -use moa_parsing::{self as parser, AssemblyLine, AssemblyOperand, AssemblyParser}; +use moa_parsing::{self as parser, AssemblyLine, AssemblyOperand, AssemblyParser, ParserError}; use super::state::M68kType; use super::instructions::Size; +#[derive(Clone, Debug)] +pub struct Error(String); + +impl Error { + pub fn new(msg: String) -> Self { + Self(msg) + } +} + +impl From for Error { + fn from(err: ParserError) -> Self { + Self(err.0) + } +} + #[repr(usize)] #[derive(Copy, Clone)] @@ -114,7 +128,7 @@ impl M68kAssembler { fn parse(&mut self, text: &str) -> Result, Error> { let mut parser = AssemblyParser::new(text); - parser.parse() + Ok(parser.parse()?) } fn apply_relocations(&mut self) -> Result<(), Error> { diff --git a/emulator/cpus/m68k/src/debugger.rs b/emulator/cpus/m68k/src/debugger.rs index ceb317b..a5ebc54 100644 --- a/emulator/cpus/m68k/src/debugger.rs +++ b/emulator/cpus/m68k/src/debugger.rs @@ -2,9 +2,7 @@ use femtos::Instant; use emulator_hal::bus::{self, BusAccess}; -use moa_core::{System, Error, Address, Addressable, Debuggable}; - -use super::state::M68k; +use super::state::{M68k, M68kError}; use super::decode::M68kDecoder; use super::execute::M68kCycleExecutor; use super::memory::M68kAddress; @@ -33,53 +31,11 @@ pub struct M68kDebugger { 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.info.chip, true, 0); - // TODO temporarily disabled - //decoder.dump_disassembly(&mut self.port, addr as u32, count as u32); - } - - fn run_command(&mut self, system: &System, args: &[&str]) -> Result { - match args[0] { - "ds" | "stack" | "dumpstack" => { - println!("Stack:"); - for addr in &self.debugger.stack_tracer.calls { - println!(" {:08x}", BusAccess::read_beu32(&mut self.port, 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, Bus> M68kCycleExecutor<'a, Bus> +impl<'a, Bus, BusError> M68kCycleExecutor<'a, Bus> where - Bus: BusAccess, + Bus: BusAccess, { - pub fn check_breakpoints(&mut self) -> Result<(), Error> { + pub fn check_breakpoints(&mut self) -> Result<(), M68kError> { for breakpoint in &self.debugger.breakpoints { if *breakpoint == self.state.pc { if self.debugger.skip_breakpoint > 0 { @@ -87,7 +43,7 @@ where return Ok(()); } else { self.debugger.skip_breakpoint = 1; - return Err(Error::breakpoint(format!("breakpoint reached: {:08x}", *breakpoint))); + return Err(M68kError::Breakpoint); } } } diff --git a/emulator/cpus/m68k/src/decode.rs b/emulator/cpus/m68k/src/decode.rs index 43e0956..8ab5930 100644 --- a/emulator/cpus/m68k/src/decode.rs +++ b/emulator/cpus/m68k/src/decode.rs @@ -1,8 +1,6 @@ use femtos::Instant; -use emulator_hal::bus::{self, BusAccess, Error as BusError}; - -use moa_core::{Error, Address, Addressable}; +use emulator_hal::bus::BusAccess; use crate::state::{M68kType, M68kError, Exceptions}; use crate::memory::{M68kBusPort, M68kAddress}; @@ -54,9 +52,9 @@ pub struct InstructionDecoding<'a, Bus> where Bus: BusAccess, { - port: &'a mut Bus, - memory: &'a mut M68kBusPort, - decoder: &'a mut M68kDecoder, + pub(crate) port: &'a mut Bus, + pub(crate) memory: &'a mut M68kBusPort, + pub(crate) decoder: &'a mut M68kDecoder, } impl M68kDecoder { @@ -109,7 +107,7 @@ impl M68kDecoder { println!("{:?}", err); match err { M68kError::Exception(ex) if ex == Exceptions::IllegalInstruction => { - println!(" at {:08x}: {:04x}", self.start, port.read_beu16(memory.current_clock, self.start as Address).unwrap()); + println!(" at {:08x}: {:04x}", self.start, port.read_beu16(memory.current_clock, self.start).unwrap()); }, _ => { }, } @@ -125,7 +123,7 @@ impl M68kDecoder { { let ins_data: Result> = (0..((self.end - self.start) / 2)).map(|offset| - Ok(format!("{:04x} ", port.read_beu16(clock, (self.start + (offset * 2)) as Address).unwrap())) + Ok(format!("{:04x} ", port.read_beu16(clock, self.start + (offset * 2)).unwrap())) ).collect(); println!("{:#010x}: {}\n\t{}\n", self.start, ins_data.unwrap(), self.instruction); } diff --git a/emulator/cpus/m68k/src/execute.rs b/emulator/cpus/m68k/src/execute.rs index 39a9355..da852cb 100644 --- a/emulator/cpus/m68k/src/execute.rs +++ b/emulator/cpus/m68k/src/execute.rs @@ -1,10 +1,8 @@ -use femtos::{Instant, Duration}; -use emulator_hal::bus::{self, BusAccess, BusAdapter}; +use femtos::Instant; +use emulator_hal::bus::BusAccess; -use moa_core::{System, Error, Address, Steppable, Interruptable, Addressable, Debuggable, Transmutable, BusPort}; - -use crate::state::{M68k, M68kType, M68kError, M68kState, ClockCycles, Status, Flags, Exceptions, InterruptPriority}; +use crate::state::{M68k, M68kType, M68kError, M68kState, Status, Flags, Exceptions, InterruptPriority}; use crate::memory::{MemType, MemAccess, M68kBusPort, M68kAddress}; use crate::decode::M68kDecoder; use crate::debugger::M68kDebugger; @@ -37,7 +35,6 @@ pub enum Used { #[derive(Clone, Debug)] pub struct M68kCycle { - pub decoder: M68kDecoder, pub timing: M68kInstructionTiming, pub memory: M68kBusPort, @@ -50,7 +47,7 @@ impl M68kCycle { Self { decoder: M68kDecoder::new(cputype, true, 0), timing: M68kInstructionTiming::new(cputype, data_width), - memory: M68kBusPort::new(Instant::START), + memory: M68kBusPort::default(), current_clock: Instant::START, } } @@ -61,13 +58,16 @@ impl M68kCycle { Self { decoder: M68kDecoder::new(cpu.info.chip, is_supervisor, cpu.state.pc), timing: M68kInstructionTiming::new(cpu.info.chip, cpu.info.data_width as u8), - memory: M68kBusPort::new(clock), + memory: M68kBusPort::from_info(&cpu.info, clock), current_clock: clock, } } #[inline] - pub fn begin<'a>(mut self, cpu: &'a mut M68k) -> M68kCycleExecutor<'a, bus::BusAdapter> { + pub fn begin<'a, Bus>(mut self, cpu: &'a mut M68k, bus: Bus) -> M68kCycleExecutor<'a, Bus> + where + Bus: BusAccess, + { cpu.stats.cycle_number += 1; if cpu.stats.cycle_number > cpu.stats.last_update { cpu.stats.last_update = cpu.stats.last_update + 1_000_000; @@ -76,25 +76,15 @@ impl M68kCycle { cpu.stats.last_time = now; } - let adapter = bus::BusAdapter::new( - &mut cpu.port, - translate_address, - |err| err, - ); - M68kCycleExecutor { state: &mut cpu.state, - port: adapter, + port: bus, debugger: &mut cpu.debugger, cycle: self, } } } -fn translate_address(addr_in: M68kAddress) -> u64 { - addr_in as u64 -} - pub struct M68kCycleExecutor<'a, Bus> where Bus: BusAccess, @@ -109,117 +99,23 @@ impl<'a, Bus> M68kCycleExecutor<'a, Bus> where Bus: BusAccess, { - #[inline] - pub fn dump_state(&mut self) { - println!("Status: {:?}", self.state.status); - println!("PC: {:#010x}", self.state.pc); - println!("SR: {:#06x}", self.state.sr); - for i in 0..7 { - println!("D{}: {:#010x} A{}: {:#010x}", i, self.state.d_reg[i as usize], i, self.state.a_reg[i as usize]); - } - println!("D7: {:#010x} USP: {:#010x}", self.state.d_reg[7], self.state.usp); - println!(" SSP: {:#010x}", self.state.ssp); - - println!("Current Instruction: {:#010x} {:?}", self.cycle.decoder.start, self.cycle.decoder.instruction); - println!(); - self.cycle.memory.dump_memory(&mut self.port, self.state.ssp, 0x40); - println!(); - } - pub fn end(self) -> M68kCycle { self.cycle } } -impl Steppable for M68k { - fn step(&mut self, system: &System) -> Result { - let cycle = M68kCycle::new(self, system.clock); - let mut executor = cycle.begin(self); - let clocks = executor.step(system)?; - self.cycle = Some(executor.end()); - Ok(self.info.frequency.period_duration() * clocks as u64) - } - - fn on_error(&mut self, _system: &System) { - // TODO the cycle data in dropped by this point - //self.dump_state(); - } -} - -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 From> for Error { - fn from(err: M68kError) -> 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 From for M68kError { - 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<'a, Bus> M68kCycleExecutor<'a, Bus> where Bus: BusAccess, { #[inline] - pub fn step(&mut self, system: &System) -> Result> { - let result = self.step_one(system); - self.process_error(result, 4) - } - - #[inline] - pub fn process_error(&mut self, result: Result>, ok: T) -> Result> { - match result { - Ok(value) => Ok(value), - Err(M68kError::Exception(ex)) => { - self.exception(ex as u8, false)?; - Ok(ok) - }, - Err(M68kError::Interrupt(ex)) => { - self.exception(ex as u8, false)?; - Ok(ok) - }, - Err(err) => Err(err), - } - } - - #[inline] - pub fn step_one(&mut self, system: &System) -> Result> { + pub fn step(&mut self) -> Result<(), M68kError> { match self.state.status { Status::Init => self.reset_cpu(), Status::Stopped => Err(M68kError::Halted), - Status::Running => self.cycle_one(system), + Status::Running => self.cycle_one(), }?; - Ok(self.cycle.timing.calculate_clocks()) + Ok(()) } #[inline] @@ -232,15 +128,18 @@ where } #[inline] - pub fn cycle_one(&mut self, system: &System) -> Result<(), M68kError> { + pub fn cycle_one(&mut self) -> Result<(), M68kError> { self.check_breakpoints()?; - self.decode_and_execute()?; + let result = self.decode_and_execute(); + self.process_error(result)?; - self.check_pending_interrupts(system)?; + // TODO this is called by the step function directly, but should be integrated better + //self.check_pending_interrupts(system)?; Ok(()) } + /* #[inline] pub fn check_pending_interrupts(&mut self, system: &System) -> Result<(), M68kError> { // TODO this could move somewhere else @@ -270,11 +169,15 @@ where Ok(()) } + */ - /* #[inline] - pub fn check_pending_interrupts2(&mut self, interrupt: Option<(InterruptPriority, u8)>) -> Result { - self.state.pending_ipl = interrupt.unwrap_or(InterruptPriority::NoInterrupt); + pub fn check_pending_interrupts(&mut self, interrupt: (bool, u8, u8)) -> Result<(InterruptPriority, Option), M68kError> { + let ack_num; + (self.state.pending_ipl, ack_num) = match interrupt { + (true, priority, ack) => (InterruptPriority::from_u8(priority), ack), + (false, _, ack) => (InterruptPriority::NoInterrupt, ack), + }; let current_ipl = self.state.current_ipl as u8; let pending_ipl = self.state.pending_ipl as u8; @@ -283,12 +186,12 @@ where let priority_mask = ((self.state.sr & Flags::IntMask as u16) >> 8) as u8; if (pending_ipl > priority_mask || pending_ipl == 7) && pending_ipl >= current_ipl { - log::debug!("{} interrupt: {} @ {} ns", DEV_NAME, pending_ipl, system.clock.as_duration().as_nanos()); + //log::debug!("{} interrupt: {} @ {} ns", DEV_NAME, pending_ipl, system.clock.as_duration().as_nanos()); self.state.current_ipl = self.state.pending_ipl; - let acknowledge = self.state.current_ipl; - let ack_num = system.get_interrupt_controller().acknowledge(self.state.current_ipl as u8)?; + //let acknowledge = self.state.current_ipl; + //let ack_num = system.get_interrupt_controller().acknowledge(self.state.current_ipl as u8)?; self.exception(ack_num, true)?; - return Ok(()); + return Ok((self.state.current_ipl, Some(ack_num))); } } @@ -296,9 +199,8 @@ where self.state.current_ipl = self.state.pending_ipl; } - Ok(()) + Ok((self.state.current_ipl, None)) } - */ pub fn exception(&mut self, number: u8, is_interrupt: bool) -> Result<(), M68kError> { log::debug!("{}: raising exception {}", DEV_NAME, number); @@ -339,7 +241,7 @@ where self.push_word((ins_word & 0xFFF0) | extra_code)?; let vector = self.state.vbr + offset as u32; - let addr = self.get_address_sized(vector as Address, Size::Long)?; + let addr = self.get_address_sized(vector, Size::Long)?; self.set_pc(addr)?; Ok(()) @@ -364,12 +266,28 @@ where self.push_word(sr)?; let vector = self.state.vbr + offset as u32; - let addr = self.get_address_sized(vector as Address, Size::Long)?; + let addr = self.get_address_sized(vector, Size::Long)?; self.set_pc(addr)?; Ok(()) } + #[inline] + pub fn process_error(&mut self, result: Result<(), M68kError>) -> Result<(), M68kError> { + match result { + Ok(value) => Ok(value), + Err(M68kError::Exception(ex)) => { + self.exception(ex as u8, false)?; + Ok(()) + }, + Err(M68kError::Interrupt(ex)) => { + self.exception(ex as u8, false)?; + Ok(()) + }, + Err(err) => Err(err), + } + } + #[inline] pub fn decode_and_execute(&mut self) -> Result<(), M68kError> { self.decode_next()?; @@ -967,7 +885,7 @@ where *self.get_stack_pointer_mut() -= 4; let sp = *self.get_stack_pointer_mut(); let value = *self.get_a_reg_mut(reg); - self.set_address_sized(sp as Address, value, Size::Long)?; + self.set_address_sized(sp, value, Size::Long)?; *self.get_a_reg_mut(reg) = sp; *self.get_stack_pointer_mut() = (sp as i32).wrapping_add(offset) as u32; Ok(()) @@ -1109,14 +1027,14 @@ where fn move_memory_to_registers(&mut self, mut addr: u32, size: Size, mut mask: u16) -> Result> { for i in 0..8 { if (mask & 0x01) != 0 { - self.state.d_reg[i] = sign_extend_to_long(self.get_address_sized(addr as Address, size)?, size) as u32; + self.state.d_reg[i] = sign_extend_to_long(self.get_address_sized(addr, size)?, size) as u32; (addr, _) = overflowing_add_sized(addr, size.in_bytes(), Size::Long); } mask >>= 1; } for i in 0..8 { if (mask & 0x01) != 0 { - *self.get_a_reg_mut(i) = sign_extend_to_long(self.get_address_sized(addr as Address, size)?, size) as u32; + *self.get_a_reg_mut(i) = sign_extend_to_long(self.get_address_sized(addr, size)?, size) as u32; (addr, _) = overflowing_add_sized(addr, size.in_bytes(), Size::Long); } mask >>= 1; @@ -1127,7 +1045,7 @@ where fn move_registers_to_memory(&mut self, mut addr: u32, size: Size, mut mask: u16) -> Result> { for i in 0..8 { if (mask & 0x01) != 0 { - self.set_address_sized(addr as Address, self.state.d_reg[i], size)?; + self.set_address_sized(addr, self.state.d_reg[i], size)?; addr += size.in_bytes(); } mask >>= 1; @@ -1135,7 +1053,7 @@ where for i in 0..8 { if (mask & 0x01) != 0 { let value = *self.get_a_reg_mut(i); - self.set_address_sized(addr as Address, value, size)?; + self.set_address_sized(addr, value, size)?; addr += size.in_bytes(); } mask >>= 1; @@ -1148,14 +1066,14 @@ where if (mask & 0x01) != 0 { let value = *self.get_a_reg_mut(i); addr -= size.in_bytes(); - self.set_address_sized(addr as Address, value, size)?; + self.set_address_sized(addr, value, size)?; } mask >>= 1; } for i in (0..8).rev() { if (mask & 0x01) != 0 { addr -= size.in_bytes(); - self.set_address_sized(addr as Address, self.state.d_reg[i], size)?; + self.set_address_sized(addr, self.state.d_reg[i], size)?; } mask >>= 1; } @@ -1166,7 +1084,7 @@ where match dir { Direction::ToTarget => { let mut shift = (size.in_bits() as i32) - 8; - let mut addr = (*self.get_a_reg_mut(areg)).wrapping_add_signed(offset as i32) as Address; + let mut addr = (*self.get_a_reg_mut(areg)).wrapping_add_signed(offset as i32); while shift >= 0 { let byte = self.state.d_reg[dreg as usize] >> shift; self.set_address_sized(addr, byte, Size::Byte)?; @@ -1176,7 +1094,7 @@ where }, Direction::FromTarget => { let mut shift = (size.in_bits() as i32) - 8; - let mut addr = (*self.get_a_reg_mut(areg)).wrapping_add_signed(offset as i32) as Address; + let mut addr = (*self.get_a_reg_mut(areg)).wrapping_add_signed(offset as i32); while shift >= 0 { let byte = self.get_address_sized(addr, Size::Byte)?; self.state.d_reg[dreg as usize] |= byte << shift; @@ -1551,35 +1469,35 @@ where Target::DirectAReg(reg) => Ok(get_value_sized(*self.get_a_reg_mut(reg), size)), Target::IndirectAReg(reg) => { let addr = *self.get_a_reg_mut(reg); - self.get_address_sized(addr as Address, size) + self.get_address_sized(addr, size) }, Target::IndirectARegInc(reg) => { let addr = self.post_increment_areg_target(reg, size, used); - self.get_address_sized(addr as Address, size) + self.get_address_sized(addr, size) }, Target::IndirectARegDec(reg) => { let addr = self.pre_decrement_areg_target(reg, size, Used::Once); - self.get_address_sized(addr as Address, size) + self.get_address_sized(addr, size) }, Target::IndirectRegOffset(base_reg, index_reg, displacement) => { let base_value = self.get_base_reg_value(base_reg); let index_value = self.get_index_reg_value(&index_reg); - self.get_address_sized(base_value.wrapping_add(displacement as u32).wrapping_add(index_value as u32) as Address, size) + self.get_address_sized(base_value.wrapping_add(displacement as u32).wrapping_add(index_value as u32), size) }, Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) => { let base_value = self.get_base_reg_value(base_reg); let index_value = self.get_index_reg_value(&index_reg); - let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32) as Address, Size::Long)?; - self.get_address_sized(intermediate.wrapping_add(outer_disp as u32) as Address, size) + let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32), Size::Long)?; + self.get_address_sized(intermediate.wrapping_add(outer_disp as u32), size) }, Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => { let base_value = self.get_base_reg_value(base_reg); let index_value = self.get_index_reg_value(&index_reg); - let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32) as Address, Size::Long)?; - self.get_address_sized(intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32) as Address, size) + let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32), Size::Long)?; + self.get_address_sized(intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32), size) }, Target::IndirectMemory(addr, _) => { - self.get_address_sized(addr as Address, size) + self.get_address_sized(addr, size) }, } } @@ -1594,35 +1512,35 @@ where }, Target::IndirectAReg(reg) => { let addr = *self.get_a_reg_mut(reg); - self.set_address_sized(addr as Address, value, size)?; + self.set_address_sized(addr, value, size)?; }, Target::IndirectARegInc(reg) => { let addr = self.post_increment_areg_target(reg, size, Used::Once); - self.set_address_sized(addr as Address, value, size)?; + self.set_address_sized(addr, value, size)?; }, Target::IndirectARegDec(reg) => { let addr = self.pre_decrement_areg_target(reg, size, used); - self.set_address_sized(addr as Address, value, size)?; + self.set_address_sized(addr, value, size)?; }, Target::IndirectRegOffset(base_reg, index_reg, displacement) => { let base_value = self.get_base_reg_value(base_reg); let index_value = self.get_index_reg_value(&index_reg); - self.set_address_sized(base_value.wrapping_add(displacement as u32).wrapping_add(index_value as u32) as Address, value, size)?; + self.set_address_sized(base_value.wrapping_add(displacement as u32).wrapping_add(index_value as u32), value, size)?; }, Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) => { let base_value = self.get_base_reg_value(base_reg); let index_value = self.get_index_reg_value(&index_reg); - let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32) as Address, Size::Long)?; - self.set_address_sized(intermediate.wrapping_add(outer_disp as u32) as Address, value, size)?; + let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32), Size::Long)?; + self.set_address_sized(intermediate.wrapping_add(outer_disp as u32), value, size)?; }, Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => { let base_value = self.get_base_reg_value(base_reg); let index_value = self.get_index_reg_value(&index_reg); - let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32) as Address, Size::Long)?; - self.set_address_sized(intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32) as Address, value, size)?; + let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32), Size::Long)?; + self.set_address_sized(intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32), value, size)?; }, Target::IndirectMemory(addr, _) => { - self.set_address_sized(addr as Address, value, size)?; + self.set_address_sized(addr, value, size)?; }, Target::Immediate(_) => return Err(M68kError::InvalidTarget(target)), } @@ -1640,13 +1558,13 @@ where Target::IndirectMemoryPreindexed(base_reg, index_reg, base_disp, outer_disp) => { let base_value = self.get_base_reg_value(base_reg); let index_value = self.get_index_reg_value(&index_reg); - let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32) as Address, Size::Long)?; + let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32).wrapping_add(index_value as u32), Size::Long)?; intermediate.wrapping_add(outer_disp as u32) }, Target::IndirectMemoryPostindexed(base_reg, index_reg, base_disp, outer_disp) => { let base_value = self.get_base_reg_value(base_reg); let index_value = self.get_index_reg_value(&index_reg); - let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32) as Address, Size::Long)?; + let intermediate = self.get_address_sized(base_value.wrapping_add(base_disp as u32), Size::Long)?; intermediate.wrapping_add(index_value as u32).wrapping_add(outer_disp as u32) }, Target::IndirectMemory(addr, _) => { @@ -1684,44 +1602,44 @@ where *reg_addr } - fn get_address_sized(&mut self, addr: Address, size: Size) -> Result> { + fn get_address_sized(&mut self, addr: M68kAddress, size: Size) -> Result> { let is_supervisor = self.is_supervisor(); self.cycle.memory.read_data_sized(&mut self.port, is_supervisor, addr, size) } - fn set_address_sized(&mut self, addr: Address, value: u32, size: Size) -> Result<(), M68kError> { + fn set_address_sized(&mut self, addr: M68kAddress, value: u32, size: Size) -> Result<(), M68kError> { let is_supervisor = self.is_supervisor(); - self.cycle.memory.write_data_sized(&mut self.port, is_supervisor, addr, value, size) + self.cycle.memory.write_data_sized(&mut self.port, is_supervisor, addr, size, value) } fn push_word(&mut self, value: u16) -> Result<(), M68kError> { + let is_supervisor = self.is_supervisor(); *self.get_stack_pointer_mut() -= 2; let addr = *self.get_stack_pointer_mut(); - self.cycle.memory.start_request(self.is_supervisor(), addr, Size::Word, MemAccess::Write, MemType::Data, false)?; - self.port.write_beu16(self.cycle.current_clock, addr as Address, value).map_err(|err| M68kError::BusError(err))?; + self.cycle.memory.write_data_sized(&mut self.port, is_supervisor, addr, Size::Word, value as u32)?; Ok(()) } fn pop_word(&mut self) -> Result> { + let is_supervisor = self.is_supervisor(); let addr = *self.get_stack_pointer_mut(); - self.cycle.memory.start_request(self.is_supervisor(), addr, Size::Word, MemAccess::Read, MemType::Data, false)?; - let value = self.port.read_beu16(self.cycle.current_clock, addr as Address).map_err(|err| M68kError::BusError(err))?; + let value = self.cycle.memory.read_data_sized(&mut self.port, is_supervisor, addr, Size::Word)?; *self.get_stack_pointer_mut() += 2; - Ok(value) + Ok(value as u16) } fn push_long(&mut self, value: u32) -> Result<(), M68kError> { + let is_supervisor = self.is_supervisor(); *self.get_stack_pointer_mut() -= 4; let addr = *self.get_stack_pointer_mut(); - self.cycle.memory.start_request(self.is_supervisor(), addr, Size::Long, MemAccess::Write, MemType::Data, false)?; - self.port.write_beu32(self.cycle.current_clock, addr as Address, value).map_err(|err| M68kError::BusError(err))?; + self.cycle.memory.write_data_sized(&mut self.port, is_supervisor, addr, Size::Long, value)?; Ok(()) } fn pop_long(&mut self) -> Result> { + let is_supervisor = self.is_supervisor(); let addr = *self.get_stack_pointer_mut(); - self.cycle.memory.start_request(self.is_supervisor(), addr, Size::Long, MemAccess::Read, MemType::Data, false)?; - let value = self.port.read_beu32(self.cycle.current_clock, addr as Address).map_err(|err| M68kError::BusError(err))?; + let value = self.cycle.memory.read_data_sized(&mut self.port, is_supervisor, addr, Size::Long)?; *self.get_stack_pointer_mut() += 4; Ok(value) } diff --git a/emulator/cpus/m68k/src/lib.rs b/emulator/cpus/m68k/src/lib.rs index c70c624..dad8dfb 100644 --- a/emulator/cpus/m68k/src/lib.rs +++ b/emulator/cpus/m68k/src/lib.rs @@ -9,5 +9,8 @@ pub mod memory; pub mod timing; pub mod tests; +#[cfg(feature = "moa")] +pub mod moa; + pub use self::state::{M68k, M68kType, M68kError}; diff --git a/emulator/cpus/m68k/src/memory.rs b/emulator/cpus/m68k/src/memory.rs index a58b09d..d9783c2 100644 --- a/emulator/cpus/m68k/src/memory.rs +++ b/emulator/cpus/m68k/src/memory.rs @@ -1,10 +1,10 @@ +use core::cmp; +use core::fmt::Write; use femtos::Instant; -use emulator_hal::bus::{BusAccess}; +use emulator_hal::bus::BusAccess; -use moa_core::{Error, Address, Addressable}; - -use crate::state::{M68k, M68kError, Exceptions}; +use crate::state::{M68k, M68kError, CpuInfo, Exceptions}; use crate::instructions::Size; #[repr(u8)] @@ -102,7 +102,8 @@ impl MemoryRequest { } //pub type M68kAddress = (FunctionCode, u32); -pub type M68kAddress = u64; +pub type M68kAddress = u32; +pub type M68kAddressSpace = (FunctionCode, u32); #[derive(Clone, Debug)] pub struct InstructionRequest { @@ -113,6 +114,8 @@ pub struct InstructionRequest { #[derive(Clone, Debug)] pub struct M68kBusPort { pub request: MemoryRequest, + pub data_bytewidth: usize, + pub address_mask: u32, pub cycle_start_clock: Instant, pub current_clock: Instant, } @@ -126,6 +129,8 @@ impl Default for M68kBusPort { fn default() -> Self { Self { request: Default::default(), + data_bytewidth: 32 / 8, + address_mask: 0xFFFF_FFFF, cycle_start_clock: Instant::START, current_clock: Instant::START, } @@ -133,36 +138,82 @@ impl Default for M68kBusPort { } impl M68kBusPort { - pub fn new(clock: Instant) -> Self { + pub fn from_info(info: &CpuInfo, clock: Instant) -> Self { Self { request: Default::default(), + data_bytewidth: info.data_width as usize / 8, + address_mask: 1_u32.wrapping_shl(info.address_width as u32).wrapping_sub(1), cycle_start_clock: clock, current_clock: clock, } } - pub(crate) fn read_data_sized(&mut self, port: &mut Bus, is_supervisor: bool, addr: Address, size: Size) -> Result> + fn read(&mut self, bus: &mut Bus, clock: Instant, addr: M68kAddress, data: &mut [u8]) -> Result<(), M68kError> + where + Bus: BusAccess, + { + let addr = addr & self.address_mask; + for i in (0..data.len()).step_by(self.data_bytewidth as usize) { + let addr_index = (addr + i as M68kAddress) & self.address_mask; + let end = cmp::min(i + self.data_bytewidth as usize, data.len()); + bus.read(clock, addr_index, &mut data[i..end]) + .map_err(|err| M68kError::BusError(err))?; + } + Ok(()) + } + + fn write(&mut self, bus: &mut Bus, clock: Instant, addr: M68kAddress, data: &[u8]) -> Result<(), M68kError> + where + Bus: BusAccess, + { + let addr = addr & self.address_mask; + for i in (0..data.len()).step_by(self.data_bytewidth as usize) { + let addr_index = (addr + i as M68kAddress) & self.address_mask; + let end = cmp::min(i + self.data_bytewidth as usize, data.len()); + bus.write(clock, addr_index, &data[i..end]) + .map_err(|err| M68kError::BusError(err))?; + } + Ok(()) + } + + fn read_sized(&mut self, bus: &mut Bus, addr: M68kAddress, size: Size) -> Result> + where + Bus: BusAccess, + { + let mut data = [0; 4]; + match size { + Size::Byte => self.read(bus, self.current_clock, addr, &mut data[3..4]), + Size::Word => self.read(bus, self.current_clock, addr, &mut data[2..4]), + Size::Long => self.read(bus, self.current_clock, addr, &mut data[0..4]), + }.map(|_| u32::from_be_bytes(data)) + } + + fn write_sized(&mut self, bus: &mut Bus, addr: M68kAddress, size: Size, value: u32) -> Result<(), M68kError> + where + Bus: BusAccess, + { + let data = value.to_be_bytes(); + match size { + Size::Byte => self.write(bus, self.current_clock, addr, &data[3..4]), + Size::Word => self.write(bus, self.current_clock, addr, &data[2..4]), + Size::Long => self.write(bus, self.current_clock, addr, &data[0..4]), + } + } + + pub(crate) fn read_data_sized(&mut self, port: &mut Bus, is_supervisor: bool, addr: M68kAddress, size: Size) -> Result> where Bus: BusAccess, { self.start_request(is_supervisor, addr as u32, size, MemAccess::Read, MemType::Data, false)?; - Ok(match size { - Size::Byte => port.read_u8(self.current_clock, addr).map(|value| value as u32), - Size::Word => port.read_beu16(self.current_clock, addr).map(|value| value as u32), - Size::Long => port.read_beu32(self.current_clock, addr), - }.map_err(|err| M68kError::BusError(err))?) + self.read_sized(port, addr, size) } - pub(crate) fn write_data_sized(&mut self, port: &mut Bus, is_supervisor: bool, addr: Address, value: u32, size: Size) -> Result<(), M68kError> + pub(crate) fn write_data_sized(&mut self, port: &mut Bus, is_supervisor: bool, addr: M68kAddress, size: Size, value: u32) -> Result<(), M68kError> where Bus: BusAccess, { self.start_request(is_supervisor, addr as u32, size, MemAccess::Write, MemType::Data, false)?; - Ok(match size { - Size::Byte => port.write_u8(self.current_clock, addr, value as u8), - Size::Word => port.write_beu16(self.current_clock, addr, value as u16), - Size::Long => port.write_beu32(self.current_clock, addr, value), - }.map_err(|err| M68kError::BusError(err))?) + self.write_sized(port, addr, size, value) } pub(crate) fn read_instruction_word(&mut self, port: &mut Bus, is_supervisor: bool, addr: u32) -> Result> @@ -170,7 +221,7 @@ impl M68kBusPort { Bus: BusAccess, { self.request.instruction(is_supervisor, addr)?; - Ok(port.read_beu16(self.current_clock, addr as Address).map_err(|err| M68kError::BusError(err))?) + Ok(self.read_sized(port, addr, Size::Word)? as u16) } pub(crate) fn read_instruction_long(&mut self, port: &mut Bus, is_supervisor: bool, addr: u32) -> Result> @@ -178,7 +229,7 @@ impl M68kBusPort { Bus: BusAccess, { self.request.instruction(is_supervisor, addr)?; - Ok(port.read_beu32(self.current_clock, addr as Address).map_err(|err| M68kError::BusError(err))?) + self.read_sized(port, addr, Size::Long) } pub(crate) fn start_request(&mut self, is_supervisor: bool, addr: u32, size: Size, access: MemAccess, mtype: MemType, i_n_bit: bool) -> Result> { @@ -197,14 +248,6 @@ impl M68kBusPort { validate_address(addr) } } - - pub(crate) fn dump_memory(&mut self, port: &mut Bus, addr: u32, length: usize) - where - Bus: BusAccess, - { - // TODO temporarily disabled - //port.dump_memory(self.current_clock, addr as Address, length as u64); - } } fn validate_address(addr: u32) -> Result> { @@ -215,22 +258,31 @@ fn validate_address(addr: u32) -> Result> { } } -/* -impl BusType for M68kBusPort { - type Instant = Instant; - type Error = Error; -} - -impl BusAccess for M68kBusPort { - fn read(&mut self, now: Self::Instant, addr: Address, data: &mut [u8]) -> Result { - self. - } - - fn write(&mut self, now: Self::Instant, addr: Address, data: &[u8]) -> Result { +pub fn dump_memory(bus: &mut Bus, clock: Instant, addr: Address, count: Address) +where + Bus: BusAccess, + Address: From + Into + Copy, + Instant: Copy, +{ + let mut addr = addr.into(); + let mut count = count.into(); + while count > 0 { + let mut line = format!("{:#010x}: ", addr); + let to = if count < 16 { count / 2 } else { 8 }; + for _ in 0..to { + let word = bus.read_beu16(clock, Address::from(addr)); + if word.is_err() { + println!("{}", line); + return; + } + write!(line, "{:#06x} ", word.unwrap()).unwrap(); + addr += 2; + count -= 2; + } + println!("{}", line); } } -*/ /* pub(crate) struct TargetAccess { diff --git a/emulator/cpus/m68k/src/moa.rs b/emulator/cpus/m68k/src/moa.rs new file mode 100644 index 0000000..7caf40b --- /dev/null +++ b/emulator/cpus/m68k/src/moa.rs @@ -0,0 +1,124 @@ + +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 { + let cycle = M68kCycle::new(self, system.clock); + + let mut bus = system.bus.borrow_mut(); + let mut adapter: bus::BusAdapter = 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 From for M68kError { + 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 From> for Error { + fn from(err: M68kError) -> 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.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.info.chip, true, 0); + //decoder.dump_disassembly(&mut self.port, self.cycle.memory, addr as u32, count as u32); + } + + fn run_command(&mut self, system: &System, args: &[&str]) -> Result { + 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) + } +} + diff --git a/emulator/cpus/m68k/src/state.rs b/emulator/cpus/m68k/src/state.rs index 4c07f99..91de783 100644 --- a/emulator/cpus/m68k/src/state.rs +++ b/emulator/cpus/m68k/src/state.rs @@ -1,13 +1,8 @@ -use std::rc::Rc; -use std::cell::RefCell; -use std::fmt::Display; -use femtos::{Instant, Frequency}; - -use moa_core::{Address, Bus, BusPort}; +use core::fmt::{self, Write}; +use femtos::{Duration, Frequency}; use crate::debugger::M68kDebugger; -use crate::memory::M68kBusPort; use crate::instructions::Target; use crate::execute::M68kCycle; @@ -82,7 +77,7 @@ impl From for CoreType { } impl CpuInfo { - fn from(cputype: M68kType, frequency: Frequency) -> Self { + pub fn from_type(cputype: M68kType, frequency: Frequency) -> Self { match cputype { M68kType::MC68008 => Self { chip: cputype, @@ -218,7 +213,6 @@ pub struct M68k { pub info: CpuInfo, pub state: M68kState, pub debugger: M68kDebugger, - pub port: BusPort, pub stats: M68kStatistics, pub cycle: Option, } @@ -242,21 +236,50 @@ impl Default for M68kState { } } +impl M68kState { + pub fn dump_state(&mut self, writer: &mut W) -> Result<(), fmt::Error> { + writeln!(writer, "Status: {:?}", self.status)?; + writeln!(writer, "PC: {:#010x}", self.pc)?; + writeln!(writer, "SR: {:#06x}", self.sr)?; + for i in 0..7 { + writeln!(writer, "D{}: {:#010x} A{}: {:#010x}", i, self.d_reg[i as usize], i, self.a_reg[i as usize])?; + } + writeln!(writer, "D7: {:#010x} USP: {:#010x}", self.d_reg[7], self.usp)?; + writeln!(writer, " SSP: {:#010x}", self.ssp)?; + Ok(()) + } +} + impl M68k { - pub fn new(info: CpuInfo, port: BusPort) -> M68k { + pub fn new(info: CpuInfo) -> Self { M68k { info, state: M68kState::default(), debugger: M68kDebugger::default(), - port, stats: Default::default(), cycle: None, } } - pub fn from_type(cputype: M68kType, frequency: Frequency, bus: Rc>, addr_offset: Address) -> Self { - let info = CpuInfo::from(cputype, frequency); - Self::new(info, BusPort::new(addr_offset, info.address_width as u8, info.data_width as u8, bus)) + pub fn from_type(cputype: M68kType, freq: Frequency) -> Self { + Self::new(CpuInfo::from_type(cputype, freq)) + } + + pub fn dump_state(&mut self, writer: &mut W) { + self.state.dump_state(writer); + + if let Some(cycle) = self.cycle.as_ref() { + println!("Current Instruction: {:#010x} {:?}", cycle.decoder.start, cycle.decoder.instruction); + println!(); + } + //memory::dump_memory(&mut self.port, self.cycle.current_clock, self.state.ssp, 0x40); + println!(); + } + + #[inline] + pub fn last_cycle_duration(&self) -> Duration { + let clocks = self.cycle.as_ref().map(|cycle| cycle.timing.calculate_clocks()).unwrap_or(4); + self.info.frequency.period_duration() * clocks as u64 } } diff --git a/emulator/cpus/m68k/src/tests.rs b/emulator/cpus/m68k/src/tests.rs index 01b6a72..fc26353 100644 --- a/emulator/cpus/m68k/src/tests.rs +++ b/emulator/cpus/m68k/src/tests.rs @@ -4,28 +4,36 @@ mod decode_unit_tests { use std::rc::Rc; use std::cell::RefCell; use femtos::Instant; + use emulator_hal::bus::{BusAccess, BusAdapter}; - use moa_core::{Bus, BusPort, Address, Addressable, MemoryBlock, Device}; + use moa_core::{Bus, BusPort, Address, Addressable, MemoryBlock, Device, Error}; use crate::M68kType; use crate::instructions::{Target, Size, XRegister, BaseRegister, IndexRegister}; - use crate::decode::M68kDecoder; + use crate::decode::{M68kDecoder, InstructionDecoding}; use crate::memory::M68kBusPort; - const INIT_ADDR: Address = 0x00000000; + const INIT_ADDR: u32 = 0x00000000; - fn init_decode_test(cputype: M68kType) -> (M68kBusPort, M68kDecoder) { + fn init_decode_test<'a>(cputype: M68kType) -> InstructionDecoding<'a, BusAdapter> { let bus = Rc::new(RefCell::new(Bus::default())); let mem = MemoryBlock::new(vec![0; 0x0000100]); bus.borrow_mut().insert(0x00000000, Device::new(mem)); - let port = if cputype <= M68kType::MC68010 { - M68kBusPort::new(BusPort::new(0, 24, 16, bus)) - } else { - M68kBusPort::new(BusPort::new(0, 32, 32, bus)) + let mut bus = bus.borrow_mut(); + let mut adapter: BusAdapter = BusAdapter::new( + &mut *bus, + |addr| addr as u64, + |err| err.try_into().unwrap(), + ); + + let mut decoder = M68kDecoder::new(cputype, true, 0); + let mut decoding = InstructionDecoding { + port: &mut adapter, + memory: &mut M68kBusPort::default(), + decoder: &mut decoder, }; - let decoder = M68kDecoder::new(cputype, true, 0); - (port, decoder) + decoding } // @@ -34,216 +42,216 @@ mod decode_unit_tests { #[test] fn target_direct_d() { - let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); + let mut decoder = init_decode_test(M68kType::MC68010); let size = Size::Word; - let target = decoder.get_mode_as_target(&mut port, 0b000, 0b001, Some(size)).unwrap(); + let target = decoder.get_mode_as_target(0b000, 0b001, Some(size)).unwrap(); assert_eq!(target, Target::DirectDReg(1)); } #[test] fn target_direct_a() { - let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); + let mut decoder = init_decode_test(M68kType::MC68010); let size = Size::Word; - let target = decoder.get_mode_as_target(&mut port, 0b001, 0b010, Some(size)).unwrap(); + let target = decoder.get_mode_as_target(0b001, 0b010, Some(size)).unwrap(); assert_eq!(target, Target::DirectAReg(2)); } #[test] fn target_indirect_a() { - let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); + let mut decoder = init_decode_test(M68kType::MC68010); let size = Size::Long; let expected = 0x12345678; - port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); + decoder.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); - let target = decoder.get_mode_as_target(&mut port, 0b010, 0b010, Some(size)).unwrap(); + let target = decoder.get_mode_as_target(0b010, 0b010, Some(size)).unwrap(); assert_eq!(target, Target::IndirectAReg(2)); } #[test] fn target_indirect_a_inc() { - let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); + let mut decoder = init_decode_test(M68kType::MC68010); let size = Size::Long; let expected = 0x12345678; - port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); + decoder.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); - let target = decoder.get_mode_as_target(&mut port, 0b011, 0b010, Some(size)).unwrap(); + let target = decoder.get_mode_as_target(0b011, 0b010, Some(size)).unwrap(); assert_eq!(target, Target::IndirectARegInc(2)); } #[test] fn target_indirect_a_dec() { - let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); + let mut decoder = init_decode_test(M68kType::MC68010); let size = Size::Long; let expected = 0x12345678; - port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); + decoder.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); - let target = decoder.get_mode_as_target(&mut port, 0b100, 0b010, Some(size)).unwrap(); + let target = decoder.get_mode_as_target(0b100, 0b010, Some(size)).unwrap(); assert_eq!(target, Target::IndirectARegDec(2)); } #[test] fn target_indirect_a_reg_offset() { - let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); + let mut decoder = init_decode_test(M68kType::MC68010); let size = Size::Long; let offset = -8; - port.port.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap(); + decoder.port.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap(); - let target = decoder.get_mode_as_target(&mut port, 0b101, 0b100, Some(size)).unwrap(); + let target = decoder.get_mode_as_target(0b101, 0b100, Some(size)).unwrap(); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(4), None, offset)); } #[test] fn target_indirect_a_reg_brief_extension_word() { - let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); + let mut decoder = init_decode_test(M68kType::MC68010); let size = Size::Long; let offset = -8; let brief_extension = 0x3800 | (((offset as i8) as u8) as u16); - port.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - port.port.write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16).unwrap(); + decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); + decoder.port.write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16).unwrap(); - let target = decoder.get_mode_as_target(&mut port, 0b110, 0b010, Some(size)).unwrap(); + let target = decoder.get_mode_as_target(0b110, 0b010, Some(size)).unwrap(); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(2), Some(IndexRegister { xreg: XRegister::DReg(3), scale: 0, size: size }), offset)); } #[test] fn target_indirect_a_reg_full_extension_word() { - let (mut port, mut decoder) = init_decode_test(M68kType::MC68020); + let mut decoder = init_decode_test(M68kType::MC68020); let size = Size::Word; let offset = -1843235 as i32; let brief_extension = 0xF330; - port.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - port.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); + decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); + decoder.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); - let target = decoder.get_mode_as_target(&mut port, 0b110, 0b010, Some(size)).unwrap(); + let target = decoder.get_mode_as_target(0b110, 0b010, Some(size)).unwrap(); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(2), Some(IndexRegister { xreg: XRegister::AReg(7), scale: 1, size: size }), offset)); } #[test] fn target_indirect_a_reg_full_extension_word_no_base() { - let (mut port, mut decoder) = init_decode_test(M68kType::MC68020); + let mut decoder = init_decode_test(M68kType::MC68020); let size = Size::Word; let offset = -1843235 as i32; let brief_extension = 0xF3B0; - port.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - port.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); + decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); + decoder.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); - let target = decoder.get_mode_as_target(&mut port, 0b110, 0b010, Some(size)).unwrap(); + let target = decoder.get_mode_as_target(0b110, 0b010, Some(size)).unwrap(); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::None, Some(IndexRegister { xreg: XRegister::AReg(7), scale: 1, size: size }), offset)); } #[test] fn target_indirect_a_reg_full_extension_word_no_index() { - let (mut port, mut decoder) = init_decode_test(M68kType::MC68020); + let mut decoder = init_decode_test(M68kType::MC68020); let size = Size::Word; let offset = -1843235 as i32; let brief_extension = 0xF370; - port.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - port.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); + decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); + decoder.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); - let target = decoder.get_mode_as_target(&mut port, 0b110, 0b010, Some(size)).unwrap(); + let target = decoder.get_mode_as_target(0b110, 0b010, Some(size)).unwrap(); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(2), None, offset)); } #[test] fn target_indirect_pc_offset() { - let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); + let mut decoder = init_decode_test(M68kType::MC68010); let size = Size::Long; let offset = -8; - port.port.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap(); + decoder.port.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap(); - let target = decoder.get_mode_as_target(&mut port, 0b111, 0b010, Some(size)).unwrap(); + let target = decoder.get_mode_as_target(0b111, 0b010, Some(size)).unwrap(); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, None, offset)); } #[test] fn target_indirect_pc_brief_extension_word() { - let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); + let mut decoder = init_decode_test(M68kType::MC68010); let size = Size::Word; let offset = -8; let brief_extension = 0x3000 | (((offset as i8) as u8) as u16); - port.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - port.port.write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16).unwrap(); + decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); + decoder.port.write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16).unwrap(); - let target = decoder.get_mode_as_target(&mut port, 0b111, 0b011, Some(size)).unwrap(); + let target = decoder.get_mode_as_target(0b111, 0b011, Some(size)).unwrap(); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, Some(IndexRegister { xreg: XRegister::DReg(3), scale: 0, size: size }), offset)); } #[test] fn target_indirect_pc_full_extension_word() { - let (mut port, mut decoder) = init_decode_test(M68kType::MC68020); + let mut decoder = init_decode_test(M68kType::MC68020); let size = Size::Word; let offset = -1843235 as i32; let brief_extension = 0xF330; - port.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - port.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); + decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); + decoder.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); - let target = decoder.get_mode_as_target(&mut port, 0b111, 0b011, Some(size)).unwrap(); + let target = decoder.get_mode_as_target(0b111, 0b011, Some(size)).unwrap(); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, Some(IndexRegister { xreg: XRegister::AReg(7), scale: 1, size: size }), offset)); } #[test] fn target_indirect_immediate_word() { - let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); + let mut decoder = init_decode_test(M68kType::MC68010); let size = Size::Word; let expected = 0x1234; - port.port.write_beu16(Instant::START, INIT_ADDR, expected as u16).unwrap(); + decoder.port.write_beu16(Instant::START, INIT_ADDR, expected as u16).unwrap(); - let target = decoder.get_mode_as_target(&mut port, 0b111, 0b000, Some(size)).unwrap(); + let target = decoder.get_mode_as_target(0b111, 0b000, Some(size)).unwrap(); assert_eq!(target, Target::IndirectMemory(expected, Size::Word)); } #[test] fn target_indirect_immediate_long() { - let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); + let mut decoder = init_decode_test(M68kType::MC68010); let size = Size::Word; let expected = 0x12345678; - port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); + decoder.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); - let target = decoder.get_mode_as_target(&mut port, 0b111, 0b001, Some(size)).unwrap(); + let target = decoder.get_mode_as_target(0b111, 0b001, Some(size)).unwrap(); assert_eq!(target, Target::IndirectMemory(expected, Size::Long)); } #[test] fn target_immediate() { - let (mut port, mut decoder) = init_decode_test(M68kType::MC68010); + let mut decoder = init_decode_test(M68kType::MC68010); let size = Size::Word; let expected = 0x1234; - port.port.write_beu16(Instant::START, INIT_ADDR, expected as u16).unwrap(); + decoder.port.write_beu16(Instant::START, INIT_ADDR, expected as u16).unwrap(); - let target = decoder.get_mode_as_target(&mut port, 0b111, 0b100, Some(size)).unwrap(); + let target = decoder.get_mode_as_target(0b111, 0b100, Some(size)).unwrap(); assert_eq!(target, Target::Immediate(expected)); } } @@ -252,18 +260,20 @@ mod decode_unit_tests { #[cfg(test)] mod execute_unit_tests { use femtos::{Instant, Frequency}; - use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Steppable, Device}; + use emulator_hal::bus::{BusAdapter, BusAccess}; + + use moa_core::{System, MemoryBlock, Addressable, Steppable, Device, Error}; use crate::{M68k, M68kType}; use crate::execute::{Used, M68kCycle, M68kCycleExecutor}; use crate::instructions::{Instruction, Target, Size}; - const INIT_STACK: Address = 0x00002000; - const INIT_ADDR: Address = 0x00000010; + const INIT_STACK: u32 = 0x00002000; + const INIT_ADDR: u32 = 0x00000010; fn run_execute_test(cputype: M68kType, mut test_func: F) where - F: FnMut(M68kCycleExecutor), + F: FnMut(M68kCycleExecutor<&mut BusAdapter>), { let mut system = System::default(); @@ -274,10 +284,18 @@ mod execute_unit_tests { system.get_bus().write_beu32(system.clock, 0, INIT_STACK as u32).unwrap(); system.get_bus().write_beu32(system.clock, 4, INIT_ADDR as u32).unwrap(); - let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0); + let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10)); cpu.step(&system).unwrap(); let mut cycle = M68kCycle::new(&mut cpu, system.clock); - let mut executor = cycle.begin(&mut cpu); + + let mut bus = system.bus.borrow_mut(); + let mut adapter: BusAdapter = BusAdapter::new( + &mut *bus, + |addr| addr as u64, + |err| err.try_into().unwrap(), + ); + + let mut executor = cycle.begin(&mut cpu, &mut adapter); executor.cycle.decoder.init(true, executor.state.pc); assert_eq!(executor.state.pc, INIT_ADDR as u32); assert_eq!(executor.state.ssp, INIT_STACK as u32); @@ -322,7 +340,7 @@ mod execute_unit_tests { let size = Size::Long; let expected = 0x12345678; let target = Target::IndirectAReg(2); - cycle.port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); + cycle.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); cycle.state.a_reg[2] = INIT_ADDR as u32; let result = cycle.get_target_value(target, size, Used::Once).unwrap(); @@ -336,7 +354,7 @@ mod execute_unit_tests { let size = Size::Long; let expected = 0x12345678; let target = Target::IndirectARegInc(2); - cycle.port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); + cycle.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); cycle.state.a_reg[2] = INIT_ADDR as u32; let result = cycle.get_target_value(target, size, Used::Once).unwrap(); @@ -351,7 +369,7 @@ mod execute_unit_tests { let size = Size::Long; let expected = 0x12345678; let target = Target::IndirectARegDec(2); - cycle.port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); + cycle.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); cycle.state.a_reg[2] = (INIT_ADDR as u32) + 4; let result = cycle.get_target_value(target, size, Used::Once).unwrap(); @@ -374,5 +392,3 @@ mod execute_unit_tests { }); } } - - diff --git a/emulator/cpus/m68k/tests/decode_tests.rs b/emulator/cpus/m68k/tests/decode_tests.rs index 93b2d00..a5285cf 100644 --- a/emulator/cpus/m68k/tests/decode_tests.rs +++ b/emulator/cpus/m68k/tests/decode_tests.rs @@ -1,7 +1,8 @@ use femtos::{Instant, Frequency}; +use emulator_hal::bus::BusAdapter; -use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Device}; +use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Device, Error}; use moa_m68k::{M68k, M68kType}; use moa_m68k::instructions::{Instruction, Target, Size, Sign, XRegister, BaseRegister, IndexRegister, Direction}; @@ -77,12 +78,12 @@ fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, System) { // Initialize the CPU and make sure it's in the expected state let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0); //cpu.reset_cpu().unwrap(); - assert_eq!(cpu.state.pc, INIT_ADDR as u32); - assert_eq!(cpu.state.ssp, INIT_STACK as u32); + //assert_eq!(cpu.state.pc, INIT_ADDR as u32); + //assert_eq!(cpu.state.ssp, INIT_STACK as u32); let cycle = M68kCycle::new(&cpu, system.clock); - assert_eq!(cycle.decoder.start, INIT_ADDR as u32); - assert_eq!(cycle.decoder.instruction, Instruction::NOP); + //assert_eq!(cycle.decoder.start, INIT_ADDR as u32); + //assert_eq!(cycle.decoder.instruction, Instruction::NOP); (cpu, cycle, system) } @@ -97,14 +98,24 @@ fn load_memory(system: &System, data: &[u16]) { fn run_decode_test(case: &TestCase) { let (mut cpu, cycle, system) = init_decode_test(case.cpu); load_memory(&system, case.data); + + let mut bus = system.bus.borrow_mut(); + let mut adapter: BusAdapter = BusAdapter::new( + &mut *bus, + |addr| addr as u64, + |err| err.try_into().unwrap(), + ); + match &case.ins { Some(ins) => { - let mut executor = cycle.begin(&mut cpu); + let mut executor = cycle.begin(&mut cpu, &mut adapter); + executor.reset_cpu().unwrap(); executor.decode_next().unwrap(); assert_eq!(executor.cycle.decoder.instruction, ins.clone()); }, None => { - let mut executor = cycle.begin(&mut cpu); + let mut executor = cycle.begin(&mut cpu, &mut adapter); + executor.reset_cpu().unwrap(); let next = executor.decode_next(); println!("{:?}", executor.cycle.decoder.instruction); assert!(next.is_err()); diff --git a/emulator/cpus/m68k/tests/execute_tests.rs b/emulator/cpus/m68k/tests/execute_tests.rs index aa5652d..b3bdcc8 100644 --- a/emulator/cpus/m68k/tests/execute_tests.rs +++ b/emulator/cpus/m68k/tests/execute_tests.rs @@ -1,7 +1,8 @@ use femtos::{Instant, Frequency}; +use emulator_hal::bus::BusAdapter; -use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Steppable, Device}; +use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Steppable, Device, Error}; use moa_m68k::{M68k, M68kType}; use moa_m68k::state::M68kState; @@ -37,7 +38,7 @@ struct TestCase { fn run_execute_test(cputype: M68kType, mut test_func: F) where - F: FnMut(M68kCycleExecutor, System), + F: FnMut(M68kCycleExecutor<&mut BusAdapter>, &System), { let mut system = System::default(); @@ -48,17 +49,24 @@ where system.get_bus().write_beu32(Instant::START, 0, INIT_STACK as u32).unwrap(); system.get_bus().write_beu32(Instant::START, 4, INIT_ADDR as u32).unwrap(); + let mut bus = system.bus.borrow_mut(); + let mut adapter: BusAdapter = BusAdapter::new( + &mut *bus, + |addr| addr as u64, + |err| err.try_into().unwrap(), + ); + let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0); cpu.step(&system).unwrap(); let cycle = M68kCycle::new(&cpu, system.clock); - let mut executor = cycle.begin(&mut cpu); + let executor = cycle.begin(&mut cpu, &mut adapter); assert_eq!(executor.state.pc, INIT_ADDR as u32); assert_eq!(executor.state.ssp, INIT_STACK as u32); assert_eq!(executor.cycle.decoder.instruction, Instruction::NOP); - test_func(executor, system) + test_func(executor, &system) } fn build_state(state: &TestState) -> M68kState { diff --git a/emulator/cpus/m68k/tests/musashi_timing_tests.rs b/emulator/cpus/m68k/tests/musashi_timing_tests.rs index c22bb9b..411fb94 100644 --- a/emulator/cpus/m68k/tests/musashi_timing_tests.rs +++ b/emulator/cpus/m68k/tests/musashi_timing_tests.rs @@ -1,5 +1,6 @@ use femtos::{Instant, Frequency}; +use emulator_hal::bus::BusAdapter; use moa_core::{System, Error, MemoryBlock, Address, Addressable, Device}; @@ -42,7 +43,15 @@ fn load_memory(system: &System, data: &[u16]) { fn run_timing_test(case: &TimingCase) -> Result<(), Error> { let (mut cpu, cycle, system) = init_decode_test(case.cpu); - let mut executor = cycle.begin(&mut cpu); + + let mut bus = system.bus.borrow_mut(); + let mut adapter: BusAdapter = BusAdapter::new( + &mut *bus, + |addr| addr as u64, + |err| err.try_into().unwrap(), + ); + + let mut executor = cycle.begin(&mut cpu, &mut adapter); let mut timing = M68kInstructionTiming::new(case.cpu, 16); load_memory(&system, case.data); @@ -50,7 +59,7 @@ fn run_timing_test(case: &TimingCase) -> Result<(), Error> { assert_eq!(executor.cycle.decoder.instruction, case.ins.clone()); timing.add_instruction(&executor.cycle.decoder.instruction); - let result = timing.calculate_clocks(false, 1); + let result = timing.calculate_clocks(); let expected = match case.cpu { M68kType::MC68000 => case.timing.0, M68kType::MC68010 => case.timing.1, diff --git a/emulator/cpus/m68k/tests/timing_tests.rs b/emulator/cpus/m68k/tests/timing_tests.rs index 489b557..09a6220 100644 --- a/emulator/cpus/m68k/tests/timing_tests.rs +++ b/emulator/cpus/m68k/tests/timing_tests.rs @@ -1,5 +1,6 @@ use femtos::{Instant, Frequency}; +use emulator_hal::bus::BusAdapter; use moa_core::{System, Error, MemoryBlock, BusPort, Address, Addressable, Device}; @@ -56,7 +57,15 @@ fn load_memory(system: &System, data: &[u16]) { fn run_timing_test(case: &TimingCase) -> Result<(), Error> { let (mut cpu, cycle, system) = init_decode_test(case.cpu); - let mut executor = cycle.begin(&mut cpu); + + let mut bus = system.bus.borrow_mut(); + let mut adapter: BusAdapter = BusAdapter::new( + &mut *bus, + |addr| addr as u64, + |err| err.try_into().unwrap(), + ); + + let mut executor = cycle.begin(&mut cpu, &mut adapter); let mut timing = M68kInstructionTiming::new(case.cpu, 16); load_memory(&system, case.data); @@ -64,7 +73,7 @@ fn run_timing_test(case: &TimingCase) -> Result<(), Error> { assert_eq!(executor.cycle.decoder.instruction, case.ins.clone()); timing.add_instruction(&executor.cycle.decoder.instruction); - let result = timing.calculate_clocks(false, 1); + let result = timing.calculate_clocks(); let expected = match case.cpu { M68kType::MC68000 => case.timing.0, M68kType::MC68010 => case.timing.1, diff --git a/emulator/frontends/common/src/tty.rs b/emulator/frontends/common/src/tty.rs index 574df95..8422103 100644 --- a/emulator/frontends/common/src/tty.rs +++ b/emulator/frontends/common/src/tty.rs @@ -9,10 +9,15 @@ use nix::fcntl::OFlag; use nix::pty::{self, PtyMaster}; use nix::fcntl::{fcntl, FcntlArg}; -use moa_core::Error; -use moa_core::host::Tty; +use moa_host::Tty; +#[derive(Debug, PartialEq, Eq)] +pub enum SimplePtyError { + Open, + PtsName, +} + pub struct SimplePty { pub name: String, input: mpsc::Receiver, @@ -28,14 +33,14 @@ impl SimplePty { } } - pub fn open() -> Result { + pub fn open() -> Result { let pty = pty::posix_openpt(OFlag::O_RDWR).and_then(|pty| { pty::grantpt(&pty)?; pty::unlockpt(&pty)?; Ok(pty) - }).map_err(|_| Error::new("Error opening new pseudoterminal"))?; + }).map_err(|_| SimplePtyError::Open)?; - let name = unsafe { pty::ptsname(&pty).map_err(|_| Error::new("Unable to get pty name"))? }; + let name = unsafe { pty::ptsname(&pty).map_err(|_| SimplePtyError::PtsName)? }; let (input_tx, input_rx) = mpsc::channel(); let (output_tx, output_rx) = mpsc::channel(); let shared = SimplePty::new(name.clone(), input_rx, output_tx); diff --git a/emulator/frontends/console/Cargo.toml b/emulator/frontends/console/Cargo.toml index 3729ac3..c807843 100644 --- a/emulator/frontends/console/Cargo.toml +++ b/emulator/frontends/console/Cargo.toml @@ -11,10 +11,12 @@ simple_logger = "^2" femtos = "0.1" moa-core = { path = "../../core" } +moa-host = { path = "../../libraries/host" } moa-common = { path = "../common", features = ["tty"] } +moa-debugger = { path = "../../libraries/debugger" } moa-systems-genesis = { path = "../../systems/genesis" } moa-systems-computie = { path = "../../systems/computie" } -moa-m68k = { path = "../../cpus/m68k" } +moa-m68k = { path = "../../cpus/m68k", features = ["moa"] } moa-peripherals-generic = { path = "../../peripherals/generic" } moa-peripherals-motorola = { path = "../../peripherals/motorola" } diff --git a/emulator/frontends/console/src/lib.rs b/emulator/frontends/console/src/lib.rs index 91d89b6..bbe80a4 100644 --- a/emulator/frontends/console/src/lib.rs +++ b/emulator/frontends/console/src/lib.rs @@ -3,8 +3,9 @@ use clap::{Command, Arg, ArgAction, ArgMatches}; use std::io::{self, Write}; use femtos::Duration; -use moa_core::{Error, System, DebugControl, Debugger}; -use moa_core::host::{Host, Tty, ControllerEvent, Audio, DummyAudio, FrameReceiver, EventSender}; +use moa_core::{Error, System}; +use moa_debugger::{Debugger, DebugControl}; +use moa_host::{Host, HostError, Tty, ControllerEvent, Audio, DummyAudio, FrameReceiver, EventSender}; pub struct ConsoleFrontend; @@ -13,7 +14,7 @@ impl Host for ConsoleFrontend { fn add_pty(&self) -> Result, HostError> { use moa_common::tty::SimplePty; - Ok(Box::new(SimplePty::open()?)) + Ok(Box::new(SimplePty::open().map_err(|err| HostError::TTYNotSupported)?)) //.map_err(|err| Error::new(format!("console: error opening pty: {:?}", err)))?)) } fn add_video_source(&mut self, _receiver: FrameReceiver) -> Result<(), HostError> { diff --git a/emulator/libraries/parsing/src/lib.rs b/emulator/libraries/parsing/src/lib.rs index 698de50..49dee09 100644 --- a/emulator/libraries/parsing/src/lib.rs +++ b/emulator/libraries/parsing/src/lib.rs @@ -2,8 +2,14 @@ use std::str::Chars; use std::iter::Peekable; -use moa_core::Error; +pub struct ParserError(pub String); + +impl ParserError { + pub fn new(msg: String) -> Self { + Self(msg) + } +} #[derive(Debug)] pub enum AssemblyLine { @@ -34,7 +40,7 @@ impl<'input> AssemblyParser<'input> { } } - pub fn parse(&mut self) -> Result, Error> { + pub fn parse(&mut self) -> Result, ParserError> { let mut output = vec![]; loop { let lineno = self.lexer.get_next_lineno(); @@ -47,7 +53,7 @@ impl<'input> AssemblyParser<'input> { Ok(output) } - fn parse_line(&mut self) -> Result, Error> { + fn parse_line(&mut self) -> Result, ParserError> { let token = loop { match self.lexer.get_next() { Some(token) if token == "\n" => { }, @@ -73,7 +79,7 @@ impl<'input> AssemblyParser<'input> { } }, _ => { - return Err(Error::new(format!("parse error at line {}: expected word, found {:?}", self.lexer.lineno(), token))); + return Err(ParserError::new(format!("parse error at line {}: expected word, found {:?}", self.lexer.lineno(), token))); }, }; @@ -81,7 +87,7 @@ impl<'input> AssemblyParser<'input> { Ok(Some(result)) } - fn parse_list_of_words(&mut self) -> Result, Error> { + fn parse_list_of_words(&mut self) -> Result, ParserError> { let mut list = vec![]; // If we're already at the end of the line, then it's an empty list, so return @@ -101,7 +107,7 @@ impl<'input> AssemblyParser<'input> { } } - fn parse_list_of_operands(&mut self) -> Result, Error> { + fn parse_list_of_operands(&mut self) -> Result, ParserError> { let mut list = vec![]; // If we're already at the end of the line, then it's an empty list, so return @@ -121,7 +127,7 @@ impl<'input> AssemblyParser<'input> { } } - fn parse_operand(&mut self) -> Result { + fn parse_operand(&mut self) -> Result { let token = self.lexer.expect_next()?; match token.as_str() { "%" => { @@ -163,7 +169,7 @@ impl<'input> AssemblyParser<'input> { } } -fn parse_any_number(lineno: usize, string: &str) -> Result { +fn parse_any_number(lineno: usize, string: &str) -> Result { let (radix, numeric) = if let Some(s) = string.strip_prefix("0x") { (16, s) } else if let Some(s) = string.strip_prefix("0b") { @@ -174,7 +180,7 @@ fn parse_any_number(lineno: usize, string: &str) -> Result { (10, string) }; usize::from_str_radix(numeric, radix) - .map_err(|_| Error::new(format!("parse error at line {}: expected number after #, but found {:?}", lineno, string))) + .map_err(|_| ParserError::new(format!("parse error at line {}: expected number after #, but found {:?}", lineno, string))) } @@ -230,25 +236,25 @@ impl<'input> AssemblyLexer<'input> { self.peeked.clone() } - pub fn expect_next(&mut self) -> Result { - self.get_next().ok_or_else(|| Error::new(format!("unexpected end of input at line {}", self.lineno))) + pub fn expect_next(&mut self) -> Result { + self.get_next().ok_or_else(|| ParserError::new(format!("unexpected end of input at line {}", self.lineno))) } - pub fn expect_token(&mut self, expected: &str) -> Result<(), Error> { + pub fn expect_token(&mut self, expected: &str) -> Result<(), ParserError> { let token = self.expect_next()?; if token == expected { Ok(()) } else { - Err(Error::new(format!("parse error at line {}: expected {:?}, found {:?}", self.lineno, expected, token))) + Err(ParserError::new(format!("parse error at line {}: expected {:?}, found {:?}", self.lineno, expected, token))) } } - pub fn expect_end(&mut self) -> Result<(), Error> { + pub fn expect_end(&mut self) -> Result<(), ParserError> { let token = self.get_next(); if token.is_none() || token.as_ref().unwrap() == "\n" { Ok(()) } else { - Err(Error::new(format!("expected end of line at {}: found {:?}", self.lineno, token))) + Err(ParserError::new(format!("expected end of line at {}: found {:?}", self.lineno, token))) } } @@ -301,28 +307,28 @@ fn is_digit(ch: char) -> bool { ch.is_ascii_digit() } -pub fn expect_args(lineno: usize, args: &[AssemblyOperand], expected: usize) -> Result<(), Error> { +pub fn expect_args(lineno: usize, args: &[AssemblyOperand], expected: usize) -> Result<(), ParserError> { if args.len() == expected { Ok(()) } else { - Err(Error::new(format!("error at line {}: expected {} args, but found {}", lineno, expected, args.len()))) + Err(ParserError::new(format!("error at line {}: expected {} args, but found {}", lineno, expected, args.len()))) } } -pub fn expect_label(lineno: usize, args: &[AssemblyOperand]) -> Result { +pub fn expect_label(lineno: usize, args: &[AssemblyOperand]) -> Result { expect_args(lineno, args, 1)?; if let AssemblyOperand::Label(name) = &args[0] { Ok(name.clone()) } else { - Err(Error::new(format!("error at line {}: expected a label, but found {:?}", lineno, args))) + Err(ParserError::new(format!("error at line {}: expected a label, but found {:?}", lineno, args))) } } -pub fn expect_immediate(lineno: usize, operand: &AssemblyOperand) -> Result { +pub fn expect_immediate(lineno: usize, operand: &AssemblyOperand) -> Result { if let AssemblyOperand::Immediate(value) = operand { Ok(*value) } else { - Err(Error::new(format!("error at line {}: expected an immediate value, but found {:?}", lineno, operand))) + Err(ParserError::new(format!("error at line {}: expected an immediate value, but found {:?}", lineno, operand))) } } diff --git a/emulator/systems/computie/Cargo.toml b/emulator/systems/computie/Cargo.toml index 6de726c..aca9774 100644 --- a/emulator/systems/computie/Cargo.toml +++ b/emulator/systems/computie/Cargo.toml @@ -8,6 +8,6 @@ log = "0.4" femtos = "0.1" moa-core = { path = "../../core" } moa-host = { path = "../../libraries/host" } -moa-m68k = { path = "../../cpus/m68k" } +moa-m68k = { path = "../../cpus/m68k", features = ["moa"] } moa-peripherals-generic = { path = "../../peripherals/generic" } moa-peripherals-motorola = { path = "../../peripherals/motorola" } diff --git a/emulator/systems/computie/src/system.rs b/emulator/systems/computie/src/system.rs index 55eeb78..afadc8c 100644 --- a/emulator/systems/computie/src/system.rs +++ b/emulator/systems/computie/src/system.rs @@ -45,7 +45,7 @@ pub fn build_computie(host: &H, options: ComputieOptions) -> Result(host: &H) -> Result { system.add_addressable_device(0x00700000, Device::new(serial))?; - let cpu = M68k::from_type(M68kType::MC68030, Frequency::from_hz(10_000_000), system.bus.clone(), 0); + let cpu = M68k::from_type(M68kType::MC68030, Frequency::from_hz(10_000_000)); //cpu.enable_tracing(); //cpu.add_breakpoint(0x10781a); diff --git a/emulator/systems/genesis/Cargo.toml b/emulator/systems/genesis/Cargo.toml index 64e016c..774fe24 100644 --- a/emulator/systems/genesis/Cargo.toml +++ b/emulator/systems/genesis/Cargo.toml @@ -10,6 +10,6 @@ moa-core = { path = "../../core" } moa-signals = { path = "../../libraries/signals" } moa-host = { path = "../../libraries/host" } moa-peripherals-yamaha = { path = "../../peripherals/yamaha" } -moa-m68k = { path = "../../cpus/m68k" } +moa-m68k = { path = "../../cpus/m68k", features = ["moa"] } moa-z80 = { path = "../../cpus/z80" } diff --git a/emulator/systems/genesis/src/system.rs b/emulator/systems/genesis/src/system.rs index e0a3de9..9719d97 100644 --- a/emulator/systems/genesis/src/system.rs +++ b/emulator/systems/genesis/src/system.rs @@ -94,7 +94,7 @@ pub fn build_genesis(host: &mut H, mut options: SegaGenesisOptions) -> let vdp = Ym7101::new(host, interrupt, coproc_sn_sound)?; system.add_peripheral("vdp", 0x00c00000, Device::new(vdp))?; - let cpu = M68k::from_type(M68kType::MC68000, Frequency::from_hz(7_670_454), system.bus.clone(), 0); + let cpu = M68k::from_type(M68kType::MC68000, Frequency::from_hz(7_670_454)); system.add_interruptable_device("cpu", Device::new(cpu))?; Ok(system) diff --git a/emulator/systems/macintosh/Cargo.toml b/emulator/systems/macintosh/Cargo.toml index f063851..0120dc5 100644 --- a/emulator/systems/macintosh/Cargo.toml +++ b/emulator/systems/macintosh/Cargo.toml @@ -9,6 +9,6 @@ femtos = "0.1" moa-core = { path = "../../core" } moa-host = { path = "../../libraries/host" } moa-signals = { path = "../../libraries/signals" } -moa-m68k = { path = "../../cpus/m68k" } +moa-m68k = { path = "../../cpus/m68k", features = ["moa"] } moa-peripherals-mos = { path = "../../peripherals/mos" } moa-peripherals-zilog = { path = "../../peripherals/zilog" } diff --git a/emulator/systems/macintosh/src/system.rs b/emulator/systems/macintosh/src/system.rs index 1d74423..2ce660d 100644 --- a/emulator/systems/macintosh/src/system.rs +++ b/emulator/systems/macintosh/src/system.rs @@ -71,7 +71,7 @@ pub fn build_macintosh_512k(host: &mut H) -> Result { system.add_addressable_device(0x00000000, Device::new(mainboard))?; - let mut cpu = M68k::from_type(M68kType::MC68000, Frequency::from_hz(7_833_600), system.bus.clone(), 0); + let mut cpu = M68k::from_type(M68kType::MC68000, Frequency::from_hz(7_833_600)); //cpu.enable_tracing(); //system.enable_debugging(); diff --git a/tests/harte_tests/Cargo.toml b/tests/harte_tests/Cargo.toml index 02253f2..d7af02b 100644 --- a/tests/harte_tests/Cargo.toml +++ b/tests/harte_tests/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" femtos = "0.1" moa-core = { path = "../../emulator/core" } -moa-m68k = { path = "../../emulator/cpus/m68k" } +moa-m68k = { path = "../../emulator/cpus/m68k", features = ["moa"] } serde = "1.0" serde_json = "1.0" serde_derive = "1.0" diff --git a/tests/harte_tests/latest.txt b/tests/harte_tests/latest.txt index 293981f..3db3c97 100644 --- a/tests/harte_tests/latest.txt +++ b/tests/harte_tests/latest.txt @@ -1,4 +1,4 @@ -Last run on 2024-03-08 at commit 8b274f72ccf6f143e527cb95552f80deedc2fc64 +Last run on 2024-03-13 at commit af1c660dc0682a62c123b1d7577f2ce2b5f3d8ad ABCD.json.gz completed: 7993 passed, 72 FAILED ADD.b.json.gz completed, all passed! @@ -37,93 +37,3 @@ CMPA.l.json.gz completed, all passed! CMPA.w.json.gz completed, all passed! DBcc.json.gz completed, all passed! DIVS.json.gz completed, all passed! -DIVU.json.gz completed: 8064 passed, 1 FAILED -EOR.b.json.gz completed, all passed! -EOR.l.json.gz completed: 7519 passed, 546 FAILED -EOR.w.json.gz completed: 7525 passed, 540 FAILED -EORItoCCR.json.gz completed, all passed! -EORItoSR.json.gz completed, all passed! -EXG.json.gz completed, all passed! -EXT.l.json.gz completed, all passed! -EXT.w.json.gz completed, all passed! -JMP.json.gz completed, all passed! -JSR.json.gz completed, all passed! -LEA.json.gz completed, all passed! -LINK.json.gz completed, all passed! -LSL.b.json.gz completed, all passed! -LSL.l.json.gz completed, all passed! -LSL.w.json.gz completed: 7910 passed, 155 FAILED -LSR.b.json.gz completed, all passed! -LSR.l.json.gz completed, all passed! -LSR.w.json.gz completed: 7909 passed, 156 FAILED -MOVE.b.json.gz completed, all passed! -MOVE.l.json.gz completed: 5827 passed, 2238 FAILED -MOVE.q.json.gz completed, all passed! -MOVE.w.json.gz completed: 5855 passed, 2210 FAILED -MOVEA.l.json.gz completed, all passed! -MOVEA.w.json.gz completed, all passed! -MOVEM.l.json.gz completed: 6035 passed, 2030 FAILED -MOVEM.w.json.gz completed: 6431 passed, 1634 FAILED -MOVEP.l.json.gz completed: 4036 passed, 4029 FAILED -MOVEP.w.json.gz completed: 4046 passed, 4019 FAILED -MOVEfromSR.json.gz completed: 6896 passed, 1169 FAILED -MOVEfromUSP.json.gz completed, all passed! -MOVEtoCCR.json.gz completed, all passed! -MOVEtoSR.json.gz completed, all passed! -MOVEtoUSP.json.gz completed, all passed! -MULS.json.gz completed, all passed! -MULU.json.gz completed, all passed! -NBCD.json.gz completed: 8037 passed, 28 FAILED -NEG.b.json.gz completed, all passed! -NEG.l.json.gz completed: 7552 passed, 513 FAILED -NEG.w.json.gz completed: 7531 passed, 534 FAILED -NEGX.b.json.gz completed, all passed! -NEGX.l.json.gz completed: 7520 passed, 545 FAILED -NEGX.w.json.gz completed: 7510 passed, 555 FAILED -NOP.json.gz completed, all passed! -NOT.b.json.gz completed, all passed! -NOT.l.json.gz completed: 7512 passed, 553 FAILED -NOT.w.json.gz completed: 7530 passed, 535 FAILED -OR.b.json.gz completed, all passed! -OR.l.json.gz completed: 7756 passed, 309 FAILED -OR.w.json.gz completed: 7765 passed, 300 FAILED -ORItoCCR.json.gz completed, all passed! -ORItoSR.json.gz completed, all passed! -PEA.json.gz completed, all passed! -RESET.json.gz completed, all passed! -ROL.b.json.gz completed, all passed! -ROL.l.json.gz completed, all passed! -ROL.w.json.gz completed: 7898 passed, 167 FAILED -ROR.b.json.gz completed, all passed! -ROR.l.json.gz completed, all passed! -ROR.w.json.gz completed: 7932 passed, 133 FAILED -ROXL.b.json.gz completed: 8032 passed, 33 FAILED -ROXL.l.json.gz completed: 8029 passed, 36 FAILED -ROXL.w.json.gz completed: 7890 passed, 175 FAILED -ROXR.b.json.gz completed: 8027 passed, 38 FAILED -ROXR.l.json.gz completed: 8039 passed, 26 FAILED -ROXR.w.json.gz completed: 7880 passed, 185 FAILED -RTE.json.gz completed, all passed! -RTR.json.gz completed, all passed! -RTS.json.gz completed, all passed! -SBCD.json.gz completed: 6809 passed, 1256 FAILED -SUB.b.json.gz completed, all passed! -SUB.l.json.gz completed: 7747 passed, 318 FAILED -SUB.w.json.gz completed: 7716 passed, 349 FAILED -SUBA.l.json.gz completed, all passed! -SUBA.w.json.gz completed, all passed! -SUBX.b.json.gz completed, all passed! -SUBX.l.json.gz completed: 5481 passed, 2584 FAILED -SUBX.w.json.gz completed, all passed! -SWAP.json.gz completed, all passed! -Scc.json.gz completed, all passed! -TAS.json.gz completed, all passed! -TRAP.json.gz completed, all passed! -TRAPV.json.gz completed, all passed! -TST.b.json.gz completed, all passed! -TST.l.json.gz completed, all passed! -TST.w.json.gz completed, all passed! -UNLINK.json.gz completed, all passed! - -passed: 966037, failed: 34023, total 97% -completed in 13m 59s diff --git a/todo.txt b/todo.txt index 28439d1..f54a508 100644 --- a/todo.txt +++ b/todo.txt @@ -1,4 +1,8 @@ +* the next step is to factor all of moa_core into the moa.rs file, with BusPort being the last big piece + The functionality of BusPort should be integrated into memory.rs, to break up operations based on the cpu type + and then you won't need a value to hold on to port in a special bundle type. It can be borrowed in the step function from system.bus + * I want to push System, and BusPort into only the step function * first I need to make Decoder take &mut Addressable, and still function like it does * next I need to make Executor only access through a &mut Addressable