From 8b274f72ccf6f143e527cb95552f80deedc2fc64 Mon Sep 17 00:00:00 2001 From: transistor Date: Fri, 8 Mar 2024 19:41:36 -0800 Subject: [PATCH 1/9] Modified to use emulator-hal traits --- emulator/core/src/memory.rs | 22 +++ emulator/cpus/m68k/src/debugger.rs | 11 +- emulator/cpus/m68k/src/decode.rs | 78 ++++---- emulator/cpus/m68k/src/execute.rs | 285 ++++++++++++++++------------- emulator/cpus/m68k/src/memory.rs | 52 ++++-- emulator/cpus/m68k/src/state.rs | 5 +- emulator/cpus/m68k/src/timing.rs | 27 ++- emulator/cpus/z80/src/decode.rs | 8 +- tests/harte_tests/latest.txt | 254 ++++++++++++------------- tests/harte_tests/src/main.rs | 10 +- todo.txt | 6 + 11 files changed, 434 insertions(+), 324 deletions(-) diff --git a/emulator/core/src/memory.rs b/emulator/core/src/memory.rs index e76553f..52db709 100644 --- a/emulator/core/src/memory.rs +++ b/emulator/core/src/memory.rs @@ -358,3 +358,25 @@ pub fn dump_slice(data: &[u8], mut count: usize) { } } +use emulator_hal::bus::{self, BusAccess}; + +//impl bus::Error for Error {} + +//impl ErrorType for BusPort { +// type Error = Error; +//} + +impl BusAccess for BusPort { + type Error = Error; + + fn read(&mut self, now: Instant, addr: Address, data: &mut [u8]) -> Result { + ::read(self, now, addr, data)?; + Ok(data.len()) + } + + fn write(&mut self, now: Instant, addr: Address, data: &[u8]) -> Result { + ::write(self, now, addr, data)?; + Ok(data.len()) + } +} + diff --git a/emulator/cpus/m68k/src/debugger.rs b/emulator/cpus/m68k/src/debugger.rs index 9849c14..ceb317b 100644 --- a/emulator/cpus/m68k/src/debugger.rs +++ b/emulator/cpus/m68k/src/debugger.rs @@ -1,9 +1,13 @@ +use femtos::Instant; +use emulator_hal::bus::{self, BusAccess}; + use moa_core::{System, Error, Address, Addressable, Debuggable}; use super::state::M68k; use super::decode::M68kDecoder; use super::execute::M68kCycleExecutor; +use super::memory::M68kAddress; #[derive(Clone, Default)] pub struct StackTracer { @@ -59,7 +63,7 @@ impl Debuggable for M68k { "ds" | "stack" | "dumpstack" => { println!("Stack:"); for addr in &self.debugger.stack_tracer.calls { - println!(" {:08x}", self.port.read_beu32(system.clock, *addr as Address)?); + println!(" {:08x}", BusAccess::read_beu32(&mut self.port, system.clock, *addr as Address)?); } }, "so" | "stepout" => { @@ -71,7 +75,10 @@ impl Debuggable for M68k { } } -impl<'a> M68kCycleExecutor<'a> { +impl<'a, Bus> M68kCycleExecutor<'a, Bus> +where + Bus: BusAccess, +{ pub fn check_breakpoints(&mut self) -> Result<(), Error> { for breakpoint in &self.debugger.breakpoints { if *breakpoint == self.state.pc { diff --git a/emulator/cpus/m68k/src/decode.rs b/emulator/cpus/m68k/src/decode.rs index fc94bf2..5699240 100644 --- a/emulator/cpus/m68k/src/decode.rs +++ b/emulator/cpus/m68k/src/decode.rs @@ -1,10 +1,11 @@ use femtos::Instant; +use emulator_hal::bus::{self, BusAccess, BusError}; -use moa_core::{Address, Addressable, BusPort}; +use moa_core::{Error, Address, Addressable}; use crate::state::{M68kType, M68kError, Exceptions}; -use crate::memory::M68kBusPort; +use crate::memory::{M68kBusPort, M68kAddress}; use crate::instructions::{ Size, Sign, @@ -49,8 +50,11 @@ pub struct M68kDecoder { pub instruction: Instruction, } -pub struct InstructionDecoding<'a> { - port: &'a mut BusPort, +pub struct InstructionDecoding<'a, Bus> +where + Bus: BusAccess, +{ + port: &'a mut Bus, memory: &'a mut M68kBusPort, decoder: &'a mut M68kDecoder, } @@ -76,7 +80,10 @@ impl M68kDecoder { } #[inline] - pub fn decode_at(&mut self, port: &mut BusPort, memory: &mut M68kBusPort, is_supervisor: bool, start: u32) -> Result<(), M68kError> { + pub fn decode_at(&mut self, port: &mut Bus, memory: &mut M68kBusPort, is_supervisor: bool, start: u32) -> Result<(), M68kError> + where + Bus: BusAccess, + { self.init(is_supervisor, start); let mut decoding = InstructionDecoding { port, @@ -87,7 +94,10 @@ impl M68kDecoder { Ok(()) } - pub fn dump_disassembly(&mut self, port: &mut BusPort, memory: &mut M68kBusPort, start: u32, length: u32) { + pub fn dump_disassembly(&mut self, port: &mut Bus, memory: &mut M68kBusPort, start: u32, length: u32) + where + Bus: BusAccess, + { let mut next = start; while next < (start + length) { match self.decode_at(port, memory, self.is_supervisor, next) { @@ -109,8 +119,11 @@ impl M68kDecoder { } } - pub fn dump_decoded(&mut self, clock: Instant, port: &mut BusPort) { - let ins_data: Result = + pub fn dump_decoded(&mut self, clock: Instant, port: &mut Bus) + where + Bus: BusAccess, + { + 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())) ).collect(); @@ -118,9 +131,12 @@ impl M68kDecoder { } } -impl<'a> InstructionDecoding<'a> { +impl<'a, Bus> InstructionDecoding<'a, Bus> +where + Bus: BusAccess, +{ #[inline] - pub fn decode_next(&mut self) -> Result { + pub fn decode_next(&mut self) -> Result> { let ins = self.read_instruction_word()?; self.decoder.instruction_word = ins; @@ -146,7 +162,7 @@ impl<'a> InstructionDecoding<'a> { } #[inline] - fn decode_group_bit_ops(&mut self, ins: u16) -> Result { + fn decode_group_bit_ops(&mut self, ins: u16) -> Result> { let optype = (ins & 0x0F00) >> 8; if (ins & 0x13F) == 0x03C { @@ -221,14 +237,14 @@ impl<'a> InstructionDecoding<'a> { } #[inline] - fn decode_group_move_byte(&mut self, ins: u16) -> Result { + fn decode_group_move_byte(&mut self, ins: u16) -> Result> { let src = self.decode_lower_effective_address(ins, Some(Size::Byte))?; let dest = self.decode_upper_effective_address(ins, Some(Size::Byte))?; Ok(Instruction::MOVE(src, dest, Size::Byte)) } #[inline] - fn decode_group_move_long(&mut self, ins: u16) -> Result { + fn decode_group_move_long(&mut self, ins: u16) -> Result> { let src = self.decode_lower_effective_address(ins, Some(Size::Long))?; let dest = self.decode_upper_effective_address(ins, Some(Size::Long))?; if let Target::DirectAReg(reg) = dest { @@ -239,7 +255,7 @@ impl<'a> InstructionDecoding<'a> { } #[inline] - fn decode_group_move_word(&mut self, ins: u16) -> Result { + fn decode_group_move_word(&mut self, ins: u16) -> Result> { let src = self.decode_lower_effective_address(ins, Some(Size::Word))?; let dest = self.decode_upper_effective_address(ins, Some(Size::Word))?; if let Target::DirectAReg(reg) = dest { @@ -250,7 +266,7 @@ impl<'a> InstructionDecoding<'a> { } #[inline] - fn decode_group_misc(&mut self, ins: u16) -> Result { + fn decode_group_misc(&mut self, ins: u16) -> Result> { let ins_0f00 = ins & 0xF00; let ins_00f0 = ins & 0x0F0; @@ -421,7 +437,7 @@ impl<'a> InstructionDecoding<'a> { } #[inline] - fn decode_group_addq_subq(&mut self, ins: u16) -> Result { + fn decode_group_addq_subq(&mut self, ins: u16) -> Result> { match get_size(ins) { Some(size) => { let target = self.decode_lower_effective_address(ins, Some(size))?; @@ -459,7 +475,7 @@ impl<'a> InstructionDecoding<'a> { } #[inline] - fn decode_group_branch(&mut self, ins: u16) -> Result { + fn decode_group_branch(&mut self, ins: u16) -> Result> { let mut disp = ((ins & 0xFF) as i8) as i32; if disp == 0 { disp = (self.read_instruction_word()? as i16) as i32; @@ -475,7 +491,7 @@ impl<'a> InstructionDecoding<'a> { } #[inline] - fn decode_group_moveq(&mut self, ins: u16) -> Result { + fn decode_group_moveq(&mut self, ins: u16) -> Result> { if (ins & 0x0100) != 0 { return Err(M68kError::Exception(Exceptions::IllegalInstruction)); } @@ -485,7 +501,7 @@ impl<'a> InstructionDecoding<'a> { } #[inline] - fn decode_group_div_or(&mut self, ins: u16) -> Result { + fn decode_group_div_or(&mut self, ins: u16) -> Result> { let size = get_size(ins); if (ins & 0x1F0) == 0x100 { @@ -509,7 +525,7 @@ impl<'a> InstructionDecoding<'a> { } #[inline] - fn decode_group_sub(&mut self, ins: u16) -> Result { + fn decode_group_sub(&mut self, ins: u16) -> Result> { let reg = get_high_reg(ins); let dir = (ins & 0x0100) >> 8; let size = get_size(ins); @@ -540,7 +556,7 @@ impl<'a> InstructionDecoding<'a> { } #[inline] - fn decode_group_cmp_eor(&mut self, ins: u16) -> Result { + fn decode_group_cmp_eor(&mut self, ins: u16) -> Result> { let reg = get_high_reg(ins); let optype = (ins & 0x0100) >> 8; let size = get_size(ins); @@ -567,7 +583,7 @@ impl<'a> InstructionDecoding<'a> { } #[inline] - fn decode_group_mul_and(&mut self, ins: u16) -> Result { + fn decode_group_mul_and(&mut self, ins: u16) -> Result> { let size = get_size(ins); if (ins & 0b0001_1111_0000) == 0b0001_0000_0000 { @@ -600,7 +616,7 @@ impl<'a> InstructionDecoding<'a> { } #[inline] - fn decode_group_add(&mut self, ins: u16) -> Result { + fn decode_group_add(&mut self, ins: u16) -> Result> { let reg = get_high_reg(ins); let dir = (ins & 0x0100) >> 8; let size = get_size(ins); @@ -630,7 +646,7 @@ impl<'a> InstructionDecoding<'a> { } } - fn decode_group_shift(&mut self, ins: u16) -> Result { + fn decode_group_shift(&mut self, ins: u16) -> Result> { match get_size(ins) { Some(size) => { let target = Target::DirectDReg(get_low_reg(ins)); @@ -716,31 +732,31 @@ impl<'a> InstructionDecoding<'a> { } } - fn read_instruction_word(&mut self) -> Result { + fn read_instruction_word(&mut self) -> Result> { let word = self.memory.read_instruction_word(self.port, self.decoder.is_supervisor, self.decoder.end)?; self.decoder.end += 2; Ok(word) } - fn read_instruction_long(&mut self) -> Result { + fn read_instruction_long(&mut self) -> Result> { let word = self.memory.read_instruction_long(self.port, self.decoder.is_supervisor, self.decoder.end)?; self.decoder.end += 4; Ok(word) } - fn decode_lower_effective_address(&mut self, ins: u16, size: Option) -> Result { + fn decode_lower_effective_address(&mut self, ins: u16, size: Option) -> Result> { let reg = get_low_reg(ins); let mode = get_low_mode(ins); self.get_mode_as_target(mode, reg, size) } - fn decode_upper_effective_address(&mut self, ins: u16, size: Option) -> Result { + fn decode_upper_effective_address(&mut self, ins: u16, size: Option) -> Result> { let reg = get_high_reg(ins); let mode = get_high_mode(ins); self.get_mode_as_target(mode, reg, size) } - fn get_extension_displacement(&mut self, select: u16) -> Result { + fn get_extension_displacement(&mut self, select: u16) -> Result> { let result = match select { 0b00 | 0b01 => 0, 0b10 => sign_extend_to_long(self.read_instruction_word()? as u32, Size::Word), @@ -750,7 +766,7 @@ impl<'a> InstructionDecoding<'a> { Ok(result) } - fn decode_extension_word(&mut self, areg: Option) -> Result { + fn decode_extension_word(&mut self, areg: Option) -> Result> { let brief_extension = self.read_instruction_word()?; let use_brief = (brief_extension & 0x0100) == 0; @@ -803,7 +819,7 @@ impl<'a> InstructionDecoding<'a> { } } - pub(super) fn get_mode_as_target(&mut self, mode: u8, reg: u8, size: Option) -> Result { + pub(super) fn get_mode_as_target(&mut self, mode: u8, reg: u8, size: Option) -> Result> { let value = match mode { 0b000 => Target::DirectDReg(reg), 0b001 => Target::DirectAReg(reg), diff --git a/emulator/cpus/m68k/src/execute.rs b/emulator/cpus/m68k/src/execute.rs index d17af98..d4c9232 100644 --- a/emulator/cpus/m68k/src/execute.rs +++ b/emulator/cpus/m68k/src/execute.rs @@ -1,10 +1,11 @@ use femtos::{Instant, Duration}; +use emulator_hal::bus::{self, BusAccess, BusAdapter}; 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::memory::{MemType, MemAccess, M68kBusPort}; +use crate::memory::{MemType, MemAccess, M68kBusPort, M68kAddress}; use crate::decode::M68kDecoder; use crate::debugger::M68kDebugger; use crate::timing::M68kInstructionTiming; @@ -65,24 +66,40 @@ impl M68kCycle { } #[inline] - pub fn begin<'a>(mut self, cpu: &'a mut M68k) -> M68kCycleExecutor<'a> { + pub fn begin<'a>(mut self, cpu: &'a mut M68k) -> M68kCycleExecutor<'a, bus::BusAdapter> { + let adapter = bus::BusAdapter { + bus: &mut cpu.port, + translate: translate_address, + instant: core::marker::PhantomData, + }; + M68kCycleExecutor { state: &mut cpu.state, - port: &mut cpu.port, + port: adapter, debugger: &mut cpu.debugger, cycle: self, } } } -pub struct M68kCycleExecutor<'a> { +fn translate_address(addr_in: M68kAddress) -> u64 { + addr_in as u64 +} + +pub struct M68kCycleExecutor<'a, Bus> +where + Bus: BusAccess, +{ pub state: &'a mut M68kState, - pub port: &'a mut BusPort, + pub port: Bus, pub debugger: &'a mut M68kDebugger, pub cycle: M68kCycle, } -impl<'a> M68kCycleExecutor<'a> { +impl<'a, Bus> M68kCycleExecutor<'a, Bus> +where + Bus: BusAccess, +{ #[inline] pub fn dump_state(&mut self) { println!("Status: {:?}", self.state.status); @@ -96,7 +113,7 @@ impl<'a> M68kCycleExecutor<'a> { println!("Current Instruction: {:#010x} {:?}", self.cycle.decoder.start, self.cycle.decoder.instruction); println!(); - self.cycle.memory.dump_memory(self.port, self.state.ssp, 0x40); + self.cycle.memory.dump_memory(&mut self.port, self.state.ssp, 0x40); println!(); } @@ -136,20 +153,21 @@ impl Transmutable for M68k { } } -impl From for Error { - fn from(err: M68kError) -> 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 { +impl From for M68kError { fn from(err: Error) -> Self { match err { Error::Processor(ex) => M68kError::Interrupt(ex as u8), @@ -159,15 +177,18 @@ impl From for M68kError { } } -impl<'a> M68kCycleExecutor<'a> { +impl<'a, Bus> M68kCycleExecutor<'a, Bus> +where + Bus: BusAccess, +{ #[inline] - pub fn step(&mut self, system: &System) -> Result { + 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 { + pub fn process_error(&mut self, result: Result>, ok: T) -> Result> { match result { Ok(value) => Ok(value), Err(M68kError::Exception(ex)) => { @@ -183,34 +204,36 @@ impl<'a> M68kCycleExecutor<'a> { } #[inline] - pub fn step_one(&mut self, system: &System) -> Result { + pub fn step_one(&mut self, system: &System) -> Result> { match self.state.status { Status::Init => self.reset_cpu(), Status::Stopped => Err(M68kError::Halted), Status::Running => self.cycle_one(system), - } + }?; + Ok(self.cycle.timing.calculate_clocks()) } #[inline] - pub fn reset_cpu(&mut self) -> Result { + pub fn reset_cpu(&mut self) -> Result<(), M68kError> { self.state.ssp = self.get_address_sized(0, Size::Long)?; self.state.pc = self.get_address_sized(4, Size::Long)?; self.state.status = Status::Running; - Ok(16) + self.cycle.timing.performed_reset(); + Ok(()) } #[inline] - pub fn cycle_one(&mut self, system: &System) -> Result { + pub fn cycle_one(&mut self, system: &System) -> Result<(), M68kError> { self.check_breakpoints()?; self.decode_and_execute()?; self.check_pending_interrupts(system)?; - Ok(self.cycle.timing.calculate_clocks(false, 1)) + Ok(()) } #[inline] - pub fn check_pending_interrupts(&mut self, system: &System) -> Result<(), M68kError> { + pub fn check_pending_interrupts(&mut self, system: &System) -> Result<(), M68kError> { // TODO this could move somewhere else self.state.pending_ipl = match system.get_interrupt_controller().check() { (true, priority) => InterruptPriority::from_u8(priority), @@ -268,7 +291,7 @@ impl<'a> M68kCycleExecutor<'a> { } */ - pub fn exception(&mut self, number: u8, is_interrupt: bool) -> Result<(), M68kError> { + pub fn exception(&mut self, number: u8, is_interrupt: bool) -> Result<(), M68kError> { log::debug!("{}: raising exception {}", DEV_NAME, number); if number == Exceptions::BusError as u8 || number == Exceptions::AddressError as u8 { @@ -284,7 +307,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn setup_group0_exception(&mut self, number: u8) -> Result<(), M68kError> { + fn setup_group0_exception(&mut self, number: u8) -> Result<(), M68kError> { let sr = self.state.sr; let ins_word = self.cycle.decoder.instruction_word; let extra_code = self.cycle.memory.request.get_type_code(); @@ -313,7 +336,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn setup_normal_exception(&mut self, number: u8, is_interrupt: bool) -> Result<(), M68kError> { + fn setup_normal_exception(&mut self, number: u8, is_interrupt: bool) -> Result<(), M68kError> { let sr = self.state.sr; self.cycle.memory.request.i_n_bit = true; @@ -339,14 +362,14 @@ impl<'a> M68kCycleExecutor<'a> { } #[inline] - pub fn decode_and_execute(&mut self) -> Result<(), M68kError> { + pub fn decode_and_execute(&mut self) -> Result<(), M68kError> { self.decode_next()?; self.execute_current()?; Ok(()) } #[inline] - pub fn decode_next(&mut self) -> Result<(), M68kError> { + pub fn decode_next(&mut self) -> Result<(), M68kError> { let is_supervisor = self.is_supervisor(); self.cycle.decoder.decode_at(&mut self.port, &mut self.cycle.memory, is_supervisor, self.state.pc)?; @@ -358,7 +381,7 @@ impl<'a> M68kCycleExecutor<'a> { } #[inline] - pub fn execute_current(&mut self) -> Result<(), M68kError> { + pub fn execute_current(&mut self) -> Result<(), M68kError> { match self.cycle.decoder.instruction { Instruction::ABCD(src, dest) => self.execute_abcd(src, dest), Instruction::ADD(src, dest, size) => self.execute_add(src, dest, size), @@ -454,7 +477,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_abcd(&mut self, src: Target, dest: Target) -> Result<(), M68kError> { + fn execute_abcd(&mut self, src: Target, dest: Target) -> Result<(), M68kError> { let src_val = self.get_target_value(src, Size::Byte, Used::Once)?; let dest_val = self.get_target_value(dest, Size::Byte, Used::Twice)?; @@ -478,7 +501,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_add(&mut self, src: Target, dest: Target, size: Size) -> Result<(), M68kError> { + fn execute_add(&mut self, src: Target, dest: Target, size: Size) -> Result<(), M68kError> { let src_val = self.get_target_value(src, size, Used::Once)?; let dest_val = self.get_target_value(dest, size, Used::Twice)?; let (result, carry) = overflowing_add_sized(dest_val, src_val, size); @@ -489,7 +512,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_adda(&mut self, src: Target, dest: Register, size: Size) -> Result<(), M68kError> { + fn execute_adda(&mut self, src: Target, dest: Register, size: Size) -> Result<(), M68kError> { let src_val = sign_extend_to_long(self.get_target_value(src, size, Used::Once)?, size) as u32; let dest_val = *self.get_a_reg_mut(dest); let (result, _) = overflowing_add_sized(dest_val, src_val, Size::Long); @@ -497,7 +520,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_addx(&mut self, src: Target, dest: Target, size: Size) -> Result<(), M68kError> { + fn execute_addx(&mut self, src: Target, dest: Target, size: Size) -> Result<(), M68kError> { let src_val = self.get_target_value(src, size, Used::Once)?; let dest_val = self.get_target_value(dest, size, Used::Twice)?; let extend = self.get_flag(Flags::Extend) as u32; @@ -518,7 +541,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_and(&mut self, src: Target, dest: Target, size: Size) -> Result<(), M68kError> { + fn execute_and(&mut self, src: Target, dest: Target, size: Size) -> Result<(), M68kError> { let src_val = self.get_target_value(src, size, Used::Once)?; let dest_val = self.get_target_value(dest, size, Used::Twice)?; let result = get_value_sized(dest_val & src_val, size); @@ -527,18 +550,18 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_and_to_ccr(&mut self, value: u8) -> Result<(), M68kError> { + fn execute_and_to_ccr(&mut self, value: u8) -> Result<(), M68kError> { self.state.sr = (self.state.sr & 0xFF00) | ((self.state.sr & 0x00FF) & (value as u16)); Ok(()) } - fn execute_and_to_sr(&mut self, value: u16) -> Result<(), M68kError> { + fn execute_and_to_sr(&mut self, value: u16) -> Result<(), M68kError> { self.require_supervisor()?; self.set_sr(self.state.sr & value); Ok(()) } - fn execute_asl(&mut self, count: Target, target: Target, size: Size) -> Result<(), M68kError> { + fn execute_asl(&mut self, count: Target, target: Target, size: Size) -> Result<(), M68kError> { let count = self.get_target_value(count, size, Used::Once)? % 64; let value = self.get_target_value(target, size, Used::Twice)?; @@ -558,7 +581,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_asr(&mut self, count: Target, target: Target, size: Size) -> Result<(), M68kError> { + fn execute_asr(&mut self, count: Target, target: Target, size: Size) -> Result<(), M68kError> { let count = self.get_target_value(count, size, Used::Once)? % 64; let value = self.get_target_value(target, size, Used::Twice)?; @@ -591,7 +614,7 @@ impl<'a> M68kCycleExecutor<'a> { } } - fn execute_bcc(&mut self, cond: Condition, offset: i32) -> Result<(), M68kError> { + fn execute_bcc(&mut self, cond: Condition, offset: i32) -> Result<(), M68kError> { let should_branch = self.get_current_condition(cond); if should_branch { if let Err(err) = self.set_pc(self.cycle.decoder.start.wrapping_add(2).wrapping_add(offset as u32)) { @@ -602,7 +625,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_bra(&mut self, offset: i32) -> Result<(), M68kError> { + fn execute_bra(&mut self, offset: i32) -> Result<(), M68kError> { if let Err(err) = self.set_pc(self.cycle.decoder.start.wrapping_add(2).wrapping_add(offset as u32)) { self.state.pc -= 2; return Err(err); @@ -610,7 +633,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_bsr(&mut self, offset: i32) -> Result<(), M68kError> { + fn execute_bsr(&mut self, offset: i32) -> Result<(), M68kError> { self.push_long(self.state.pc)?; let sp = *self.get_stack_pointer_mut(); self.debugger.stack_tracer.push_return(sp); @@ -621,7 +644,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_bchg(&mut self, bitnum: Target, target: Target, size: Size) -> Result<(), M68kError> { + fn execute_bchg(&mut self, bitnum: Target, target: Target, size: Size) -> Result<(), M68kError> { let bitnum = self.get_target_value(bitnum, Size::Byte, Used::Once)?; let mut src_val = self.get_target_value(target, size, Used::Twice)?; let mask = self.set_bit_test_flags(src_val, bitnum, size); @@ -630,7 +653,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_bclr(&mut self, bitnum: Target, target: Target, size: Size) -> Result<(), M68kError> { + fn execute_bclr(&mut self, bitnum: Target, target: Target, size: Size) -> Result<(), M68kError> { let bitnum = self.get_target_value(bitnum, Size::Byte, Used::Once)?; let mut src_val = self.get_target_value(target, size, Used::Twice)?; let mask = self.set_bit_test_flags(src_val, bitnum, size); @@ -639,7 +662,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_bset(&mut self, bitnum: Target, target: Target, size: Size) -> Result<(), M68kError> { + fn execute_bset(&mut self, bitnum: Target, target: Target, size: Size) -> Result<(), M68kError> { let bitnum = self.get_target_value(bitnum, Size::Byte, Used::Once)?; let mut value = self.get_target_value(target, size, Used::Twice)?; let mask = self.set_bit_test_flags(value, bitnum, size); @@ -648,14 +671,14 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_btst(&mut self, bitnum: Target, target: Target, size: Size) -> Result<(), M68kError> { + fn execute_btst(&mut self, bitnum: Target, target: Target, size: Size) -> Result<(), M68kError> { let bitnum = self.get_target_value(bitnum, Size::Byte, Used::Once)?; let value = self.get_target_value(target, size, Used::Once)?; self.set_bit_test_flags(value, bitnum, size); Ok(()) } - fn execute_bfchg(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate) -> Result<(), M68kError> { + fn execute_bfchg(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate) -> Result<(), M68kError> { let (offset, width) = self.get_bit_field_args(offset, width); let mask = get_bit_field_mask(offset, width); let value = self.get_target_value(target, Size::Long, Used::Twice)?; @@ -665,7 +688,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_bfclr(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate) -> Result<(), M68kError> { + fn execute_bfclr(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate) -> Result<(), M68kError> { let (offset, width) = self.get_bit_field_args(offset, width); let mask = get_bit_field_mask(offset, width); let value = self.get_target_value(target, Size::Long, Used::Twice)?; @@ -675,7 +698,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_bfexts(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate, reg: Register) -> Result<(), M68kError> { + fn execute_bfexts(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate, reg: Register) -> Result<(), M68kError> { let (offset, width) = self.get_bit_field_args(offset, width); let mask = get_bit_field_mask(offset, width); let value = self.get_target_value(target, Size::Long, Used::Once)?; @@ -691,7 +714,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_bfextu(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate, reg: Register) -> Result<(), M68kError> { + fn execute_bfextu(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate, reg: Register) -> Result<(), M68kError> { let (offset, width) = self.get_bit_field_args(offset, width); let mask = get_bit_field_mask(offset, width); let value = self.get_target_value(target, Size::Long, Used::Once)?; @@ -701,7 +724,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_bfset(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate) -> Result<(), M68kError> { + fn execute_bfset(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate) -> Result<(), M68kError> { let (offset, width) = self.get_bit_field_args(offset, width); let mask = get_bit_field_mask(offset, width); let value = self.get_target_value(target, Size::Long, Used::Twice)?; @@ -711,7 +734,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_bftst(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate) -> Result<(), M68kError> { + fn execute_bftst(&mut self, target: Target, offset: RegOrImmediate, width: RegOrImmediate) -> Result<(), M68kError> { let (offset, width) = self.get_bit_field_args(offset, width); let mask = get_bit_field_mask(offset, width); let value = self.get_target_value(target, Size::Long, Used::Once)?; @@ -720,7 +743,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_chk(&mut self, target: Target, reg: Register, size: Size) -> Result<(), M68kError> { + fn execute_chk(&mut self, target: Target, reg: Register, size: Size) -> Result<(), M68kError> { let upper_bound = sign_extend_to_long(self.get_target_value(target, size, Used::Once)?, size); let dreg = sign_extend_to_long(self.state.d_reg[reg as usize], size); @@ -736,7 +759,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_clr(&mut self, target: Target, size: Size) -> Result<(), M68kError> { + fn execute_clr(&mut self, target: Target, size: Size) -> Result<(), M68kError> { if self.cycle.decoder.cputype == M68kType::MC68000 { self.get_target_value(target, size, Used::Twice)?; self.set_target_value(target, 0, size, Used::Twice)?; @@ -748,7 +771,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_cmp(&mut self, src: Target, dest: Target, size: Size) -> Result<(), M68kError> { + fn execute_cmp(&mut self, src: Target, dest: Target, size: Size) -> Result<(), M68kError> { let src_val = self.get_target_value(src, size, Used::Once)?; let dest_val = self.get_target_value(dest, size, Used::Once)?; let (result, carry) = overflowing_sub_sized(dest_val, src_val, size); @@ -757,7 +780,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_cmpa(&mut self, src: Target, reg: Register, size: Size) -> Result<(), M68kError> { + fn execute_cmpa(&mut self, src: Target, reg: Register, size: Size) -> Result<(), M68kError> { let src_val = sign_extend_to_long(self.get_target_value(src, size, Used::Once)?, size) as u32; let dest_val = *self.get_a_reg_mut(reg); let (result, carry) = overflowing_sub_sized(dest_val, src_val, Size::Long); @@ -766,7 +789,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_dbcc(&mut self, cond: Condition, reg: Register, offset: i16) -> Result<(), M68kError> { + fn execute_dbcc(&mut self, cond: Condition, reg: Register, offset: i16) -> Result<(), M68kError> { let condition_true = self.get_current_condition(cond); if !condition_true { let next = ((get_value_sized(self.state.d_reg[reg as usize], Size::Word) as u16) as i16).wrapping_sub(1); @@ -781,7 +804,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_divw(&mut self, src: Target, dest: Register, sign: Sign) -> Result<(), M68kError> { + fn execute_divw(&mut self, src: Target, dest: Register, sign: Sign) -> Result<(), M68kError> { let src_val = self.get_target_value(src, Size::Word, Used::Once)?; if src_val == 0 { self.exception(Exceptions::ZeroDivide as u8, false)?; @@ -821,7 +844,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_divl(&mut self, src: Target, dest_h: Option, dest_l: Register, sign: Sign) -> Result<(), M68kError> { + fn execute_divl(&mut self, src: Target, dest_h: Option, dest_l: Register, sign: Sign) -> Result<(), M68kError> { let src_val = self.get_target_value(src, Size::Long, Used::Once)?; if src_val == 0 { self.exception(Exceptions::ZeroDivide as u8, false)?; @@ -854,7 +877,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_eor(&mut self, src: Target, dest: Target, size: Size) -> Result<(), M68kError> { + fn execute_eor(&mut self, src: Target, dest: Target, size: Size) -> Result<(), M68kError> { let src_val = self.get_target_value(src, size, Used::Once)?; let dest_val = self.get_target_value(dest, size, Used::Twice)?; let result = get_value_sized(dest_val ^ src_val, size); @@ -863,18 +886,18 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_eor_to_ccr(&mut self, value: u8) -> Result<(), M68kError> { + fn execute_eor_to_ccr(&mut self, value: u8) -> Result<(), M68kError> { self.set_sr((self.state.sr & 0xFF00) | ((self.state.sr & 0x00FF) ^ (value as u16))); Ok(()) } - fn execute_eor_to_sr(&mut self, value: u16) -> Result<(), M68kError> { + fn execute_eor_to_sr(&mut self, value: u16) -> Result<(), M68kError> { self.require_supervisor()?; self.set_sr(self.state.sr ^ value); Ok(()) } - fn execute_exg(&mut self, target1: Target, target2: Target) -> Result<(), M68kError> { + fn execute_exg(&mut self, target1: Target, target2: Target) -> Result<(), M68kError> { let value1 = self.get_target_value(target1, Size::Long, Used::Twice)?; let value2 = self.get_target_value(target2, Size::Long, Used::Twice)?; self.set_target_value(target1, value2, Size::Long, Used::Twice)?; @@ -882,7 +905,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_ext(&mut self, reg: Register, from_size: Size, to_size: Size) -> Result<(), M68kError> { + fn execute_ext(&mut self, reg: Register, from_size: Size, to_size: Size) -> Result<(), M68kError> { let input = get_value_sized(self.state.d_reg[reg as usize], from_size); let result = match (from_size, to_size) { (Size::Byte, Size::Word) => ((((input as u8) as i8) as i16) as u16) as u32, @@ -895,12 +918,12 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_illegal(&mut self) -> Result<(), M68kError> { + fn execute_illegal(&mut self) -> Result<(), M68kError> { self.exception(Exceptions::IllegalInstruction as u8, false)?; Ok(()) } - fn execute_jmp(&mut self, target: Target) -> Result<(), M68kError> { + fn execute_jmp(&mut self, target: Target) -> Result<(), M68kError> { let addr = self.get_target_address(target)?; if let Err(err) = self.set_pc(addr) { self.state.pc -= 2; @@ -909,7 +932,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_jsr(&mut self, target: Target) -> Result<(), M68kError> { + fn execute_jsr(&mut self, target: Target) -> Result<(), M68kError> { let previous_pc = self.state.pc; let addr = self.get_target_address(target)?; if let Err(err) = self.set_pc(addr) { @@ -924,14 +947,14 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_lea(&mut self, target: Target, reg: Register) -> Result<(), M68kError> { + fn execute_lea(&mut self, target: Target, reg: Register) -> Result<(), M68kError> { let value = self.get_target_address(target)?; let addr = self.get_a_reg_mut(reg); *addr = value; Ok(()) } - fn execute_link(&mut self, reg: Register, offset: i32) -> Result<(), M68kError> { + fn execute_link(&mut self, reg: Register, offset: i32) -> Result<(), M68kError> { *self.get_stack_pointer_mut() -= 4; let sp = *self.get_stack_pointer_mut(); let value = *self.get_a_reg_mut(reg); @@ -941,7 +964,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_lsl(&mut self, count: Target, target: Target, size: Size) -> Result<(), M68kError> { + fn execute_lsl(&mut self, count: Target, target: Target, size: Size) -> Result<(), M68kError> { let count = self.get_target_value(count, size, Used::Once)? % 64; let mut pair = (self.get_target_value(target, size, Used::Twice)?, false); for _ in 0..count { @@ -953,7 +976,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_lsr(&mut self, count: Target, target: Target, size: Size) -> Result<(), M68kError> { + fn execute_lsr(&mut self, count: Target, target: Target, size: Size) -> Result<(), M68kError> { let count = self.get_target_value(count, size, Used::Once)? % 64; let mut pair = (self.get_target_value(target, size, Used::Twice)?, false); for _ in 0..count { @@ -976,14 +999,14 @@ impl<'a> M68kCycleExecutor<'a> { } } - fn execute_move(&mut self, src: Target, dest: Target, size: Size) -> Result<(), M68kError> { + fn execute_move(&mut self, src: Target, dest: Target, size: Size) -> Result<(), M68kError> { let src_val = self.get_target_value(src, size, Used::Once)?; self.set_logic_flags(src_val, size); self.set_target_value(dest, src_val, size, Used::Once)?; Ok(()) } - fn execute_movea(&mut self, src: Target, reg: Register, size: Size) -> Result<(), M68kError> { + fn execute_movea(&mut self, src: Target, reg: Register, size: Size) -> Result<(), M68kError> { let src_val = self.get_target_value(src, size, Used::Once)?; let src_val = sign_extend_to_long(src_val, size) as u32; let addr = self.get_a_reg_mut(reg); @@ -991,26 +1014,26 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_move_from_sr(&mut self, target: Target) -> Result<(), M68kError> { + fn execute_move_from_sr(&mut self, target: Target) -> Result<(), M68kError> { self.require_supervisor()?; self.set_target_value(target, self.state.sr as u32, Size::Word, Used::Once)?; Ok(()) } - fn execute_move_to_sr(&mut self, target: Target) -> Result<(), M68kError> { + fn execute_move_to_sr(&mut self, target: Target) -> Result<(), M68kError> { self.require_supervisor()?; let value = self.get_target_value(target, Size::Word, Used::Once)? as u16; self.set_sr(value); Ok(()) } - fn execute_move_to_ccr(&mut self, target: Target) -> Result<(), M68kError> { + fn execute_move_to_ccr(&mut self, target: Target) -> Result<(), M68kError> { let value = self.get_target_value(target, Size::Word, Used::Once)? as u16; self.set_sr((self.state.sr & 0xFF00) | (value & 0x00FF)); Ok(()) } - fn execute_movec(&mut self, target: Target, control_reg: ControlRegister, dir: Direction) -> Result<(), M68kError> { + fn execute_movec(&mut self, target: Target, control_reg: ControlRegister, dir: Direction) -> Result<(), M68kError> { self.require_supervisor()?; match dir { Direction::FromTarget => { @@ -1027,7 +1050,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_movem(&mut self, target: Target, size: Size, dir: Direction, mask: u16) -> Result<(), M68kError> { + fn execute_movem(&mut self, target: Target, size: Size, dir: Direction, mask: u16) -> Result<(), M68kError> { let addr = self.get_target_address(target)?; // If we're using a MC68020 or higher, and it was Post-Inc/Pre-Dec target, then update the value before it's stored @@ -1074,7 +1097,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn move_memory_to_registers(&mut self, mut addr: u32, size: Size, mut mask: u16) -> Result { + 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; @@ -1092,7 +1115,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(addr) } - fn move_registers_to_memory(&mut self, mut addr: u32, size: Size, mut mask: u16) -> Result { + 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)?; @@ -1111,7 +1134,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(addr) } - fn move_registers_to_memory_reverse(&mut self, mut addr: u32, size: Size, mut mask: u16) -> Result { + fn move_registers_to_memory_reverse(&mut self, mut addr: u32, size: Size, mut mask: u16) -> Result> { for i in (0..8).rev() { if (mask & 0x01) != 0 { let value = *self.get_a_reg_mut(i); @@ -1130,7 +1153,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(addr) } - fn execute_movep(&mut self, dreg: Register, areg: Register, offset: i16, size: Size, dir: Direction) -> Result<(), M68kError> { + fn execute_movep(&mut self, dreg: Register, areg: Register, offset: i16, size: Size, dir: Direction) -> Result<(), M68kError> { match dir { Direction::ToTarget => { let mut shift = (size.in_bits() as i32) - 8; @@ -1156,14 +1179,14 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_moveq(&mut self, data: u8, reg: Register) -> Result<(), M68kError> { + fn execute_moveq(&mut self, data: u8, reg: Register) -> Result<(), M68kError> { let value = sign_extend_to_long(data as u32, Size::Byte) as u32; self.state.d_reg[reg as usize] = value; self.set_logic_flags(value, Size::Long); Ok(()) } - fn execute_moveusp(&mut self, target: Target, dir: Direction) -> Result<(), M68kError> { + fn execute_moveusp(&mut self, target: Target, dir: Direction) -> Result<(), M68kError> { self.require_supervisor()?; match dir { Direction::ToTarget => self.set_target_value(target, self.state.usp, Size::Long, Used::Once)?, @@ -1172,7 +1195,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_mulw(&mut self, src: Target, dest: Register, sign: Sign) -> Result<(), M68kError> { + fn execute_mulw(&mut self, src: Target, dest: Register, sign: Sign) -> Result<(), M68kError> { let src_val = self.get_target_value(src, Size::Word, Used::Once)?; let dest_val = get_value_sized(self.state.d_reg[dest as usize], Size::Word); let result = match sign { @@ -1185,7 +1208,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_mull(&mut self, src: Target, dest_h: Option, dest_l: Register, sign: Sign) -> Result<(), M68kError> { + fn execute_mull(&mut self, src: Target, dest_h: Option, dest_l: Register, sign: Sign) -> Result<(), M68kError> { let src_val = self.get_target_value(src, Size::Long, Used::Once)?; let dest_val = get_value_sized(self.state.d_reg[dest_l as usize], Size::Long); let result = match sign { @@ -1201,14 +1224,14 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_nbcd(&mut self, dest: Target) -> Result<(), M68kError> { + fn execute_nbcd(&mut self, dest: Target) -> Result<(), M68kError> { let dest_val = self.get_target_value(dest, Size::Byte, Used::Twice)?; let result = self.execute_sbcd_val(dest_val, 0)?; self.set_target_value(dest, result, Size::Byte, Used::Twice)?; Ok(()) } - fn execute_neg(&mut self, target: Target, size: Size) -> Result<(), M68kError> { + fn execute_neg(&mut self, target: Target, size: Size) -> Result<(), M68kError> { let original = self.get_target_value(target, size, Used::Twice)?; let (result, overflow) = overflowing_sub_signed_sized(0, original, size); let carry = result != 0; @@ -1218,7 +1241,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_negx(&mut self, dest: Target, size: Size) -> Result<(), M68kError> { + fn execute_negx(&mut self, dest: Target, size: Size) -> Result<(), M68kError> { let dest_val = self.get_target_value(dest, size, Used::Twice)?; let extend = self.get_flag(Flags::Extend) as u32; let (result1, carry1) = overflowing_sub_sized(0, dest_val, size); @@ -1238,7 +1261,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_not(&mut self, target: Target, size: Size) -> Result<(), M68kError> { + fn execute_not(&mut self, target: Target, size: Size) -> Result<(), M68kError> { let mut value = self.get_target_value(target, size, Used::Twice)?; value = get_value_sized(!value, size); self.set_target_value(target, value, size, Used::Twice)?; @@ -1246,7 +1269,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_or(&mut self, src: Target, dest: Target, size: Size) -> Result<(), M68kError> { + fn execute_or(&mut self, src: Target, dest: Target, size: Size) -> Result<(), M68kError> { let src_val = self.get_target_value(src, size, Used::Once)?; let dest_val = self.get_target_value(dest, size, Used::Twice)?; let result = get_value_sized(dest_val | src_val, size); @@ -1255,30 +1278,30 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_or_to_ccr(&mut self, value: u8) -> Result<(), M68kError> { + fn execute_or_to_ccr(&mut self, value: u8) -> Result<(), M68kError> { self.set_sr((self.state.sr & 0xFF00) | ((self.state.sr & 0x00FF) | (value as u16))); Ok(()) } - fn execute_or_to_sr(&mut self, value: u16) -> Result<(), M68kError> { + fn execute_or_to_sr(&mut self, value: u16) -> Result<(), M68kError> { self.require_supervisor()?; self.set_sr(self.state.sr | value); Ok(()) } - fn execute_pea(&mut self, target: Target) -> Result<(), M68kError> { + fn execute_pea(&mut self, target: Target) -> Result<(), M68kError> { let value = self.get_target_address(target)?; self.push_long(value)?; Ok(()) } - fn execute_reset(&mut self) -> Result<(), M68kError> { + fn execute_reset(&mut self) -> Result<(), M68kError> { self.require_supervisor()?; // TODO this only resets external devices and not internal ones Ok(()) } - fn execute_rol(&mut self, count: Target, target: Target, size: Size) -> Result<(), M68kError> { + fn execute_rol(&mut self, count: Target, target: Target, size: Size) -> Result<(), M68kError> { let count = self.get_target_value(count, size, Used::Once)? % 64; let mut pair = (self.get_target_value(target, size, Used::Twice)?, false); for _ in 0..count { @@ -1289,7 +1312,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_ror(&mut self, count: Target, target: Target, size: Size) -> Result<(), M68kError> { + fn execute_ror(&mut self, count: Target, target: Target, size: Size) -> Result<(), M68kError> { let count = self.get_target_value(count, size, Used::Once)? % 64; let mut pair = (self.get_target_value(target, size, Used::Twice)?, false); for _ in 0..count { @@ -1300,7 +1323,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_roxl(&mut self, count: Target, target: Target, size: Size) -> Result<(), M68kError> { + fn execute_roxl(&mut self, count: Target, target: Target, size: Size) -> Result<(), M68kError> { let count = self.get_target_value(count, size, Used::Once)? % 64; let mut pair = (self.get_target_value(target, size, Used::Twice)?, false); for _ in 0..count { @@ -1312,7 +1335,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_roxr(&mut self, count: Target, target: Target, size: Size) -> Result<(), M68kError> { + fn execute_roxr(&mut self, count: Target, target: Target, size: Size) -> Result<(), M68kError> { let count = self.get_target_value(count, size, Used::Once)? % 64; let mut pair = (self.get_target_value(target, size, Used::Twice)?, false); for _ in 0..count { @@ -1331,7 +1354,7 @@ impl<'a> M68kCycleExecutor<'a> { } } - fn execute_rte(&mut self) -> Result<(), M68kError> { + fn execute_rte(&mut self) -> Result<(), M68kError> { self.require_supervisor()?; let sr = self.pop_word()?; let addr = self.pop_long()?; @@ -1348,7 +1371,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_rtr(&mut self) -> Result<(), M68kError> { + fn execute_rtr(&mut self) -> Result<(), M68kError> { let ccr = self.pop_word()?; let addr = self.pop_long()?; self.set_sr((self.state.sr & 0xFF00) | (ccr & 0x00FF)); @@ -1359,7 +1382,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_rts(&mut self) -> Result<(), M68kError> { + fn execute_rts(&mut self) -> Result<(), M68kError> { self.debugger.stack_tracer.pop_return(); let addr = self.pop_long()?; if let Err(err) = self.set_pc(addr) { @@ -1369,7 +1392,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_scc(&mut self, cond: Condition, target: Target) -> Result<(), M68kError> { + fn execute_scc(&mut self, cond: Condition, target: Target) -> Result<(), M68kError> { let condition_true = self.get_current_condition(cond); if condition_true { self.set_target_value(target, 0xFF, Size::Byte, Used::Once)?; @@ -1379,14 +1402,14 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_stop(&mut self, flags: u16) -> Result<(), M68kError> { + fn execute_stop(&mut self, flags: u16) -> Result<(), M68kError> { self.require_supervisor()?; self.set_sr(flags); self.state.status = Status::Stopped; Ok(()) } - fn execute_sbcd(&mut self, src: Target, dest: Target) -> Result<(), M68kError> { + fn execute_sbcd(&mut self, src: Target, dest: Target) -> Result<(), M68kError> { let src_val = self.get_target_value(src, Size::Byte, Used::Once)?; let dest_val = self.get_target_value(dest, Size::Byte, Used::Twice)?; let result = self.execute_sbcd_val(src_val, dest_val)?; @@ -1394,7 +1417,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_sbcd_val(&mut self, src_val: u32, dest_val: u32) -> Result { + fn execute_sbcd_val(&mut self, src_val: u32, dest_val: u32) -> Result> { let extend_flag = self.get_flag(Flags::Extend) as u32; let src_parts = get_nibbles_from_byte(src_val); let dest_parts = get_nibbles_from_byte(dest_val); @@ -1415,7 +1438,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(result) } - fn execute_sub(&mut self, src: Target, dest: Target, size: Size) -> Result<(), M68kError> { + fn execute_sub(&mut self, src: Target, dest: Target, size: Size) -> Result<(), M68kError> { let src_val = self.get_target_value(src, size, Used::Once)?; let dest_val = self.get_target_value(dest, size, Used::Twice)?; let (result, carry) = overflowing_sub_sized(dest_val, src_val, size); @@ -1426,7 +1449,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_suba(&mut self, src: Target, dest: Register, size: Size) -> Result<(), M68kError> { + fn execute_suba(&mut self, src: Target, dest: Register, size: Size) -> Result<(), M68kError> { let src_val = sign_extend_to_long(self.get_target_value(src, size, Used::Once)?, size) as u32; let dest_val = *self.get_a_reg_mut(dest); let (result, _) = overflowing_sub_sized(dest_val, src_val, Size::Long); @@ -1434,7 +1457,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_subx(&mut self, src: Target, dest: Target, size: Size) -> Result<(), M68kError> { + fn execute_subx(&mut self, src: Target, dest: Target, size: Size) -> Result<(), M68kError> { let src_val = self.get_target_value(src, size, Used::Once)?; let dest_val = self.get_target_value(dest, size, Used::Twice)?; let extend = self.get_flag(Flags::Extend) as u32; @@ -1455,14 +1478,14 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_swap(&mut self, reg: Register) -> Result<(), M68kError> { + fn execute_swap(&mut self, reg: Register) -> Result<(), M68kError> { let value = self.state.d_reg[reg as usize]; self.state.d_reg[reg as usize] = ((value & 0x0000FFFF) << 16) | ((value & 0xFFFF0000) >> 16); self.set_logic_flags(self.state.d_reg[reg as usize], Size::Long); Ok(()) } - fn execute_tas(&mut self, target: Target) -> Result<(), M68kError> { + fn execute_tas(&mut self, target: Target) -> Result<(), M68kError> { let value = self.get_target_value(target, Size::Byte, Used::Twice)?; self.set_flag(Flags::Negative, (value & 0x80) != 0); self.set_flag(Flags::Zero, value == 0); @@ -1472,25 +1495,25 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_tst(&mut self, target: Target, size: Size) -> Result<(), M68kError> { + fn execute_tst(&mut self, target: Target, size: Size) -> Result<(), M68kError> { let value = self.get_target_value(target, size, Used::Once)?; self.set_logic_flags(value, size); Ok(()) } - fn execute_trap(&mut self, number: u8) -> Result<(), M68kError> { + fn execute_trap(&mut self, number: u8) -> Result<(), M68kError> { self.exception(32 + number, false)?; Ok(()) } - fn execute_trapv(&mut self) -> Result<(), M68kError> { + fn execute_trapv(&mut self) -> Result<(), M68kError> { if self.get_flag(Flags::Overflow) { self.exception(Exceptions::TrapvInstruction as u8, false)?; } Ok(()) } - fn execute_unlk(&mut self, reg: Register) -> Result<(), M68kError> { + fn execute_unlk(&mut self, reg: Register) -> Result<(), M68kError> { let value = *self.get_a_reg_mut(reg); *self.get_stack_pointer_mut() = value; let new_value = self.pop_long()?; @@ -1499,20 +1522,20 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn execute_unimplemented_a(&mut self, _: u16) -> Result<(), M68kError> { + fn execute_unimplemented_a(&mut self, _: u16) -> Result<(), M68kError> { self.state.pc -= 2; self.exception(Exceptions::LineAEmulator as u8, false)?; Ok(()) } - fn execute_unimplemented_f(&mut self, _: u16) -> Result<(), M68kError> { + fn execute_unimplemented_f(&mut self, _: u16) -> Result<(), M68kError> { self.state.pc -= 2; self.exception(Exceptions::LineFEmulator as u8, false)?; Ok(()) } - pub(super) fn get_target_value(&mut self, target: Target, size: Size, used: Used) -> Result { + pub(super) fn get_target_value(&mut self, target: Target, size: Size, used: Used) -> Result> { match target { Target::Immediate(value) => Ok(value), Target::DirectDReg(reg) => Ok(get_value_sized(self.state.d_reg[reg as usize], size)), @@ -1552,7 +1575,7 @@ impl<'a> M68kCycleExecutor<'a> { } } - pub(super) fn set_target_value(&mut self, target: Target, value: u32, size: Size, used: Used) -> Result<(), M68kError> { + pub(super) fn set_target_value(&mut self, target: Target, value: u32, size: Size, used: Used) -> Result<(), M68kError> { match target { Target::DirectDReg(reg) => { set_value_sized(&mut self.state.d_reg[reg as usize], value, size); @@ -1597,7 +1620,7 @@ impl<'a> M68kCycleExecutor<'a> { Ok(()) } - fn get_target_address(&mut self, target: Target) -> Result { + fn get_target_address(&mut self, target: Target) -> Result> { let addr = match target { Target::IndirectAReg(reg) | Target::IndirectARegInc(reg) | Target::IndirectARegDec(reg) => *self.get_a_reg_mut(reg), Target::IndirectRegOffset(base_reg, index_reg, displacement) => { @@ -1652,47 +1675,49 @@ impl<'a> M68kCycleExecutor<'a> { *reg_addr } - fn get_address_sized(&mut self, addr: Address, size: Size) -> Result { - self.cycle.memory.read_data_sized(self.port, self.is_supervisor(), addr, size) + fn get_address_sized(&mut self, addr: Address, 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> { - self.cycle.memory.write_data_sized(self.port, self.is_supervisor(), addr, value, size) + fn set_address_sized(&mut self, addr: Address, 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) } - fn push_word(&mut self, value: u16) -> Result<(), M68kError> { + fn push_word(&mut self, value: u16) -> Result<(), M68kError> { *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)?; + self.port.write_beu16(self.cycle.current_clock, addr as Address, value).map_err(|err| M68kError::BusError(err))?; Ok(()) } - fn pop_word(&mut self) -> Result { + fn pop_word(&mut self) -> Result> { 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)?; + let value = self.port.read_beu16(self.cycle.current_clock, addr as Address).map_err(|err| M68kError::BusError(err))?; *self.get_stack_pointer_mut() += 2; Ok(value) } - fn push_long(&mut self, value: u32) -> Result<(), M68kError> { + fn push_long(&mut self, value: u32) -> Result<(), M68kError> { *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)?; + self.port.write_beu32(self.cycle.current_clock, addr as Address, value).map_err(|err| M68kError::BusError(err))?; Ok(()) } - fn pop_long(&mut self) -> Result { + fn pop_long(&mut self) -> Result> { 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)?; + let value = self.port.read_beu32(self.cycle.current_clock, addr as Address).map_err(|err| M68kError::BusError(err))?; *self.get_stack_pointer_mut() += 4; Ok(value) } - fn set_pc(&mut self, value: u32) -> Result<(), M68kError> { + fn set_pc(&mut self, value: u32) -> Result<(), M68kError> { self.state.pc = value; self.cycle.memory.start_request(self.is_supervisor(), self.state.pc, Size::Word, MemAccess::Read, MemType::Program, true)?; Ok(()) @@ -1769,7 +1794,7 @@ impl<'a> M68kCycleExecutor<'a> { self.state.sr & (Flags:: Supervisor as u16) != 0 } - fn require_supervisor(&self) -> Result<(), M68kError> { + fn require_supervisor(&self) -> Result<(), M68kError> { if self.is_supervisor() { Ok(()) } else { diff --git a/emulator/cpus/m68k/src/memory.rs b/emulator/cpus/m68k/src/memory.rs index 9a1c921..a58b09d 100644 --- a/emulator/cpus/m68k/src/memory.rs +++ b/emulator/cpus/m68k/src/memory.rs @@ -1,8 +1,8 @@ use femtos::Instant; -use emulator_hal::bus::{BusType, BusAccess}; +use emulator_hal::bus::{BusAccess}; -use moa_core::{Address, Addressable, BusPort}; +use moa_core::{Error, Address, Addressable}; use crate::state::{M68k, M68kError, Exceptions}; use crate::instructions::Size; @@ -76,7 +76,7 @@ impl Default for MemoryRequest { } impl MemoryRequest { - pub(crate) fn instruction(&mut self, is_supervisor: bool, addr: u32) -> Result { + pub(crate) fn instruction(&mut self, is_supervisor: bool, addr: u32) -> Result> { self.i_n_bit = false; self.code = FunctionCode::program(is_supervisor); self.access = MemAccess::Read; @@ -101,6 +101,8 @@ impl MemoryRequest { } } +//pub type M68kAddress = (FunctionCode, u32); +pub type M68kAddress = u64; #[derive(Clone, Debug)] pub struct InstructionRequest { @@ -110,7 +112,6 @@ pub struct InstructionRequest { #[derive(Clone, Debug)] pub struct M68kBusPort { - //pub port: BusPort, pub request: MemoryRequest, pub cycle_start_clock: Instant, pub current_clock: Instant, @@ -122,9 +123,8 @@ impl M68k { } impl Default for M68kBusPort { - fn default(/* port: BusPort */) -> Self { + fn default() -> Self { Self { - //port, request: Default::default(), cycle_start_clock: Instant::START, current_clock: Instant::START, @@ -141,35 +141,47 @@ impl M68kBusPort { } } - pub(crate) fn read_data_sized(&mut self, port: &mut BusPort, is_supervisor: bool, addr: Address, size: Size) -> Result { + pub(crate) fn read_data_sized(&mut self, port: &mut Bus, is_supervisor: bool, addr: Address, 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))?) } - pub(crate) fn write_data_sized(&mut self, port: &mut BusPort, 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: Address, value: u32, size: Size) -> 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))?) } - pub(crate) fn read_instruction_word(&mut self, port: &mut BusPort, is_supervisor: bool, addr: u32) -> Result { + pub(crate) fn read_instruction_word(&mut self, port: &mut Bus, is_supervisor: bool, addr: u32) -> Result> + where + Bus: BusAccess, + { self.request.instruction(is_supervisor, addr)?; - Ok(port.read_beu16(self.current_clock, addr as Address)?) + Ok(port.read_beu16(self.current_clock, addr as Address).map_err(|err| M68kError::BusError(err))?) } - pub(crate) fn read_instruction_long(&mut self, port: &mut BusPort, is_supervisor: bool, addr: u32) -> Result { + pub(crate) fn read_instruction_long(&mut self, port: &mut Bus, is_supervisor: bool, addr: u32) -> Result> + where + Bus: BusAccess, + { self.request.instruction(is_supervisor, addr)?; - Ok(port.read_beu32(self.current_clock, addr as Address)?) + Ok(port.read_beu32(self.current_clock, addr as Address).map_err(|err| M68kError::BusError(err))?) } - pub(crate) fn start_request(&mut self, is_supervisor: bool, addr: u32, size: Size, access: MemAccess, mtype: MemType, i_n_bit: bool) -> Result { + pub(crate) fn start_request(&mut self, is_supervisor: bool, addr: u32, size: Size, access: MemAccess, mtype: MemType, i_n_bit: bool) -> Result> { self.request.i_n_bit = i_n_bit; self.request.code = match mtype { MemType::Program => FunctionCode::program(is_supervisor), @@ -186,12 +198,16 @@ impl M68kBusPort { } } - pub(crate) fn dump_memory(&mut self, port: &mut BusPort, addr: u32, length: usize) { - port.dump_memory(self.current_clock, addr as Address, length as u64); + 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 { +fn validate_address(addr: u32) -> Result> { if addr & 0x1 == 0 { Ok(addr) } else { diff --git a/emulator/cpus/m68k/src/state.rs b/emulator/cpus/m68k/src/state.rs index 00a7f7b..0bfa069 100644 --- a/emulator/cpus/m68k/src/state.rs +++ b/emulator/cpus/m68k/src/state.rs @@ -1,6 +1,7 @@ use std::rc::Rc; use std::cell::RefCell; +use std::fmt::Display; use femtos::{Instant, Frequency}; use moa_core::{Address, Bus, BusPort}; @@ -178,7 +179,7 @@ pub struct M68kState { } #[derive(Clone, Debug, thiserror::Error)] -pub enum M68kError { +pub enum M68kError { #[error("cpu halted")] Halted, #[error("processor exception {0:?}")] @@ -189,6 +190,8 @@ pub enum M68kError { Breakpoint, #[error("invalid instruction target, direct value used as a pointer: {0:?}")] InvalidTarget(Target), + #[error("bus error")] + BusError(BusError), #[error("error: {0}")] Other(String), } diff --git a/emulator/cpus/m68k/src/timing.rs b/emulator/cpus/m68k/src/timing.rs index 1c45c9c..cd38386 100644 --- a/emulator/cpus/m68k/src/timing.rs +++ b/emulator/cpus/m68k/src/timing.rs @@ -9,6 +9,9 @@ pub struct M68kInstructionTiming { pub cputype: M68kType, pub bus_size: Size, + pub branched: bool, + pub reps: u16, + pub accesses: u8, pub internal: u8, pub on_branch: u8, @@ -22,6 +25,9 @@ impl M68kInstructionTiming { cputype, bus_size, + branched: false, + reps: 0, + accesses: 0, internal: 0, on_branch: 0, @@ -338,12 +344,27 @@ impl M68kInstructionTiming { self.add_internal(4) } - pub fn calculate_clocks(&self, branched: bool, reps: u16) -> ClockCycles { + pub fn performed_reset(&mut self) { + self.internal = 0; + self.accesses = 4; + self.branched = false; + self.reps = 0; + } + + pub fn increase_reps(&mut self, reps: u16) { + self.reps += reps; + } + + pub fn branch_taken(&mut self) { + self.branched = true; + } + + pub fn calculate_clocks(&self) -> ClockCycles { //println!("{:?}", self); (self.accesses as ClockCycles * 4) + self.internal as ClockCycles - + (if branched { self.on_branch as ClockCycles } else { 0 }) - + self.per_rep as ClockCycles * reps + + (if self.branched { self.on_branch as ClockCycles } else { 0 }) + + self.per_rep as ClockCycles * self.reps } #[inline(always)] diff --git a/emulator/cpus/z80/src/decode.rs b/emulator/cpus/z80/src/decode.rs index c394caa..2a9c5d5 100644 --- a/emulator/cpus/z80/src/decode.rs +++ b/emulator/cpus/z80/src/decode.rs @@ -6,18 +6,12 @@ use moa_core::{Address, Addressable}; use crate::state::Z80Error; use crate::instructions::{Direction, Condition, Register, RegisterPair, IndexRegister, IndexRegisterHalf, SpecialRegister, InterruptMode, Target, LoadTarget, UndocumentedCopy, Instruction}; -use emulator_hal::bus::{BusType, BusAccess}; +use emulator_hal::bus::{BusAccess}; struct Z80Bus; type Z80Address = (bool, u16); -impl BusType for Z80Bus { - //type Address = (bool, u16); - type Error = Z80Error; - type Instant = Instant; -} - #[derive(Clone)] pub struct Z80Decoder { pub clock: Instant, diff --git a/tests/harte_tests/latest.txt b/tests/harte_tests/latest.txt index a6c947f..d5ac00e 100644 --- a/tests/harte_tests/latest.txt +++ b/tests/harte_tests/latest.txt @@ -1,129 +1,129 @@ -Last run on 2022-09-18 at commit 94d3e1d3894e6588ff6daa55f0ba82473b1e74c7 +Last run on 2024-03-08 at commit b4a35641e4d52349f1d392f749da2e4af561a5e0 -ABCD.json completed: 7993 passed, 72 FAILED -ADD.b.json completed, all passed! -ADD.l.json completed: 7736 passed, 329 FAILED -ADD.w.json completed: 7712 passed, 353 FAILED -ADDA.l.json completed, all passed! -ADDA.w.json completed, all passed! -ADDX.b.json completed, all passed! -ADDX.l.json completed: 5472 passed, 2593 FAILED -ADDX.w.json completed, all passed! -AND.b.json completed, all passed! -AND.l.json completed: 7779 passed, 286 FAILED -AND.w.json completed: 7764 passed, 301 FAILED -ANDItoCCR.json completed, all passed! -ANDItoSR.json completed, all passed! -ASL.b.json completed: 7238 passed, 827 FAILED -ASL.l.json completed: 6471 passed, 1594 FAILED -ASL.w.json completed: 7053 passed, 1012 FAILED -ASR.b.json completed: 7547 passed, 518 FAILED -ASR.l.json completed: 7092 passed, 973 FAILED -ASR.w.json completed: 7513 passed, 552 FAILED -BCHG.json completed, all passed! -BCLR.json completed, all passed! -BSET.json completed, all passed! -BSR.json completed, all passed! -BTST.json completed: 8052 passed, 13 FAILED -Bcc.json completed, all passed! -CHK.json completed: 7744 passed, 321 FAILED -CLR.b.json completed, all passed! -CLR.l.json completed: 7472 passed, 593 FAILED -CLR.w.json completed: 7465 passed, 600 FAILED -CMP.b.json completed, all passed! -CMP.l.json completed, all passed! -CMP.w.json completed, all passed! -CMPA.l.json completed, all passed! -CMPA.w.json completed, all passed! -DBcc.json completed, all passed! -DIVS.json completed, all passed! -DIVU.json completed: 8064 passed, 1 FAILED -EOR.b.json completed, all passed! -EOR.l.json completed: 7519 passed, 546 FAILED -EOR.w.json completed: 7525 passed, 540 FAILED -EORItoCCR.json completed, all passed! -EORItoSR.json completed, all passed! -EXG.json completed, all passed! -EXT.l.json completed, all passed! -EXT.w.json completed, all passed! -JMP.json completed, all passed! -JSR.json completed, all passed! -LEA.json completed, all passed! -LINK.json completed, all passed! -LSL.b.json completed: 7809 passed, 256 FAILED -LSL.l.json completed: 7056 passed, 1009 FAILED -LSL.w.json completed: 7523 passed, 542 FAILED -LSR.b.json completed: 7817 passed, 248 FAILED -LSR.l.json completed: 7072 passed, 993 FAILED -LSR.w.json completed: 7541 passed, 524 FAILED -MOVE.b.json completed, all passed! -MOVE.l.json completed: 5827 passed, 2238 FAILED -MOVE.q.json completed, all passed! -MOVE.w.json completed: 5855 passed, 2210 FAILED -MOVEA.l.json completed, all passed! -MOVEA.w.json completed, all passed! -MOVEM.l.json completed: 6035 passed, 2030 FAILED -MOVEM.w.json completed: 6431 passed, 1634 FAILED -MOVEP.l.json completed: 4036 passed, 4029 FAILED -MOVEP.w.json completed: 4046 passed, 4019 FAILED -MOVEfromSR.json completed: 6896 passed, 1169 FAILED -MOVEfromUSP.json completed, all passed! -MOVEtoCCR.json completed, all passed! -MOVEtoSR.json completed, all passed! -MOVEtoUSP.json completed, all passed! -MULS.json completed, all passed! -MULU.json completed, all passed! -NBCD.json completed: 8037 passed, 28 FAILED -NEG.b.json completed, all passed! -NEG.l.json completed: 7552 passed, 513 FAILED -NEG.w.json completed: 7531 passed, 534 FAILED -NEGX.b.json completed, all passed! -NEGX.l.json completed: 7520 passed, 545 FAILED -NEGX.w.json completed: 7510 passed, 555 FAILED -NOP.json completed, all passed! -NOT.b.json completed, all passed! -NOT.l.json completed: 7512 passed, 553 FAILED -NOT.w.json completed: 7530 passed, 535 FAILED -OR.b.json completed, all passed! -OR.l.json completed: 7756 passed, 309 FAILED -OR.w.json completed: 7765 passed, 300 FAILED -ORItoCCR.json completed, all passed! -ORItoSR.json completed, all passed! -PEA.json completed, all passed! -RESET.json completed, all passed! -ROL.b.json completed, all passed! -ROL.l.json completed, all passed! -ROL.w.json completed: 7882 passed, 183 FAILED -ROR.b.json completed, all passed! -ROR.l.json completed, all passed! -ROR.w.json completed: 7907 passed, 158 FAILED -ROXL.b.json completed: 8039 passed, 26 FAILED -ROXL.l.json completed: 8029 passed, 36 FAILED -ROXL.w.json completed: 7892 passed, 173 FAILED -ROXR.b.json completed: 8037 passed, 28 FAILED -ROXR.l.json completed: 8022 passed, 43 FAILED -ROXR.w.json completed: 7880 passed, 185 FAILED -RTE.json completed, all passed! -RTR.json completed, all passed! -RTS.json completed, all passed! -SBCD.json completed: 6809 passed, 1256 FAILED -SUB.b.json completed, all passed! -SUB.l.json completed: 7747 passed, 318 FAILED -SUB.w.json completed: 7716 passed, 349 FAILED -SUBA.l.json completed, all passed! -SUBA.w.json completed, all passed! -SUBX.b.json completed, all passed! -SUBX.l.json completed: 5481 passed, 2584 FAILED -SUBX.w.json completed, all passed! -SWAP.json completed, all passed! -Scc.json completed, all passed! -TAS.json completed, all passed! -TRAP.json completed, all passed! -TRAPV.json completed, all passed! -TST.b.json completed, all passed! -TST.l.json completed, all passed! -TST.w.json completed, all passed! -UNLINK.json completed, all passed! +ABCD.json.gz completed: 7993 passed, 72 FAILED +ADD.b.json.gz completed, all passed! +ADD.l.json.gz completed: 7736 passed, 329 FAILED +ADD.w.json.gz completed: 7712 passed, 353 FAILED +ADDA.l.json.gz completed, all passed! +ADDA.w.json.gz completed, all passed! +ADDX.b.json.gz completed, all passed! +ADDX.l.json.gz completed: 5472 passed, 2593 FAILED +ADDX.w.json.gz completed, all passed! +AND.b.json.gz completed, all passed! +AND.l.json.gz completed: 7779 passed, 286 FAILED +AND.w.json.gz completed: 7764 passed, 301 FAILED +ANDItoCCR.json.gz completed, all passed! +ANDItoSR.json.gz completed, all passed! +ASL.b.json.gz completed: 8063 passed, 2 FAILED +ASL.l.json.gz completed, all passed! +ASL.w.json.gz completed: 7896 passed, 169 FAILED +ASR.b.json.gz completed: 7783 passed, 282 FAILED +ASR.l.json.gz completed: 8029 passed, 36 FAILED +ASR.w.json.gz completed: 7891 passed, 174 FAILED +BCHG.json.gz completed, all passed! +BCLR.json.gz completed, all passed! +BSET.json.gz completed, all passed! +BSR.json.gz completed, all passed! +BTST.json.gz completed: 8052 passed, 13 FAILED +Bcc.json.gz completed, all passed! +CHK.json.gz completed: 7744 passed, 321 FAILED +CLR.b.json.gz completed, all passed! +CLR.l.json.gz completed: 7472 passed, 593 FAILED +CLR.w.json.gz completed: 7465 passed, 600 FAILED +CMP.b.json.gz completed, all passed! +CMP.l.json.gz completed, all passed! +CMP.w.json.gz completed, all passed! +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: 957924, failed: 42136, total 96% -completed in 24m 47s +passed: 966037, failed: 34023, total 97% +completed in 14m 25s diff --git a/tests/harte_tests/src/main.rs b/tests/harte_tests/src/main.rs index 0c4490b..45aec0e 100644 --- a/tests/harte_tests/src/main.rs +++ b/tests/harte_tests/src/main.rs @@ -150,7 +150,7 @@ fn init_execute_test(cputype: M68kType, state: &TestState) -> Result<(M68k, Syst } else { BusPort::new(0, 32, 32, system.bus.clone()) }; - let mut cpu = M68k::new(cputype, Frequency::from_mhz(10), port); + let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0); cpu.state.status = Status::Running; load_state(&mut cpu, &mut system, state)?; @@ -226,7 +226,7 @@ fn assert_state(cpu: &M68k, system: &System, expected: &TestState) -> Result<(), assert_value(cpu.state.sr, expected.sr, "sr")?; assert_value(cpu.state.pc, expected.pc, "pc")?; - let addr_mask = cpu.port.port.address_mask(); + let addr_mask = cpu.port.address_mask(); // Load instructions into memory for (i, ins) in expected.prefetch.iter().enumerate() { @@ -246,7 +246,7 @@ fn assert_state(cpu: &M68k, system: &System, expected: &TestState) -> Result<(), fn step_cpu_and_assert(cpu: &mut M68k, system: &System, case: &TestCase, test_timing: bool) -> Result<(), Error> { let clock_elapsed = cpu.step(&system)?; - let cycles = clock_elapsed / cpu.frequency.period_duration(); + let cycles = clock_elapsed / cpu.info.frequency.period_duration(); assert_state(&cpu, &system, &case.final_state)?; @@ -269,8 +269,8 @@ fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> { if args.debug { case.dump(); println!(""); - initial_cpu.dump_state(); - cpu.dump_state(); + //initial_cpu.dump_state(); + //cpu.dump_state(); } println!("FAILED: {:?}", err); } diff --git a/todo.txt b/todo.txt index 5fd526f..28439d1 100644 --- a/todo.txt +++ b/todo.txt @@ -2,10 +2,16 @@ * 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 + +* move the BusPort breakup code to m68k +* implement BusAccess for BusPort * move the interrupt controller logic to the step() function only, and have a customish interrupt interface into the sim * move the impls for Step, Transmutable, etc into a moa.rs file or something * the remaining code should really use Addressable, and then we can swap it for BusAccess +* could you use the m68k cpu status enum for interrupts, and start handling the interrupt in the next step? but that will affect tests and behaviour if it takes two steps + to get to the same point... + * the idea would be, instead of argument drilling, you create an object that is short lived, that lasts one instruction, or possibly even parts of one instruction, and it has some references instead of "moving" data (or if you move, you move and move out without cloning), such that you can bundle everything up, call a method on the bundle, with the execution context and state all part of or reference by the bundle, all instructions would be implemented on the bundle and not the state alone, and From ec74b64984353ca46ef1d275de4d6759c91cc1bf Mon Sep 17 00:00:00 2001 From: transistor Date: Fri, 8 Mar 2024 23:38:51 -0800 Subject: [PATCH 2/9] Added stats --- emulator/cpus/m68k/src/execute.rs | 9 +++++++++ emulator/cpus/m68k/src/state.rs | 19 +++++++++++++++++++ tests/harte_tests/latest.txt | 4 ++-- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/emulator/cpus/m68k/src/execute.rs b/emulator/cpus/m68k/src/execute.rs index d4c9232..e9161e0 100644 --- a/emulator/cpus/m68k/src/execute.rs +++ b/emulator/cpus/m68k/src/execute.rs @@ -37,6 +37,7 @@ pub enum Used { #[derive(Clone, Debug)] pub struct M68kCycle { + pub decoder: M68kDecoder, pub timing: M68kInstructionTiming, pub memory: M68kBusPort, @@ -67,6 +68,14 @@ impl M68kCycle { #[inline] pub fn begin<'a>(mut self, cpu: &'a mut M68k) -> M68kCycleExecutor<'a, bus::BusAdapter> { + 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; + let now = std::time::SystemTime::now(); + log::warn!("{} per million", now.duration_since(cpu.stats.last_time).unwrap().as_micros()); + cpu.stats.last_time = now; + } + let adapter = bus::BusAdapter { bus: &mut cpu.port, translate: translate_address, diff --git a/emulator/cpus/m68k/src/state.rs b/emulator/cpus/m68k/src/state.rs index 0bfa069..4c07f99 100644 --- a/emulator/cpus/m68k/src/state.rs +++ b/emulator/cpus/m68k/src/state.rs @@ -196,12 +196,30 @@ pub enum M68kError { Other(String), } +#[derive(Clone)] +pub struct M68kStatistics { + pub cycle_number: usize, + pub last_update: usize, + pub last_time: std::time::SystemTime, +} + +impl Default for M68kStatistics { + fn default() -> Self { + Self { + cycle_number: 0, + last_update: 0, + last_time: std::time::SystemTime::now(), + } + } +} + #[derive(Clone)] pub struct M68k { pub info: CpuInfo, pub state: M68kState, pub debugger: M68kDebugger, pub port: BusPort, + pub stats: M68kStatistics, pub cycle: Option, } @@ -231,6 +249,7 @@ impl M68k { state: M68kState::default(), debugger: M68kDebugger::default(), port, + stats: Default::default(), cycle: None, } } diff --git a/tests/harte_tests/latest.txt b/tests/harte_tests/latest.txt index d5ac00e..293981f 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 b4a35641e4d52349f1d392f749da2e4af561a5e0 +Last run on 2024-03-08 at commit 8b274f72ccf6f143e527cb95552f80deedc2fc64 ABCD.json.gz completed: 7993 passed, 72 FAILED ADD.b.json.gz completed, all passed! @@ -126,4 +126,4 @@ TST.w.json.gz completed, all passed! UNLINK.json.gz completed, all passed! passed: 966037, failed: 34023, total 97% -completed in 14m 25s +completed in 13m 59s From e0330d41a5c62b3395225ae4c20e518316896bde Mon Sep 17 00:00:00 2001 From: transistor Date: Sat, 9 Mar 2024 23:58:07 -0800 Subject: [PATCH 3/9] Added some fixes --- emulator/core/src/memory.rs | 6 +----- emulator/cpus/m68k/src/decode.rs | 2 +- emulator/cpus/m68k/src/execute.rs | 14 +++++++------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/emulator/core/src/memory.rs b/emulator/core/src/memory.rs index 52db709..dd411f7 100644 --- a/emulator/core/src/memory.rs +++ b/emulator/core/src/memory.rs @@ -360,11 +360,7 @@ pub fn dump_slice(data: &[u8], mut count: usize) { use emulator_hal::bus::{self, BusAccess}; -//impl bus::Error for Error {} - -//impl ErrorType for BusPort { -// type Error = Error; -//} +impl bus::Error for Error {} impl BusAccess for BusPort { type Error = Error; diff --git a/emulator/cpus/m68k/src/decode.rs b/emulator/cpus/m68k/src/decode.rs index 5699240..43e0956 100644 --- a/emulator/cpus/m68k/src/decode.rs +++ b/emulator/cpus/m68k/src/decode.rs @@ -1,6 +1,6 @@ use femtos::Instant; -use emulator_hal::bus::{self, BusAccess, BusError}; +use emulator_hal::bus::{self, BusAccess, Error as BusError}; use moa_core::{Error, Address, Addressable}; diff --git a/emulator/cpus/m68k/src/execute.rs b/emulator/cpus/m68k/src/execute.rs index e9161e0..39a9355 100644 --- a/emulator/cpus/m68k/src/execute.rs +++ b/emulator/cpus/m68k/src/execute.rs @@ -67,7 +67,7 @@ impl M68kCycle { } #[inline] - pub fn begin<'a>(mut self, cpu: &'a mut M68k) -> M68kCycleExecutor<'a, bus::BusAdapter> { + pub fn begin<'a>(mut self, cpu: &'a mut M68k) -> M68kCycleExecutor<'a, bus::BusAdapter> { 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,11 +76,11 @@ impl M68kCycle { cpu.stats.last_time = now; } - let adapter = bus::BusAdapter { - bus: &mut cpu.port, - translate: translate_address, - instant: core::marker::PhantomData, - }; + let adapter = bus::BusAdapter::new( + &mut cpu.port, + translate_address, + |err| err, + ); M68kCycleExecutor { state: &mut cpu.state, @@ -162,7 +162,7 @@ impl Transmutable for M68k { } } -impl From> for Error { +impl From> for Error { fn from(err: M68kError) -> Self { match err { M68kError::Halted => Self::Other("cpu halted".to_string()), From af1c660dc0682a62c123b1d7577f2ce2b5f3d8ad Mon Sep 17 00:00:00 2001 From: transistor Date: Sun, 10 Mar 2024 00:06:22 -0800 Subject: [PATCH 4/9] Modified to use submodule for emulator-hal --- .gitmodules | 3 +++ Cargo.lock | 19 +++++++++++++++++++ emulator/core/Cargo.toml | 2 +- emulator/cpus/m68k/Cargo.toml | 2 +- emulator/cpus/z80/Cargo.toml | 2 +- emulator/libraries/emulator-hal | 1 + 6 files changed, 26 insertions(+), 3 deletions(-) create mode 160000 emulator/libraries/emulator-hal diff --git a/.gitmodules b/.gitmodules index cb2b5ae..7b6d891 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "emulator/libraries/femtos"] path = emulator/libraries/femtos url = git@github.com:transistorfet/femtos.git +[submodule "emulator/libraries/emulator-hal"] + path = emulator/libraries/emulator-hal + url = git@github.com:transistorfet/emulator-hal.git diff --git a/Cargo.lock b/Cargo.lock index d71adab..1c2f7d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -420,6 +420,10 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "emulator-hal" version = "0.1.0" +dependencies = [ + "femtos", + "fugit", +] [[package]] name = "env_logger" @@ -480,6 +484,21 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "fugit" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7" +dependencies = [ + "gcd", +] + +[[package]] +name = "gcd" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" + [[package]] name = "glob" version = "0.3.1" diff --git a/emulator/core/Cargo.toml b/emulator/core/Cargo.toml index c3cb2e7..ec434d7 100644 --- a/emulator/core/Cargo.toml +++ b/emulator/core/Cargo.toml @@ -8,4 +8,4 @@ log = "0.4" femtos = "0.1" thiserror = "1.0" moa-host = { path = "../libraries/host" } -emulator-hal = { path = "/media/work/projects/emulator-hal/emulator-hal" } +emulator-hal = { path = "../libraries/emulator-hal/emulator-hal" } diff --git a/emulator/cpus/m68k/Cargo.toml b/emulator/cpus/m68k/Cargo.toml index 483a72f..6124799 100644 --- a/emulator/cpus/m68k/Cargo.toml +++ b/emulator/cpus/m68k/Cargo.toml @@ -9,4 +9,4 @@ thiserror = "1.0" femtos = "0.1" moa-core = { path = "../../core" } moa-parsing = { path = "../../libraries/parsing" } -emulator-hal = { path = "/media/work/projects/emulator-hal/emulator-hal" } +emulator-hal = { path = "../../libraries/emulator-hal/emulator-hal" } diff --git a/emulator/cpus/z80/Cargo.toml b/emulator/cpus/z80/Cargo.toml index 0478736..29a194d 100644 --- a/emulator/cpus/z80/Cargo.toml +++ b/emulator/cpus/z80/Cargo.toml @@ -9,4 +9,4 @@ thiserror = "1.0" femtos = "0.1" moa-core = { path = "../../core" } moa-signals = { path = "../../libraries/signals" } -emulator-hal = { path = "/media/work/projects/emulator-hal/emulator-hal" } +emulator-hal = { path = "../../libraries/emulator-hal/emulator-hal" } diff --git a/emulator/libraries/emulator-hal b/emulator/libraries/emulator-hal new file mode 160000 index 0000000..84e665c --- /dev/null +++ b/emulator/libraries/emulator-hal @@ -0,0 +1 @@ +Subproject commit 84e665ce5749187d0c323f77971c288d0964fa96 From 545f339fe2714cc648bd4a01506518a13c1faf39 Mon Sep 17 00:00:00 2001 From: transistor Date: Wed, 13 Mar 2024 21:49:04 -0700 Subject: [PATCH 5/9] 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 From 59306bceff1a5964902118f33034086a349e2fd3 Mon Sep 17 00:00:00 2001 From: transistor Date: Thu, 14 Mar 2024 22:35:02 -0700 Subject: [PATCH 6/9] Fixed alloc in harte_tests that was taking all the time --- Cargo.lock | 9 ++ emulator/core/src/error.rs | 5 +- emulator/cpus/m68k/Cargo.toml | 2 +- emulator/cpus/m68k/src/bin/m68kas.rs | 2 +- emulator/cpus/m68k/src/debugger.rs | 5 +- emulator/cpus/m68k/src/decode.rs | 22 ++--- emulator/cpus/m68k/src/execute.rs | 58 +++++++++--- emulator/cpus/m68k/src/memory.rs | 16 ++-- emulator/cpus/m68k/src/moa.rs | 6 +- emulator/cpus/m68k/src/state.rs | 2 +- .../frontends/console/src/bin/moa-bench.rs | 2 +- .../frontends/console/src/bin/moa-computie.rs | 2 +- .../console/src/bin/moa-console-genesis.rs | 2 +- emulator/frontends/console/src/lib.rs | 6 +- tests/harte_tests/Cargo.toml | 4 + tests/harte_tests/latest.txt | 92 ++++++++++++++++++- tests/harte_tests/src/main.rs | 76 ++++++++------- 17 files changed, 227 insertions(+), 84 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 38dd4a3..94c30ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -425,6 +425,13 @@ dependencies = [ "fugit", ] +[[package]] +name = "emulator-hal-memory" +version = "0.1.0" +dependencies = [ + "emulator-hal", +] + [[package]] name = "env_logger" version = "0.8.4" @@ -510,6 +517,8 @@ name = "harte-tests" version = "0.1.0" dependencies = [ "clap 3.2.25", + "emulator-hal", + "emulator-hal-memory", "femtos", "flate2", "moa-core", diff --git a/emulator/core/src/error.rs b/emulator/core/src/error.rs index d438343..0ffe7f6 100644 --- a/emulator/core/src/error.rs +++ b/emulator/core/src/error.rs @@ -1,10 +1,7 @@ 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, @@ -78,7 +75,7 @@ impl fmt::Display for Error { impl From> for Error { fn from(err: HostError) -> Self { - Self::Other(format!("other")) + Self::Other("other".to_string()) } } diff --git a/emulator/cpus/m68k/Cargo.toml b/emulator/cpus/m68k/Cargo.toml index 12bcfe0..6143ee6 100644 --- a/emulator/cpus/m68k/Cargo.toml +++ b/emulator/cpus/m68k/Cargo.toml @@ -13,4 +13,4 @@ emulator-hal = { path = "../../libraries/emulator-hal/emulator-hal" } moa-core = { path = "../../core", optional = true } [features] -moa = [] +moa = ["moa-core"] diff --git a/emulator/cpus/m68k/src/bin/m68kas.rs b/emulator/cpus/m68k/src/bin/m68kas.rs index 9cb662c..5681b9b 100644 --- a/emulator/cpus/m68k/src/bin/m68kas.rs +++ b/emulator/cpus/m68k/src/bin/m68kas.rs @@ -17,7 +17,7 @@ fn main() { for word in words.iter() { print!("{:04x} ", word); } - println!(""); + println!(); }, Err(err) => { println!("{:?}", err); diff --git a/emulator/cpus/m68k/src/debugger.rs b/emulator/cpus/m68k/src/debugger.rs index a5ebc54..827dfb5 100644 --- a/emulator/cpus/m68k/src/debugger.rs +++ b/emulator/cpus/m68k/src/debugger.rs @@ -1,9 +1,8 @@ use femtos::Instant; -use emulator_hal::bus::{self, BusAccess}; +use emulator_hal::bus::BusAccess; -use super::state::{M68k, M68kError}; -use super::decode::M68kDecoder; +use super::state::M68kError; use super::execute::M68kCycleExecutor; use super::memory::M68kAddress; diff --git a/emulator/cpus/m68k/src/decode.rs b/emulator/cpus/m68k/src/decode.rs index 8ab5930..83e965a 100644 --- a/emulator/cpus/m68k/src/decode.rs +++ b/emulator/cpus/m68k/src/decode.rs @@ -52,7 +52,7 @@ pub struct InstructionDecoding<'a, Bus> where Bus: BusAccess, { - pub(crate) port: &'a mut Bus, + pub(crate) bus: &'a mut Bus, pub(crate) memory: &'a mut M68kBusPort, pub(crate) decoder: &'a mut M68kDecoder, } @@ -78,13 +78,13 @@ impl M68kDecoder { } #[inline] - pub fn decode_at(&mut self, port: &mut Bus, memory: &mut M68kBusPort, is_supervisor: bool, start: u32) -> Result<(), M68kError> + pub fn decode_at(&mut self, bus: &mut Bus, memory: &mut M68kBusPort, is_supervisor: bool, start: u32) -> Result<(), M68kError> where Bus: BusAccess, { self.init(is_supervisor, start); let mut decoding = InstructionDecoding { - port, + bus, memory, decoder: self, }; @@ -92,22 +92,22 @@ impl M68kDecoder { Ok(()) } - pub fn dump_disassembly(&mut self, port: &mut Bus, memory: &mut M68kBusPort, start: u32, length: u32) + pub fn dump_disassembly(&mut self, bus: &mut Bus, memory: &mut M68kBusPort, start: u32, length: u32) where Bus: BusAccess, { let mut next = start; while next < (start + length) { - match self.decode_at(port, memory, self.is_supervisor, next) { + match self.decode_at(bus, memory, self.is_supervisor, next) { Ok(()) => { - self.dump_decoded(memory.current_clock, port); + self.dump_decoded(memory.current_clock, bus); next = self.end; }, Err(err) => { 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).unwrap()); + println!(" at {:08x}: {:04x}", self.start, bus.read_beu16(memory.current_clock, self.start).unwrap()); }, _ => { }, } @@ -117,13 +117,13 @@ impl M68kDecoder { } } - pub fn dump_decoded(&mut self, clock: Instant, port: &mut Bus) + pub fn dump_decoded(&mut self, clock: Instant, bus: &mut Bus) where Bus: BusAccess, { let ins_data: Result> = (0..((self.end - self.start) / 2)).map(|offset| - Ok(format!("{:04x} ", port.read_beu16(clock, self.start + (offset * 2)).unwrap())) + Ok(format!("{:04x} ", bus.read_beu16(clock, self.start + (offset * 2)).unwrap())) ).collect(); println!("{:#010x}: {}\n\t{}\n", self.start, ins_data.unwrap(), self.instruction); } @@ -731,13 +731,13 @@ where } fn read_instruction_word(&mut self) -> Result> { - let word = self.memory.read_instruction_word(self.port, self.decoder.is_supervisor, self.decoder.end)?; + let word = self.memory.read_instruction_word(self.bus, self.decoder.is_supervisor, self.decoder.end)?; self.decoder.end += 2; Ok(word) } fn read_instruction_long(&mut self) -> Result> { - let word = self.memory.read_instruction_long(self.port, self.decoder.is_supervisor, self.decoder.end)?; + let word = self.memory.read_instruction_long(self.bus, self.decoder.is_supervisor, self.decoder.end)?; self.decoder.end += 4; Ok(word) } diff --git a/emulator/cpus/m68k/src/execute.rs b/emulator/cpus/m68k/src/execute.rs index da852cb..7fb1e91 100644 --- a/emulator/cpus/m68k/src/execute.rs +++ b/emulator/cpus/m68k/src/execute.rs @@ -1,6 +1,7 @@ use femtos::Instant; -use emulator_hal::bus::BusAccess; +use emulator_hal::bus::{self, BusAccess}; +use emulator_hal::step::Step; use crate::state::{M68k, M68kType, M68kError, M68kState, Status, Flags, Exceptions, InterruptPriority}; use crate::memory::{MemType, MemAccess, M68kBusPort, M68kAddress}; @@ -64,7 +65,7 @@ impl M68kCycle { } #[inline] - pub fn begin<'a, Bus>(mut self, cpu: &'a mut M68k, bus: Bus) -> M68kCycleExecutor<'a, Bus> + pub fn begin(self, cpu: &mut M68k, bus: Bus) -> M68kCycleExecutor<'_, Bus> where Bus: BusAccess, { @@ -78,19 +79,52 @@ impl M68kCycle { M68kCycleExecutor { state: &mut cpu.state, - port: bus, + bus: bus, debugger: &mut cpu.debugger, cycle: self, } } } +impl Step for M68k +where + BusError: bus::Error, + Bus: BusAccess, +{ + type Error = M68kError; + + fn is_running(&mut self) -> bool { + self.state.status == Status::Running + } + + fn reset(&mut self, now: Instant, bus: &mut Bus) -> Result<(), Self::Error> { + Ok(()) + } + + fn step(&mut self, now: Instant, bus: &mut Bus) -> Result { + let cycle = M68kCycle::new(self, now); + + let mut executor = cycle.begin(self, &mut *bus); + 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(now + self.last_cycle_duration()) + } +} + pub struct M68kCycleExecutor<'a, Bus> where Bus: BusAccess, { pub state: &'a mut M68kState, - pub port: Bus, + pub bus: Bus, pub debugger: &'a mut M68kDebugger, pub cycle: M68kCycle, } @@ -298,7 +332,7 @@ where #[inline] pub fn decode_next(&mut self) -> Result<(), M68kError> { let is_supervisor = self.is_supervisor(); - self.cycle.decoder.decode_at(&mut self.port, &mut self.cycle.memory, is_supervisor, self.state.pc)?; + self.cycle.decoder.decode_at(&mut self.bus, &mut self.cycle.memory, is_supervisor, self.state.pc)?; self.cycle.timing.add_instruction(&self.cycle.decoder.instruction); @@ -1604,26 +1638,26 @@ where 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) + self.cycle.memory.read_data_sized(&mut self.bus, is_supervisor, addr, size) } 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, size, value) + self.cycle.memory.write_data_sized(&mut self.bus, 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.write_data_sized(&mut self.port, is_supervisor, addr, Size::Word, value as u32)?; + self.cycle.memory.write_data_sized(&mut self.bus, 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(); - let value = self.cycle.memory.read_data_sized(&mut self.port, is_supervisor, addr, Size::Word)?; + let value = self.cycle.memory.read_data_sized(&mut self.bus, is_supervisor, addr, Size::Word)?; *self.get_stack_pointer_mut() += 2; Ok(value as u16) } @@ -1632,14 +1666,14 @@ where let is_supervisor = self.is_supervisor(); *self.get_stack_pointer_mut() -= 4; let addr = *self.get_stack_pointer_mut(); - self.cycle.memory.write_data_sized(&mut self.port, is_supervisor, addr, Size::Long, value)?; + self.cycle.memory.write_data_sized(&mut self.bus, 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(); - let value = self.cycle.memory.read_data_sized(&mut self.port, is_supervisor, addr, Size::Long)?; + let value = self.cycle.memory.read_data_sized(&mut self.bus, is_supervisor, addr, Size::Long)?; *self.get_stack_pointer_mut() += 4; Ok(value) } @@ -1677,7 +1711,7 @@ where match base_reg { BaseRegister::None => 0, BaseRegister::PC => self.cycle.decoder.start + 2, - BaseRegister::AReg(reg) if reg == 7 => if self.is_supervisor() { self.state.ssp } else { self.state.usp }, + BaseRegister::AReg(7) => if self.is_supervisor() { self.state.ssp } else { self.state.usp }, BaseRegister::AReg(reg) => self.state.a_reg[reg as usize], } } diff --git a/emulator/cpus/m68k/src/memory.rs b/emulator/cpus/m68k/src/memory.rs index d9783c2..6f1e7b1 100644 --- a/emulator/cpus/m68k/src/memory.rs +++ b/emulator/cpus/m68k/src/memory.rs @@ -200,36 +200,36 @@ impl M68kBusPort { } } - pub(crate) fn read_data_sized(&mut self, port: &mut Bus, is_supervisor: bool, addr: M68kAddress, size: Size) -> Result> + pub(crate) fn read_data_sized(&mut self, bus: &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)?; - self.read_sized(port, addr, size) + self.read_sized(bus, addr, size) } - pub(crate) fn write_data_sized(&mut self, port: &mut Bus, is_supervisor: bool, addr: M68kAddress, size: Size, value: u32) -> Result<(), M68kError> + pub(crate) fn write_data_sized(&mut self, bus: &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)?; - self.write_sized(port, addr, size, value) + self.write_sized(bus, addr, size, value) } - pub(crate) fn read_instruction_word(&mut self, port: &mut Bus, is_supervisor: bool, addr: u32) -> Result> + pub(crate) fn read_instruction_word(&mut self, bus: &mut Bus, is_supervisor: bool, addr: u32) -> Result> where Bus: BusAccess, { self.request.instruction(is_supervisor, addr)?; - Ok(self.read_sized(port, addr, Size::Word)? as u16) + Ok(self.read_sized(bus, addr, Size::Word)? as u16) } - pub(crate) fn read_instruction_long(&mut self, port: &mut Bus, is_supervisor: bool, addr: u32) -> Result> + pub(crate) fn read_instruction_long(&mut self, bus: &mut Bus, is_supervisor: bool, addr: u32) -> Result> where Bus: BusAccess, { self.request.instruction(is_supervisor, addr)?; - self.read_sized(port, addr, Size::Long) + self.read_sized(bus, 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> { diff --git a/emulator/cpus/m68k/src/moa.rs b/emulator/cpus/m68k/src/moa.rs index 7caf40b..76940b1 100644 --- a/emulator/cpus/m68k/src/moa.rs +++ b/emulator/cpus/m68k/src/moa.rs @@ -94,15 +94,15 @@ impl Debuggable for M68k { 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); + //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.port, self.cycle.memory, addr as u32, count as u32); + //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 { diff --git a/emulator/cpus/m68k/src/state.rs b/emulator/cpus/m68k/src/state.rs index 91de783..04249fc 100644 --- a/emulator/cpus/m68k/src/state.rs +++ b/emulator/cpus/m68k/src/state.rs @@ -272,7 +272,7 @@ impl M68k { 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); + //memory::dump_memory(&mut self.bus, self.cycle.current_clock, self.state.ssp, 0x40); println!(); } diff --git a/emulator/frontends/console/src/bin/moa-bench.rs b/emulator/frontends/console/src/bin/moa-bench.rs index 5391d09..366feef 100644 --- a/emulator/frontends/console/src/bin/moa-bench.rs +++ b/emulator/frontends/console/src/bin/moa-bench.rs @@ -28,7 +28,7 @@ fn main() { system.add_addressable_device(0x00700000, Device::new(serial)).unwrap(); - let cpu = M68k::from_type(M68kType::MC68010, Frequency::from_mhz(8), system.bus.clone(), 0); + let cpu = M68k::from_type(M68kType::MC68010, Frequency::from_mhz(8)); //cpu.enable_tracing(); //cpu.add_breakpoint(0x10781a); diff --git a/emulator/frontends/console/src/bin/moa-computie.rs b/emulator/frontends/console/src/bin/moa-computie.rs index 1331894..eafe886 100644 --- a/emulator/frontends/console/src/bin/moa-computie.rs +++ b/emulator/frontends/console/src/bin/moa-computie.rs @@ -18,7 +18,7 @@ fn main() { options.rom = filename.to_string(); } - let mut frontend = ConsoleFrontend::new(); + let mut frontend = ConsoleFrontend::default(); let system = build_computie(&mut frontend, options).unwrap(); frontend.start(matches, system); diff --git a/emulator/frontends/console/src/bin/moa-console-genesis.rs b/emulator/frontends/console/src/bin/moa-console-genesis.rs index 9b4c8b7..561129a 100644 --- a/emulator/frontends/console/src/bin/moa-console-genesis.rs +++ b/emulator/frontends/console/src/bin/moa-console-genesis.rs @@ -10,7 +10,7 @@ fn main() { .help("ROM file to load (must be flat binary)")) .get_matches(); - let mut frontend = ConsoleFrontend::new(); + let mut frontend = ConsoleFrontend::default(); let mut options = SegaGenesisOptions::default(); if let Some(filename) = matches.get_one::("ROM") { diff --git a/emulator/frontends/console/src/lib.rs b/emulator/frontends/console/src/lib.rs index bbe80a4..b7c08d8 100644 --- a/emulator/frontends/console/src/lib.rs +++ b/emulator/frontends/console/src/lib.rs @@ -33,11 +33,13 @@ impl Host for ConsoleFrontend { } } -impl ConsoleFrontend { - pub fn new() -> Self { +impl Default for ConsoleFrontend { + fn default() -> Self { Self } +} +impl ConsoleFrontend { pub fn args(application_name: &'static str) -> Command { Command::new(application_name) .arg(Arg::new("log-level") diff --git a/tests/harte_tests/Cargo.toml b/tests/harte_tests/Cargo.toml index d7af02b..7b35f4c 100644 --- a/tests/harte_tests/Cargo.toml +++ b/tests/harte_tests/Cargo.toml @@ -5,9 +5,13 @@ edition = "2021" [dependencies] femtos = "0.1" +emulator-hal = { path = "../../emulator/libraries/emulator-hal/emulator-hal" } +emulator-hal-memory = { path = "../../emulator/libraries/emulator-hal/emulator-hal-memory" } moa-core = { path = "../../emulator/core" } moa-m68k = { path = "../../emulator/cpus/m68k", features = ["moa"] } + +#thiserror = "1.0" 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 3db3c97..2f284a3 100644 --- a/tests/harte_tests/latest.txt +++ b/tests/harte_tests/latest.txt @@ -1,4 +1,4 @@ -Last run on 2024-03-13 at commit af1c660dc0682a62c123b1d7577f2ce2b5f3d8ad +Last run on 2024-03-14 at commit 545f339fe2714cc648bd4a01506518a13c1faf39 ABCD.json.gz completed: 7993 passed, 72 FAILED ADD.b.json.gz completed, all passed! @@ -37,3 +37,93 @@ 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 15m 0s diff --git a/tests/harte_tests/src/main.rs b/tests/harte_tests/src/main.rs index 45aec0e..f6240e4 100644 --- a/tests/harte_tests/src/main.rs +++ b/tests/harte_tests/src/main.rs @@ -10,13 +10,22 @@ use std::fs::{self, File}; use clap::{Parser, ArgEnum}; use flate2::read::GzDecoder; use serde_derive::Deserialize; -use femtos::Frequency; +use femtos::{Instant, Frequency}; -use moa_core::{System, Error, MemoryBlock, BusPort, Address, Addressable, Steppable, Device}; +use emulator_hal::bus::BusAccess; +use emulator_hal::step::Step; +use emulator_hal_memory::MemoryBlock; use moa_m68k::{M68k, M68kType}; use moa_m68k::state::Status; +#[derive(Clone, Debug)] +enum Error { + Assertion(String), + Bus(String), + Step(String), +} + #[derive(Copy, Clone, PartialEq, Eq, ArgEnum)] enum Selection { Include, @@ -106,7 +115,7 @@ impl TestState { for word in self.prefetch.iter() { print!("{:04x} ", *word); } - println!(""); + println!(); println!("ram: "); for (addr, byte) in self.ram.iter() { @@ -137,25 +146,19 @@ impl TestCase { } -fn init_execute_test(cputype: M68kType, state: &TestState) -> Result<(M68k, System), Error> { - let mut system = System::default(); - +fn init_execute_test(cputype: M68kType, state: &TestState) -> Result<(M68k, MemoryBlock), Error> { // Insert basic initialization - let data = vec![0; 0x01000000]; - let mem = MemoryBlock::new(data); - system.add_addressable_device(0x00000000, Device::new(mem)).unwrap(); + let len = 0x100_0000; + let mut data = Vec::with_capacity(len); + unsafe { data.set_len(len); } + let mut memory = MemoryBlock::::from(data); - let port = if cputype <= M68kType::MC68010 { - BusPort::new(0, 24, 16, system.bus.clone()) - } else { - BusPort::new(0, 32, 32, system.bus.clone()) - }; - 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.state.status = Status::Running; - load_state(&mut cpu, &mut system, state)?; + load_state(&mut cpu, &mut memory, state)?; - Ok((cpu, system)) + Ok((cpu, memory)) } fn assert_value(actual: T, expected: T, message: &str) -> Result<(), Error> @@ -165,11 +168,11 @@ where if actual == expected { Ok(()) } else { - Err(Error::assertion(&format!("{:#X} != {:#X}, {}", actual, expected, message))) + Err(Error::Assertion(format!("{:#X} != {:#X}, {}", actual, expected, message))) } } -fn load_state(cpu: &mut M68k, system: &mut System, initial: &TestState) -> Result<(), Error> { +fn load_state(cpu: &mut M68k, memory: &mut MemoryBlock, initial: &TestState) -> Result<(), Error> { cpu.state.d_reg[0] = initial.d0; cpu.state.d_reg[1] = initial.d1; cpu.state.d_reg[2] = initial.d2; @@ -193,18 +196,20 @@ fn load_state(cpu: &mut M68k, system: &mut System, initial: &TestState) -> Resul // Load instructions into memory for (i, ins) in initial.prefetch.iter().enumerate() { - system.get_bus().write_beu16(system.clock, (initial.pc + (i as u32 * 2)) as u64, *ins)?; + memory.write_beu16(Instant::START, initial.pc + (i as u32 * 2), *ins) + .map_err(|err| Error::Bus(format!("{:?}", err)))?; } // Load data bytes into memory for (addr, byte) in initial.ram.iter() { - system.get_bus().write_u8(system.clock, *addr as u64, *byte)?; + memory.write_u8(Instant::START, *addr, *byte) + .map_err(|err| Error::Bus(format!("{:?}", err)))?; } Ok(()) } -fn assert_state(cpu: &M68k, system: &System, expected: &TestState) -> Result<(), Error> { +fn assert_state(cpu: &M68k, memory: &mut MemoryBlock, expected: &TestState) -> Result<(), Error> { assert_value(cpu.state.d_reg[0], expected.d0, "d0")?; assert_value(cpu.state.d_reg[1], expected.d1, "d1")?; assert_value(cpu.state.d_reg[2], expected.d2, "d2")?; @@ -226,29 +231,32 @@ fn assert_state(cpu: &M68k, system: &System, expected: &TestState) -> Result<(), assert_value(cpu.state.sr, expected.sr, "sr")?; assert_value(cpu.state.pc, expected.pc, "pc")?; - let addr_mask = cpu.port.address_mask(); + let addr_mask = 1_u32.wrapping_shl(cpu.info.address_width as u32).wrapping_sub(1); // Load instructions into memory for (i, ins) in expected.prefetch.iter().enumerate() { let addr = expected.pc + (i as u32 * 2); - let actual = system.get_bus().read_beu16(system.clock, addr as Address & addr_mask)?; + let actual = memory.read_beu16(Instant::START, addr & addr_mask) + .map_err(|err| Error::Bus(format!("{:?}", err)))?; assert_value(actual, *ins, &format!("prefetch at {:x}", addr))?; } // Load data bytes into memory for (addr, byte) in expected.ram.iter() { - let actual = system.get_bus().read_u8(system.clock, *addr as Address & addr_mask)?; + let actual = memory.read_u8(Instant::START, *addr & addr_mask) + .map_err(|err| Error::Bus(format!("{:?}", err)))?; assert_value(actual, *byte, &format!("ram at {:x}", addr))?; } Ok(()) } -fn step_cpu_and_assert(cpu: &mut M68k, system: &System, case: &TestCase, test_timing: bool) -> Result<(), Error> { - let clock_elapsed = cpu.step(&system)?; - let cycles = clock_elapsed / cpu.info.frequency.period_duration(); +fn step_cpu_and_assert(cpu: &mut M68k, memory: &mut MemoryBlock, case: &TestCase, test_timing: bool) -> Result<(), Error> { + let clock_elapsed = cpu.step(Instant::START, memory) + .map_err(|err| Error::Step(format!("{:?}", err)))?; + let cycles = clock_elapsed.as_duration() / cpu.info.frequency.period_duration(); - assert_state(&cpu, &system, &case.final_state)?; + assert_state(cpu, memory, &case.final_state)?; if test_timing { assert_value(cycles, case.length as u64, "clock cycles")?; @@ -257,10 +265,10 @@ fn step_cpu_and_assert(cpu: &mut M68k, system: &System, case: &TestCase, test_ti } fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> { - let (mut cpu, system) = init_execute_test(M68kType::MC68000, &case.initial_state).unwrap(); - let mut initial_cpu = cpu.clone(); + let (mut cpu, mut memory) = init_execute_test(M68kType::MC68000, &case.initial_state).unwrap(); + let initial_cpu = cpu.clone(); - let result = step_cpu_and_assert(&mut cpu, &system, case, args.timing); + let result = step_cpu_and_assert(&mut cpu, &mut memory, case, args.timing); match result { Ok(()) => Ok(()), @@ -268,7 +276,7 @@ fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> { if !args.quiet { if args.debug { case.dump(); - println!(""); + println!(); //initial_cpu.dump_state(); //cpu.dump_state(); } @@ -391,7 +399,7 @@ fn run_all_tests(args: &Args) { } } - println!(""); + println!(); println!("passed: {}, failed: {}, total {:.0}%", passed, failed, ((passed as f32) / (passed as f32 + failed as f32)) * 100.0); println!("completed in {}m {}s", elapsed_secs / 60, elapsed_secs % 60); } From c20d7afe6e8005ab272602953154280f0e1aa944 Mon Sep 17 00:00:00 2001 From: transistor Date: Fri, 15 Mar 2024 23:01:41 -0700 Subject: [PATCH 7/9] Fixed some tests --- Cargo.lock | 1 + docs/log.txt | 7 ++ emulator/core/src/error.rs | 2 +- emulator/cpus/m68k/Cargo.toml | 3 + emulator/cpus/m68k/src/debugger.rs | 1 + emulator/cpus/m68k/src/decode.rs | 7 +- emulator/cpus/m68k/src/execute.rs | 40 +----- emulator/cpus/m68k/src/lib.rs | 3 +- emulator/cpus/m68k/src/memory.rs | 12 +- emulator/cpus/m68k/src/moa.rs | 2 +- emulator/cpus/m68k/src/state.rs | 13 +- emulator/cpus/m68k/src/tests.rs | 104 ++++++--------- emulator/cpus/m68k/tests/decode_tests.rs | 56 ++++----- emulator/cpus/m68k/tests/execute_tests.rs | 66 +++++----- .../cpus/m68k/tests/musashi_timing_tests.rs | 59 ++++----- emulator/cpus/m68k/tests/timing_tests.rs | 58 ++++----- emulator/libraries/host/src/mouse.rs | 2 +- emulator/libraries/host/src/traits.rs | 8 +- emulator/libraries/parsing/src/lib.rs | 2 - tests/harte_tests/latest.txt | 118 +----------------- tests/harte_tests/src/main.rs | 21 ++-- tests/rad_tests/src/main.rs | 22 ++-- todo.txt | 31 ++--- 23 files changed, 214 insertions(+), 424 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 94c30ae..04f274e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -824,6 +824,7 @@ name = "moa-m68k" version = "0.1.0" dependencies = [ "emulator-hal", + "emulator-hal-memory", "femtos", "log", "moa-core", diff --git a/docs/log.txt b/docs/log.txt index b15f51c..980a358 100644 --- a/docs/log.txt +++ b/docs/log.txt @@ -484,3 +484,10 @@ General Work - 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 + +2024-03-14 +- I finally took a look at a flamegraph of the harte_test runner, and almost the entirety of the time + spent running tests was in zeroing of the array of memory at the start of each test. I really + should use MaybeUninit, but I instead used Vec::with_capacity/.set_len(). It went from 15-24 minutes + down to 6 seconds. + diff --git a/emulator/core/src/error.rs b/emulator/core/src/error.rs index 0ffe7f6..cd10af0 100644 --- a/emulator/core/src/error.rs +++ b/emulator/core/src/error.rs @@ -74,7 +74,7 @@ impl fmt::Display for Error { } impl From> for Error { - fn from(err: HostError) -> Self { + fn from(_err: HostError) -> Self { Self::Other("other".to_string()) } } diff --git a/emulator/cpus/m68k/Cargo.toml b/emulator/cpus/m68k/Cargo.toml index 6143ee6..ee4eb8f 100644 --- a/emulator/cpus/m68k/Cargo.toml +++ b/emulator/cpus/m68k/Cargo.toml @@ -12,5 +12,8 @@ emulator-hal = { path = "../../libraries/emulator-hal/emulator-hal" } moa-core = { path = "../../core", optional = true } +[dev-dependencies] +emulator-hal-memory = { path = "../../libraries/emulator-hal/emulator-hal-memory" } + [features] moa = ["moa-core"] diff --git a/emulator/cpus/m68k/src/debugger.rs b/emulator/cpus/m68k/src/debugger.rs index 827dfb5..7f5c709 100644 --- a/emulator/cpus/m68k/src/debugger.rs +++ b/emulator/cpus/m68k/src/debugger.rs @@ -26,6 +26,7 @@ impl StackTracer { pub struct M68kDebugger { pub(crate) skip_breakpoint: usize, pub(crate) breakpoints: Vec, + #[allow(dead_code)] pub(crate) step_until_return: Option, pub(crate) stack_tracer: StackTracer, } diff --git a/emulator/cpus/m68k/src/decode.rs b/emulator/cpus/m68k/src/decode.rs index 83e965a..e64b815 100644 --- a/emulator/cpus/m68k/src/decode.rs +++ b/emulator/cpus/m68k/src/decode.rs @@ -105,11 +105,8 @@ impl M68kDecoder { }, Err(err) => { println!("{:?}", err); - match err { - M68kError::Exception(ex) if ex == Exceptions::IllegalInstruction => { - println!(" at {:08x}: {:04x}", self.start, bus.read_beu16(memory.current_clock, self.start).unwrap()); - }, - _ => { }, + if let M68kError::Exception(Exceptions::IllegalInstruction) = err { + println!(" at {:08x}: {:04x}", self.start, bus.read_beu16(memory.current_clock, self.start).unwrap()); } return; }, diff --git a/emulator/cpus/m68k/src/execute.rs b/emulator/cpus/m68k/src/execute.rs index 7fb1e91..8aeca3c 100644 --- a/emulator/cpus/m68k/src/execute.rs +++ b/emulator/cpus/m68k/src/execute.rs @@ -71,7 +71,7 @@ impl M68kCycle { { 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; + cpu.stats.last_update += 1_000_000; let now = std::time::SystemTime::now(); log::warn!("{} per million", now.duration_since(cpu.stats.last_time).unwrap().as_micros()); cpu.stats.last_time = now; @@ -79,7 +79,7 @@ impl M68kCycle { M68kCycleExecutor { state: &mut cpu.state, - bus: bus, + bus, debugger: &mut cpu.debugger, cycle: self, } @@ -97,7 +97,7 @@ where self.state.status == Status::Running } - fn reset(&mut self, now: Instant, bus: &mut Bus) -> Result<(), Self::Error> { + fn reset(&mut self, _now: Instant, _bus: &mut Bus) -> Result<(), Self::Error> { Ok(()) } @@ -173,38 +173,6 @@ where Ok(()) } - /* - #[inline] - pub fn check_pending_interrupts(&mut self, system: &System) -> Result<(), M68kError> { - // TODO this could move somewhere else - self.state.pending_ipl = match system.get_interrupt_controller().check() { - (true, priority) => InterruptPriority::from_u8(priority), - (false, _) => InterruptPriority::NoInterrupt, - }; - - let current_ipl = self.state.current_ipl as u8; - let pending_ipl = self.state.pending_ipl as u8; - - if self.state.pending_ipl != InterruptPriority::NoInterrupt { - 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()); - self.state.current_ipl = self.state.pending_ipl; - let ack_num = system.get_interrupt_controller().acknowledge(self.state.current_ipl as u8)?; - self.exception(ack_num, true)?; - return Ok(()); - } - } - - if pending_ipl < current_ipl { - self.state.current_ipl = self.state.pending_ipl; - } - - Ok(()) - } - */ - #[inline] pub fn check_pending_interrupts(&mut self, interrupt: (bool, u8, u8)) -> Result<(InterruptPriority, Option), M68kError> { let ack_num; @@ -315,7 +283,7 @@ where Ok(()) }, Err(M68kError::Interrupt(ex)) => { - self.exception(ex as u8, false)?; + self.exception(ex, false)?; Ok(()) }, Err(err) => Err(err), diff --git a/emulator/cpus/m68k/src/lib.rs b/emulator/cpus/m68k/src/lib.rs index dad8dfb..a8253e4 100644 --- a/emulator/cpus/m68k/src/lib.rs +++ b/emulator/cpus/m68k/src/lib.rs @@ -12,5 +12,6 @@ pub mod tests; #[cfg(feature = "moa")] pub mod moa; -pub use self::state::{M68k, M68kType, M68kError}; +pub use crate::state::{M68k, M68kType, M68kError}; +pub use crate::memory::{M68kAddress, M68kAddressSpace}; diff --git a/emulator/cpus/m68k/src/memory.rs b/emulator/cpus/m68k/src/memory.rs index 6f1e7b1..8dab166 100644 --- a/emulator/cpus/m68k/src/memory.rs +++ b/emulator/cpus/m68k/src/memory.rs @@ -153,9 +153,9 @@ impl M68kBusPort { Bus: BusAccess, { let addr = addr & self.address_mask; - for i in (0..data.len()).step_by(self.data_bytewidth as usize) { + for i in (0..data.len()).step_by(self.data_bytewidth) { let addr_index = (addr + i as M68kAddress) & self.address_mask; - let end = cmp::min(i + self.data_bytewidth as usize, data.len()); + let end = cmp::min(i + self.data_bytewidth, data.len()); bus.read(clock, addr_index, &mut data[i..end]) .map_err(|err| M68kError::BusError(err))?; } @@ -167,9 +167,9 @@ impl M68kBusPort { Bus: BusAccess, { let addr = addr & self.address_mask; - for i in (0..data.len()).step_by(self.data_bytewidth as usize) { + for i in (0..data.len()).step_by(self.data_bytewidth) { let addr_index = (addr + i as M68kAddress) & self.address_mask; - let end = cmp::min(i + self.data_bytewidth as usize, data.len()); + let end = cmp::min(i + self.data_bytewidth, data.len()); bus.write(clock, addr_index, &data[i..end]) .map_err(|err| M68kError::BusError(err))?; } @@ -204,7 +204,7 @@ impl M68kBusPort { where Bus: BusAccess, { - self.start_request(is_supervisor, addr as u32, size, MemAccess::Read, MemType::Data, false)?; + self.start_request(is_supervisor, addr, size, MemAccess::Read, MemType::Data, false)?; self.read_sized(bus, addr, size) } @@ -212,7 +212,7 @@ impl M68kBusPort { where Bus: BusAccess, { - self.start_request(is_supervisor, addr as u32, size, MemAccess::Write, MemType::Data, false)?; + self.start_request(is_supervisor, addr, size, MemAccess::Write, MemType::Data, false)?; self.write_sized(bus, addr, size, value) } diff --git a/emulator/cpus/m68k/src/moa.rs b/emulator/cpus/m68k/src/moa.rs index 76940b1..46ac931 100644 --- a/emulator/cpus/m68k/src/moa.rs +++ b/emulator/cpus/m68k/src/moa.rs @@ -102,7 +102,7 @@ impl Debuggable for M68k { 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); + 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 { diff --git a/emulator/cpus/m68k/src/state.rs b/emulator/cpus/m68k/src/state.rs index 04249fc..c2a46aa 100644 --- a/emulator/cpus/m68k/src/state.rs +++ b/emulator/cpus/m68k/src/state.rs @@ -237,7 +237,7 @@ impl Default for M68kState { } impl M68kState { - pub fn dump_state(&mut self, writer: &mut W) -> Result<(), fmt::Error> { + pub fn dump_state(&self, writer: &mut W) -> Result<(), fmt::Error> { writeln!(writer, "Status: {:?}", self.status)?; writeln!(writer, "PC: {:#010x}", self.pc)?; writeln!(writer, "SR: {:#06x}", self.sr)?; @@ -265,15 +265,16 @@ impl M68k { Self::new(CpuInfo::from_type(cputype, freq)) } - pub fn dump_state(&mut self, writer: &mut W) { - self.state.dump_state(writer); + pub fn dump_state(&self, writer: &mut W) -> Result<(), fmt::Error> { + self.state.dump_state(writer)?; if let Some(cycle) = self.cycle.as_ref() { - println!("Current Instruction: {:#010x} {:?}", cycle.decoder.start, cycle.decoder.instruction); - println!(); + writeln!(writer, "Current Instruction: {:#010x} {:?}", cycle.decoder.start, cycle.decoder.instruction)?; + writeln!(writer)?; } //memory::dump_memory(&mut self.bus, self.cycle.current_clock, self.state.ssp, 0x40); - println!(); + writeln!(writer)?; + Ok(()) } #[inline] diff --git a/emulator/cpus/m68k/src/tests.rs b/emulator/cpus/m68k/src/tests.rs index fc26353..14d180b 100644 --- a/emulator/cpus/m68k/src/tests.rs +++ b/emulator/cpus/m68k/src/tests.rs @@ -1,12 +1,9 @@ - +/( #[cfg(test)] 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, Error}; + use emulator_hal::bus::BusAccess; + use emulator_hal_memory::MemoryBlock; use crate::M68kType; use crate::instructions::{Target, Size, XRegister, BaseRegister, IndexRegister}; @@ -15,21 +12,11 @@ mod decode_unit_tests { const INIT_ADDR: u32 = 0x00000000; - 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 mut bus = bus.borrow_mut(); - let mut adapter: BusAdapter = BusAdapter::new( - &mut *bus, - |addr| addr as u64, - |err| err.try_into().unwrap(), - ); - + fn init_decode_test<'a>(cputype: M68kType) -> InstructionDecoding<'a, MemoryBlock> { + let mut memory = MemoryBlock::from(vec![0; 0x0000100]); let mut decoder = M68kDecoder::new(cputype, true, 0); let mut decoding = InstructionDecoding { - port: &mut adapter, + bus: &mut memory, memory: &mut M68kBusPort::default(), decoder: &mut decoder, }; @@ -67,7 +54,7 @@ mod decode_unit_tests { let size = Size::Long; let expected = 0x12345678; - decoder.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); + decoder.bus.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); let target = decoder.get_mode_as_target(0b010, 0b010, Some(size)).unwrap(); assert_eq!(target, Target::IndirectAReg(2)); @@ -80,7 +67,7 @@ mod decode_unit_tests { let size = Size::Long; let expected = 0x12345678; - decoder.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); + decoder.bus.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); let target = decoder.get_mode_as_target(0b011, 0b010, Some(size)).unwrap(); assert_eq!(target, Target::IndirectARegInc(2)); @@ -93,7 +80,7 @@ mod decode_unit_tests { let size = Size::Long; let expected = 0x12345678; - decoder.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); + decoder.bus.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); let target = decoder.get_mode_as_target(0b100, 0b010, Some(size)).unwrap(); assert_eq!(target, Target::IndirectARegDec(2)); @@ -106,7 +93,7 @@ mod decode_unit_tests { let size = Size::Long; let offset = -8; - decoder.port.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap(); + decoder.bus.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap(); let target = decoder.get_mode_as_target(0b101, 0b100, Some(size)).unwrap(); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(4), None, offset)); @@ -120,8 +107,8 @@ mod decode_unit_tests { let offset = -8; let brief_extension = 0x3800 | (((offset as i8) as u8) as u16); - 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(); + decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); + decoder.bus.write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16).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)); @@ -135,8 +122,8 @@ mod decode_unit_tests { let offset = -1843235 as i32; let brief_extension = 0xF330; - decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - decoder.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); + decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); + decoder.bus.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).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)); @@ -150,8 +137,8 @@ mod decode_unit_tests { let offset = -1843235 as i32; let brief_extension = 0xF3B0; - decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - decoder.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); + decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); + decoder.bus.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).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)); @@ -165,8 +152,8 @@ mod decode_unit_tests { let offset = -1843235 as i32; let brief_extension = 0xF370; - decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - decoder.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); + decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); + decoder.bus.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); let target = decoder.get_mode_as_target(0b110, 0b010, Some(size)).unwrap(); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(2), None, offset)); @@ -179,7 +166,7 @@ mod decode_unit_tests { let size = Size::Long; let offset = -8; - decoder.port.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap(); + decoder.bus.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap(); let target = decoder.get_mode_as_target(0b111, 0b010, Some(size)).unwrap(); assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, None, offset)); @@ -193,8 +180,8 @@ mod decode_unit_tests { let offset = -8; let brief_extension = 0x3000 | (((offset as i8) as u8) as u16); - 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(); + decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); + decoder.bus.write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16).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)); @@ -208,8 +195,8 @@ mod decode_unit_tests { let offset = -1843235 as i32; let brief_extension = 0xF330; - decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - decoder.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); + decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); + decoder.bus.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).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)); @@ -223,7 +210,7 @@ mod decode_unit_tests { let size = Size::Word; let expected = 0x1234; - decoder.port.write_beu16(Instant::START, INIT_ADDR, expected as u16).unwrap(); + decoder.bus.write_beu16(Instant::START, INIT_ADDR, expected as u16).unwrap(); let target = decoder.get_mode_as_target(0b111, 0b000, Some(size)).unwrap(); assert_eq!(target, Target::IndirectMemory(expected, Size::Word)); @@ -236,7 +223,7 @@ mod decode_unit_tests { let size = Size::Word; let expected = 0x12345678; - decoder.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); + decoder.bus.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); let target = decoder.get_mode_as_target(0b111, 0b001, Some(size)).unwrap(); assert_eq!(target, Target::IndirectMemory(expected, Size::Long)); @@ -249,20 +236,19 @@ mod decode_unit_tests { let size = Size::Word; let expected = 0x1234; - decoder.port.write_beu16(Instant::START, INIT_ADDR, expected as u16).unwrap(); + decoder.bus.write_beu16(Instant::START, INIT_ADDR, expected as u16).unwrap(); let target = decoder.get_mode_as_target(0b111, 0b100, Some(size)).unwrap(); assert_eq!(target, Target::Immediate(expected)); } } - #[cfg(test)] mod execute_unit_tests { use femtos::{Instant, Frequency}; use emulator_hal::bus::{BusAdapter, BusAccess}; - - use moa_core::{System, MemoryBlock, Addressable, Steppable, Device, Error}; + use emulator_hal::step::Step; + use emulator_hal_memory::MemoryBlock; use crate::{M68k, M68kType}; use crate::execute::{Used, M68kCycle, M68kCycleExecutor}; @@ -271,31 +257,23 @@ mod execute_unit_tests { const INIT_STACK: u32 = 0x00002000; const INIT_ADDR: u32 = 0x00000010; + #[allow(clippy::uninit_vec)] fn run_execute_test(cputype: M68kType, mut test_func: F) where - F: FnMut(M68kCycleExecutor<&mut BusAdapter>), + F: FnMut(M68kCycleExecutor<&mut MemoryBlock>), { - let mut system = System::default(); - // Insert basic initialization - let data = vec![0; 0x00100000]; - let mem = MemoryBlock::new(data); - system.add_addressable_device(0x00000000, Device::new(mem)).unwrap(); - 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 len = 0x10_0000; + let mut data = Vec::with_capacity(len); + let mut memory = MemoryBlock::from(data); + memory.write_beu32(Instant::START, 0, INIT_STACK as u32).unwrap(); + memory.write_beu32(Instant::START, 4, INIT_ADDR as u32).unwrap(); let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10)); - cpu.step(&system).unwrap(); - let mut cycle = M68kCycle::new(&mut cpu, system.clock); + cpu.step(Instant::START, &mut memory).unwrap(); + let mut cycle = M68kCycle::new(&mut cpu, Instant::START); - 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 executor = cycle.begin(&mut cpu, &mut memory); 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); @@ -340,7 +318,7 @@ mod execute_unit_tests { let size = Size::Long; let expected = 0x12345678; let target = Target::IndirectAReg(2); - cycle.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); + cycle.bus.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(); @@ -354,7 +332,7 @@ mod execute_unit_tests { let size = Size::Long; let expected = 0x12345678; let target = Target::IndirectARegInc(2); - cycle.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); + cycle.bus.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(); @@ -369,7 +347,7 @@ mod execute_unit_tests { let size = Size::Long; let expected = 0x12345678; let target = Target::IndirectARegDec(2); - cycle.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); + cycle.bus.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(); diff --git a/emulator/cpus/m68k/tests/decode_tests.rs b/emulator/cpus/m68k/tests/decode_tests.rs index a5285cf..7ebbe09 100644 --- a/emulator/cpus/m68k/tests/decode_tests.rs +++ b/emulator/cpus/m68k/tests/decode_tests.rs @@ -1,16 +1,15 @@ use femtos::{Instant, Frequency}; -use emulator_hal::bus::BusAdapter; +use emulator_hal::bus::BusAccess; +use emulator_hal_memory::MemoryBlock; -use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Device, Error}; - -use moa_m68k::{M68k, M68kType}; +use moa_m68k::{M68k, M68kType, M68kAddress}; use moa_m68k::instructions::{Instruction, Target, Size, Sign, XRegister, BaseRegister, IndexRegister, Direction}; use moa_m68k::assembler::M68kAssembler; use moa_m68k::execute::M68kCycle; -const INIT_STACK: Address = 0x00002000; -const INIT_ADDR: Address = 0x00000010; +const INIT_STACK: M68kAddress = 0x00002000; +const INIT_ADDR: M68kAddress = 0x00000010; struct TestCase { cpu: M68kType, @@ -65,56 +64,47 @@ const DECODE_TESTS: &'static [TestCase] = &[ ]; -fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, System) { - let mut system = System::default(); - +fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, MemoryBlock) { // Insert basic initialization - let data = vec![0; 0x00100000]; - let mem = MemoryBlock::new(data); - system.add_addressable_device(0x00000000, Device::new(mem)).unwrap(); - 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 len = 0x10_0000; + let mut data = Vec::with_capacity(len); + let mut memory = MemoryBlock::from(data); + memory.write_beu32(Instant::START, 0, INIT_STACK).unwrap(); + memory.write_beu32(Instant::START, 4, INIT_ADDR).unwrap(); // 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); + let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10)); //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); + //assert_eq!(cpu.state.ssp, INIT_STACK); - let cycle = M68kCycle::new(&cpu, system.clock); - //assert_eq!(cycle.decoder.start, INIT_ADDR as u32); + let cycle = M68kCycle::new(&cpu, Instant::START); + //assert_eq!(cycle.decoder.start, INIT_ADDR); //assert_eq!(cycle.decoder.instruction, Instruction::NOP); - (cpu, cycle, system) + (cpu, cycle, memory) } -fn load_memory(system: &System, data: &[u16]) { +fn load_memory>(memory: &mut Bus, data: &[u16]) { let mut addr = INIT_ADDR; for word in data { - system.get_bus().write_beu16(system.clock, addr, *word).unwrap(); + memory.write_beu16(Instant::START, addr, *word).unwrap(); addr += 2; } } 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(), - ); + let (mut cpu, cycle, mut memory) = init_decode_test(case.cpu); + load_memory(&mut memory, case.data); match &case.ins { Some(ins) => { - let mut executor = cycle.begin(&mut cpu, &mut adapter); + let mut executor = cycle.begin(&mut cpu, &mut memory); executor.reset_cpu().unwrap(); executor.decode_next().unwrap(); assert_eq!(executor.cycle.decoder.instruction, ins.clone()); }, None => { - let mut executor = cycle.begin(&mut cpu, &mut adapter); + let mut executor = cycle.begin(&mut cpu, &mut memory); executor.reset_cpu().unwrap(); let next = executor.decode_next(); println!("{:?}", executor.cycle.decoder.instruction); diff --git a/emulator/cpus/m68k/tests/execute_tests.rs b/emulator/cpus/m68k/tests/execute_tests.rs index b3bdcc8..a34b6fd 100644 --- a/emulator/cpus/m68k/tests/execute_tests.rs +++ b/emulator/cpus/m68k/tests/execute_tests.rs @@ -1,16 +1,16 @@ use femtos::{Instant, Frequency}; -use emulator_hal::bus::BusAdapter; +use emulator_hal::bus::BusAccess; +use emulator_hal::step::Step; +use emulator_hal_memory::MemoryBlock; -use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Steppable, Device, Error}; - -use moa_m68k::{M68k, M68kType}; +use moa_m68k::{M68k, M68kType, M68kAddress}; use moa_m68k::state::M68kState; use moa_m68k::execute::{M68kCycle, M68kCycleExecutor}; use moa_m68k::instructions::{Instruction, Target, Size, Sign, Direction, Condition}; -const INIT_STACK: Address = 0x00002000; -const INIT_ADDR: Address = 0x00000010; +const INIT_STACK: M68kAddress = 0x00002000; +const INIT_ADDR: M68kAddress = 0x00000010; const MEM_ADDR: u32 = 0x00001234; @@ -36,37 +36,29 @@ struct TestCase { } +#[allow(clippy::uninit_vec)] fn run_execute_test(cputype: M68kType, mut test_func: F) where - F: FnMut(M68kCycleExecutor<&mut BusAdapter>, &System), + F: FnMut(M68kCycleExecutor<&mut MemoryBlock>), { - let mut system = System::default(); - // Insert basic initialization - let data = vec![0; 0x00100000]; - let mem = MemoryBlock::new(data); - system.add_addressable_device(0x00000000, Device::new(mem)).unwrap(); - 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 len = 0x10_0000; + let mut data = Vec::with_capacity(len); + let mut memory = MemoryBlock::from(data); + memory.write_beu32(Instant::START, 0, INIT_STACK).unwrap(); + memory.write_beu32(Instant::START, 4, INIT_ADDR).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)); + cpu.step(Instant::START, &mut memory).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, Instant::START); + let executor = cycle.begin(&mut cpu, &mut memory); - let cycle = M68kCycle::new(&cpu, system.clock); - 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.state.pc, INIT_ADDR); + assert_eq!(executor.state.ssp, INIT_STACK); assert_eq!(executor.cycle.decoder.instruction, Instruction::NOP); - test_func(executor, &system) + test_func(executor) } fn build_state(state: &TestState) -> M68kState { @@ -82,19 +74,21 @@ fn build_state(state: &TestState) -> M68kState { new_state } -fn load_memory(system: &System, data: &[u16]) { - for i in 0..data.len() { - system.get_bus().write_beu16(system.clock, (i << 1) as Address, data[i]).unwrap(); - } +fn load_memory>(bus: &mut Bus, data: &[u16]) { + let mut addr = INIT_ADDR; + for word in data { + bus.write_beu16(Instant::START, addr, *word).unwrap(); + addr += 2; + } } fn run_test(case: &TestCase) { - run_execute_test(case.cputype, |mut executor, system| { + run_execute_test(case.cputype, |mut executor| { let init_state = build_state(&case.init); let expected_state = build_state(&case.fini); - system.get_bus().write_beu32(system.clock, MEM_ADDR as Address, case.init.mem).unwrap(); + executor.bus.write_beu32(Instant::START, MEM_ADDR, case.init.mem).unwrap(); - load_memory(&system, case.data); + load_memory(&mut executor.bus, case.data); *executor.state = init_state; executor.decode_next().unwrap(); @@ -103,7 +97,7 @@ fn run_test(case: &TestCase) { executor.execute_current().unwrap(); assert_eq!(*executor.state, expected_state); - let mem = system.get_bus().read_beu32(system.clock, MEM_ADDR as Address).unwrap(); + let mem = executor.bus.read_beu32(Instant::START, MEM_ADDR).unwrap(); assert_eq!(mem, case.fini.mem); }); } diff --git a/emulator/cpus/m68k/tests/musashi_timing_tests.rs b/emulator/cpus/m68k/tests/musashi_timing_tests.rs index 411fb94..110c563 100644 --- a/emulator/cpus/m68k/tests/musashi_timing_tests.rs +++ b/emulator/cpus/m68k/tests/musashi_timing_tests.rs @@ -1,60 +1,51 @@ use femtos::{Instant, Frequency}; -use emulator_hal::bus::BusAdapter; +use emulator_hal::bus::BusAccess; +use emulator_hal_memory::MemoryBlock; -use moa_core::{System, Error, MemoryBlock, Address, Addressable, Device}; - -use moa_m68k::{M68k, M68kType}; +use moa_m68k::{M68k, M68kType, M68kAddress}; use moa_m68k::instructions::{Instruction, Target, Size, Sign, Condition, XRegister, BaseRegister, IndexRegister, Direction}; use moa_m68k::timing::M68kInstructionTiming; use moa_m68k::execute::M68kCycle; -const INIT_STACK: Address = 0x00002000; -const INIT_ADDR: Address = 0x00000010; - -fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, System) { - let mut system = System::default(); +const INIT_STACK: M68kAddress = 0x00002000; +const INIT_ADDR: M68kAddress = 0x00000010; +#[allow(clippy::uninit_vec)] +fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, MemoryBlock) { // Insert basic initialization - let data = vec![0; 0x00100000]; - let mem = MemoryBlock::new(data); - system.add_addressable_device(0x00000000, Device::new(mem)).unwrap(); - 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 len = 0x10_0000; + let mut data = Vec::with_capacity(len); + let mut memory = MemoryBlock::from(data); + memory.write_beu32(Instant::START, 0, INIT_STACK).unwrap(); + memory.write_beu32(Instant::START, 4, INIT_ADDR).unwrap(); // Initialize the CPU and make sure it's in the expected state - let cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0); - let cycle = M68kCycle::new(&cpu, system.clock); - assert_eq!(cpu.state.pc, INIT_ADDR as u32); - assert_eq!(cpu.state.ssp, INIT_STACK as u32); - assert_eq!(cycle.decoder.start, INIT_ADDR as u32); + let cpu = M68k::from_type(cputype, Frequency::from_mhz(10)); + let cycle = M68kCycle::new(&cpu, Instant::START); + assert_eq!(cpu.state.pc, INIT_ADDR); + assert_eq!(cpu.state.ssp, INIT_STACK); + assert_eq!(cycle.decoder.start, INIT_ADDR); assert_eq!(cycle.decoder.instruction, Instruction::NOP); - (cpu, cycle, system) + (cpu, cycle, memory) } -fn load_memory(system: &System, data: &[u16]) { +fn load_memory>(bus: &mut Bus, data: &[u16]) { let mut addr = INIT_ADDR; for word in data { - system.get_bus().write_beu16(system.clock, addr, *word).unwrap(); + bus.write_beu16(Instant::START, addr, *word).unwrap(); addr += 2; } } -fn run_timing_test(case: &TimingCase) -> Result<(), Error> { - let (mut cpu, cycle, system) = init_decode_test(case.cpu); +fn run_timing_test(case: &TimingCase) -> Result<(), String> { + let (mut cpu, cycle, mut memory) = init_decode_test(case.cpu); + load_memory(&mut memory, 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(), - ); - - let mut executor = cycle.begin(&mut cpu, &mut adapter); + let mut executor = cycle.begin(&mut cpu, &mut memory); let mut timing = M68kInstructionTiming::new(case.cpu, 16); - load_memory(&system, case.data); executor.decode_next().unwrap(); assert_eq!(executor.cycle.decoder.instruction, case.ins.clone()); @@ -71,7 +62,7 @@ fn run_timing_test(case: &TimingCase) -> Result<(), Error> { Ok(()) } else { println!("{:?}", timing); - Err(Error::new(format!("expected {} but found {}", expected, result))) + Err(format!("expected {} but found {}", expected, result)) } } diff --git a/emulator/cpus/m68k/tests/timing_tests.rs b/emulator/cpus/m68k/tests/timing_tests.rs index 09a6220..9144c8f 100644 --- a/emulator/cpus/m68k/tests/timing_tests.rs +++ b/emulator/cpus/m68k/tests/timing_tests.rs @@ -1,16 +1,15 @@ use femtos::{Instant, Frequency}; -use emulator_hal::bus::BusAdapter; +use emulator_hal::bus::BusAccess; +use emulator_hal_memory::MemoryBlock; -use moa_core::{System, Error, MemoryBlock, BusPort, Address, Addressable, Device}; - -use moa_m68k::{M68k, M68kType}; +use moa_m68k::{M68k, M68kType, M68kAddress}; use moa_m68k::instructions::{Instruction, Target, Size}; use moa_m68k::timing::M68kInstructionTiming; use moa_m68k::execute::M68kCycle; -const INIT_STACK: Address = 0x00002000; -const INIT_ADDR: Address = 0x00000010; +const INIT_STACK: M68kAddress = 0x00002000; +const INIT_ADDR: M68kAddress = 0x00000010; struct TimingCase { @@ -25,50 +24,41 @@ const TIMING_TESTS: &'static [TimingCase] = &[ ]; -fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, System) { - let mut system = System::default(); - +fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, MemoryBlock) { // Insert basic initialization - let data = vec![0; 0x00100000]; - let mem = MemoryBlock::new(data); - system.add_addressable_device(0x00000000, Device::new(mem)).unwrap(); - 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 len = 0x10_0000; + let mut data = Vec::with_capacity(len); + let mut memory = MemoryBlock::from(data); + memory.write_beu32(Instant::START, 0, INIT_STACK).unwrap(); + memory.write_beu32(Instant::START, 4, INIT_ADDR).unwrap(); // Initialize the CPU and make sure it's in the expected state - let cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0); + let cpu = M68k::from_type(cputype, Frequency::from_mhz(10)); //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); + assert_eq!(cpu.state.ssp, INIT_STACK); - let cycle = M68kCycle::new(&cpu, system.clock); - assert_eq!(cycle.decoder.start, INIT_ADDR as u32); + let cycle = M68kCycle::new(&cpu, Instant::START); + assert_eq!(cycle.decoder.start, INIT_ADDR); assert_eq!(cycle.decoder.instruction, Instruction::NOP); - (cpu, cycle, system) + (cpu, cycle, memory) } -fn load_memory(system: &System, data: &[u16]) { +fn load_memory>(bus: &mut Bus, data: &[u16]) { let mut addr = INIT_ADDR; for word in data { - system.get_bus().write_beu16(system.clock, addr, *word).unwrap(); + bus.write_beu16(Instant::START, addr, *word).unwrap(); addr += 2; } } -fn run_timing_test(case: &TimingCase) -> Result<(), Error> { - let (mut cpu, cycle, system) = init_decode_test(case.cpu); +fn run_timing_test(case: &TimingCase) -> Result<(), String> { + let (mut cpu, cycle, mut memory) = init_decode_test(case.cpu); + load_memory(&mut memory, 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(), - ); - - let mut executor = cycle.begin(&mut cpu, &mut adapter); + let mut executor = cycle.begin(&mut cpu, &mut memory); let mut timing = M68kInstructionTiming::new(case.cpu, 16); - load_memory(&system, case.data); executor.decode_next().unwrap(); assert_eq!(executor.cycle.decoder.instruction, case.ins.clone()); @@ -85,7 +75,7 @@ fn run_timing_test(case: &TimingCase) -> Result<(), Error> { Ok(()) } else { println!("{:?}", timing); - Err(Error::new(format!("expected {} but found {}", expected, result))) + Err(format!("expected {} but found {}", expected, result)) } } diff --git a/emulator/libraries/host/src/mouse.rs b/emulator/libraries/host/src/mouse.rs index 3b2fe29..3acfa89 100644 --- a/emulator/libraries/host/src/mouse.rs +++ b/emulator/libraries/host/src/mouse.rs @@ -69,7 +69,7 @@ impl MouseState { let events: Vec = self .buttons.into_iter() - .zip(next_state.buttons.into_iter()) + .zip(next_state.buttons) .enumerate() .filter_map(|(i, (prev, next))| { if prev != next { diff --git a/emulator/libraries/host/src/traits.rs b/emulator/libraries/host/src/traits.rs index 81154a4..8239b4f 100644 --- a/emulator/libraries/host/src/traits.rs +++ b/emulator/libraries/host/src/traits.rs @@ -24,8 +24,11 @@ pub enum HostError { Specific(E), } -/* -impl fmt::Display for HostError { + +impl fmt::Display for HostError +where + E: fmt::Display, +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { HostError::TTYNotSupported => write!(f, "This frontend doesn't support PTYs"), @@ -38,7 +41,6 @@ impl fmt::Display for HostError { } } } -*/ pub trait Host { type Error: Error; diff --git a/emulator/libraries/parsing/src/lib.rs b/emulator/libraries/parsing/src/lib.rs index 49dee09..4e5164b 100644 --- a/emulator/libraries/parsing/src/lib.rs +++ b/emulator/libraries/parsing/src/lib.rs @@ -272,8 +272,6 @@ impl<'input> AssemblyLexer<'input> { break; } } - } else { - } } else if *ch == ' ' || *ch == '\t' || *ch == '\r' { self.chars.next(); diff --git a/tests/harte_tests/latest.txt b/tests/harte_tests/latest.txt index 2f284a3..53bdaa2 100644 --- a/tests/harte_tests/latest.txt +++ b/tests/harte_tests/latest.txt @@ -1,4 +1,4 @@ -Last run on 2024-03-14 at commit 545f339fe2714cc648bd4a01506518a13c1faf39 +Last run on 2024-03-15 at commit 59306bceff1a5964902118f33034086a349e2fd3 ABCD.json.gz completed: 7993 passed, 72 FAILED ADD.b.json.gz completed, all passed! @@ -11,119 +11,3 @@ ADDX.l.json.gz completed: 5472 passed, 2593 FAILED ADDX.w.json.gz completed, all passed! AND.b.json.gz completed, all passed! AND.l.json.gz completed: 7779 passed, 286 FAILED -AND.w.json.gz completed: 7764 passed, 301 FAILED -ANDItoCCR.json.gz completed, all passed! -ANDItoSR.json.gz completed, all passed! -ASL.b.json.gz completed: 8063 passed, 2 FAILED -ASL.l.json.gz completed, all passed! -ASL.w.json.gz completed: 7896 passed, 169 FAILED -ASR.b.json.gz completed: 7783 passed, 282 FAILED -ASR.l.json.gz completed: 8029 passed, 36 FAILED -ASR.w.json.gz completed: 7891 passed, 174 FAILED -BCHG.json.gz completed, all passed! -BCLR.json.gz completed, all passed! -BSET.json.gz completed, all passed! -BSR.json.gz completed, all passed! -BTST.json.gz completed: 8052 passed, 13 FAILED -Bcc.json.gz completed, all passed! -CHK.json.gz completed: 7744 passed, 321 FAILED -CLR.b.json.gz completed, all passed! -CLR.l.json.gz completed: 7472 passed, 593 FAILED -CLR.w.json.gz completed: 7465 passed, 600 FAILED -CMP.b.json.gz completed, all passed! -CMP.l.json.gz completed, all passed! -CMP.w.json.gz completed, all passed! -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 15m 0s diff --git a/tests/harte_tests/src/main.rs b/tests/harte_tests/src/main.rs index f6240e4..c167f83 100644 --- a/tests/harte_tests/src/main.rs +++ b/tests/harte_tests/src/main.rs @@ -2,7 +2,7 @@ const DEFAULT_HARTE_TESTS: &str = "tests/ProcessorTests/680x0/68000/v1/"; use std::io::prelude::*; -use std::fmt::{Debug, UpperHex}; +use std::fmt::{Write, Debug, UpperHex}; use std::path::PathBuf; use std::time::SystemTime; use std::fs::{self, File}; @@ -146,6 +146,7 @@ impl TestCase { } +#[allow(clippy::uninit_vec)] fn init_execute_test(cputype: M68kType, state: &TestState) -> Result<(M68k, MemoryBlock), Error> { // Insert basic initialization let len = 0x100_0000; @@ -274,13 +275,15 @@ fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> { Ok(()) => Ok(()), Err(err) => { if !args.quiet { + let mut writer = String::new(); if args.debug { case.dump(); - println!(); - //initial_cpu.dump_state(); - //cpu.dump_state(); + writeln!(writer).unwrap(); + initial_cpu.dump_state(&mut writer).unwrap(); + cpu.dump_state(&mut writer).unwrap(); } - println!("FAILED: {:?}", err); + writeln!(writer, "FAILED: {:?}", err).unwrap(); + println!("{}", writer); } Err(err) }, @@ -311,11 +314,9 @@ fn test_json_file(path: PathBuf, args: &Args) -> (usize, usize, String) { } // Only run the test if it's selected by the exceptions flag - if case.is_extended_exception_case() && args.exceptions == Selection::ExcludeAddr { - continue; - } else if case.is_exception_case() && args.exceptions == Selection::Exclude { - continue; - } else if !case.is_exception_case() && args.exceptions == Selection::Only { + if case.is_extended_exception_case() && args.exceptions == Selection::ExcludeAddr + || case.is_exception_case() && args.exceptions == Selection::Exclude + || !case.is_exception_case() && args.exceptions == Selection::Only { continue; } diff --git a/tests/rad_tests/src/main.rs b/tests/rad_tests/src/main.rs index 20b9555..a5061df 100644 --- a/tests/rad_tests/src/main.rs +++ b/tests/rad_tests/src/main.rs @@ -176,7 +176,7 @@ where if actual == expected { Ok(()) } else { - Err(Error::assertion(&format!("{:#X} != {:#X}, {}", actual, expected, message))) + Err(Error::assertion(format!("{:#X} != {:#X}, {}", actual, expected, message))) } } @@ -255,7 +255,7 @@ fn assert_state(cpu: &Z80, system: &System, io_bus: Rc>, expected: let expected_im: InterruptMode = expected.im.into(); if cpu.state.im != expected_im { - return Err(Error::assertion(&format!("{:?} != {:?}, im", cpu.state.im, expected_im))); + return Err(Error::assertion(format!("{:?} != {:?}, im", cpu.state.im, expected_im))); } assert_value(cpu.state.iff1 as u8, expected.iff1, "iff1")?; assert_value(cpu.state.iff2 as u8, expected.iff2, "iff2")?; @@ -280,13 +280,13 @@ fn assert_state(cpu: &Z80, system: &System, io_bus: Rc>, expected: } fn step_cpu_and_assert(cpu: &mut Z80, system: &System, io_bus: Rc>, case: &TestCase, args: &Args) -> Result<(), Error> { - let clock_elapsed = cpu.step(&system)?; + let clock_elapsed = cpu.step(system)?; - assert_state(&cpu, &system, io_bus, &case.final_state, args.check_extra_flags, &case.ports)?; + assert_state(cpu, system, io_bus, &case.final_state, args.check_extra_flags, &case.ports)?; if args.check_timings { let cycles = clock_elapsed / cpu.frequency.period_duration(); if cycles != case.cycles.len() as Address { - return Err(Error::assertion(&format!("expected instruction to take {} cycles, but took {}", case.cycles.len(), cycles))); + return Err(Error::assertion(format!("expected instruction to take {} cycles, but took {}", case.cycles.len(), cycles))); } } @@ -305,7 +305,7 @@ fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> { if !args.quiet { if args.debug { case.dump(); - println!(""); + println!(); initial_cpu.dump_state(system.clock); cpu.dump_state(system.clock); } @@ -425,7 +425,7 @@ fn run_all_tests(args: &Args) { } } - println!(""); + println!(); println!("passed: {}, failed: {}, total {:.0}%", passed, failed, ((passed as f32) / (passed as f32 + failed as f32)) * 100.0); println!("completed in {}m {}s", elapsed_secs / 60, elapsed_secs % 60); } @@ -439,7 +439,7 @@ fn is_undocumented_instruction(name: &str) -> bool { match (opcodes[0], opcodes[1]) { (0xCB, op) => { - op >= 0x30 && op <= 0x37 + (0x30..=0x37).contains(&op) }, (0xDD, 0xCB) | (0xFD, 0xCB) => { @@ -449,9 +449,9 @@ fn is_undocumented_instruction(name: &str) -> bool { (0xFD, op) => { let upper = op & 0xF0; let lower = op & 0x0F; - !(lower == 0x06 && upper >= 0x30 && upper <= 0xB0 && upper != 0x70) && - !(lower == 0x0E && upper >= 0x40 && upper <= 0xB0) && - !(op >= 0x70 && op <= 0x77 && op != 0x76) && + !(lower == 0x06 && (0x30..=0xB0).contains(&upper) && upper != 0x70) && + !(lower == 0x0E && (0x40..=0xB0).contains(&upper)) && + !((0x70..=0x77).contains(&op) && op != 0x76) && !(op >= 0x21 && op <= 0x23 && op >= 0x34 && op <= 0x36 && op >= 0x29 && op <= 0x2B) && !(lower == 0x09 && upper <= 0x30) && !(op == 0xE1 || op == 0xE3 || op == 0xE5 || op == 0xE9 || op == 0xF9) diff --git a/todo.txt b/todo.txt index f54a508..ae0b299 100644 --- a/todo.txt +++ b/todo.txt @@ -1,34 +1,18 @@ -* 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 - -* move the BusPort breakup code to m68k -* implement BusAccess for BusPort +* fix dump_state everywhere, which now requires a writer. Is there an easier way? Maybe serde? Is there a way that doesn't require std +* can you clean it up more? +* implement the inspect and debug traits * move the interrupt controller logic to the step() function only, and have a customish interrupt interface into the sim -* move the impls for Step, Transmutable, etc into a moa.rs file or something -* the remaining code should really use Addressable, and then we can swap it for BusAccess - -* could you use the m68k cpu status enum for interrupts, and start handling the interrupt in the next step? but that will affect tests and behaviour if it takes two steps - to get to the same point... - -* the idea would be, instead of argument drilling, you create an object that is short lived, that lasts one instruction, or possibly even parts of one instruction, and - it has some references instead of "moving" data (or if you move, you move and move out without cloning), such that you can bundle everything up, call a method on the - bundle, with the execution context and state all part of or reference by the bundle, all instructions would be implemented on the bundle and not the state alone, and - after the instruction, or when transitioning from one phase to the next, you'd decompose the bundle back into its parts, and return before being called again to - repeat the process with the next instruction +* do the Z80? Should that be another PR? +* fix the tests +* fix all the clippy issues * it doesn't work when using debug due to math checks, so fix them - - * change all the inspection and debugging things to return a struct which can then be printed by the frontend + * there are many issues with the coprocessor address space, and the VDP * I mapped the sn sound chip into 0xC00010, in the middle of the VDP's address space, and didn't get a runtime error!!! needs fixing * there should be a better way of aliasing addresses. Can you make the actual Z80 bus get mapped into 0xA00000? @@ -57,7 +41,6 @@ * add rust runtime checks for math to look for overflow errors * fix the watchers in the Bus, maybe make them manual * make it possible to compile without audio support (minifb frontend requires it atm) -* does Z80 need a customized Z80BusPort like the 68k? * can you make it so you don't need borrow_mut() so much? From d0037c812507954d352f822f727461ce05d61eb9 Mon Sep 17 00:00:00 2001 From: transistor Date: Sat, 16 Mar 2024 13:15:34 -0700 Subject: [PATCH 8/9] Fixed tests and clippy warnings --- Cargo.lock | 1 - emulator/core/src/devices.rs | 2 +- emulator/cpus/m68k/src/decode.rs | 5 +- emulator/cpus/m68k/src/memory.rs | 2 +- emulator/cpus/m68k/src/moa.rs | 22 +- emulator/cpus/m68k/src/tests.rs | 255 +++++++++--------- emulator/cpus/m68k/tests/decode_tests.rs | 17 +- emulator/cpus/m68k/tests/execute_tests.rs | 46 +++- .../cpus/m68k/tests/musashi_timing_tests.rs | 22 +- emulator/cpus/m68k/tests/timing_tests.rs | 22 +- emulator/cpus/z80/src/debugger.rs | 2 +- emulator/cpus/z80/src/decode.rs | 17 +- emulator/cpus/z80/src/execute.rs | 6 +- emulator/cpus/z80/src/state.rs | 1 - emulator/frontends/common/src/cpal.rs | 4 +- .../frontends/console/src/bin/moa-bench.rs | 2 +- .../frontends/console/src/bin/moa-computie.rs | 6 +- .../console/src/bin/moa-console-genesis.rs | 2 +- emulator/frontends/console/src/lib.rs | 2 +- emulator/libraries/debugger/src/lib.rs | 2 +- emulator/peripherals/yamaha/src/ym2612.rs | 11 +- .../systems/genesis/src/peripherals/ym7101.rs | 2 +- tests/harte_tests/Cargo.toml | 5 +- tests/harte_tests/latest.txt | 118 +++++++- tests/rad_tests/src/main.rs | 6 +- todo.txt | 2 +- 26 files changed, 367 insertions(+), 215 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 04f274e..70d773e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -521,7 +521,6 @@ dependencies = [ "emulator-hal-memory", "femtos", "flate2", - "moa-core", "moa-m68k", "serde", "serde_derive", diff --git a/emulator/core/src/devices.rs b/emulator/core/src/devices.rs index 5b38e1a..1da73bd 100644 --- a/emulator/core/src/devices.rs +++ b/emulator/core/src/devices.rs @@ -171,7 +171,7 @@ pub trait Debuggable { fn remove_breakpoint(&mut self, addr: Address); fn print_current_step(&mut self, system: &System) -> Result<(), Error>; - fn print_disassembly(&mut self, addr: Address, count: usize); + fn print_disassembly(&mut self, system: &System, addr: Address, count: usize); fn run_command(&mut self, system: &System, args: &[&str]) -> Result; } diff --git a/emulator/cpus/m68k/src/decode.rs b/emulator/cpus/m68k/src/decode.rs index e64b815..8c31f66 100644 --- a/emulator/cpus/m68k/src/decode.rs +++ b/emulator/cpus/m68k/src/decode.rs @@ -92,13 +92,14 @@ impl M68kDecoder { Ok(()) } - pub fn dump_disassembly(&mut self, bus: &mut Bus, memory: &mut M68kBusPort, start: u32, length: u32) + pub fn dump_disassembly(&mut self, bus: &mut Bus, start: u32, length: u32) where Bus: BusAccess, { + let mut memory = M68kBusPort::default(); let mut next = start; while next < (start + length) { - match self.decode_at(bus, memory, self.is_supervisor, next) { + match self.decode_at(bus, &mut memory, self.is_supervisor, next) { Ok(()) => { self.dump_decoded(memory.current_clock, bus); next = self.end; diff --git a/emulator/cpus/m68k/src/memory.rs b/emulator/cpus/m68k/src/memory.rs index 8dab166..5826802 100644 --- a/emulator/cpus/m68k/src/memory.rs +++ b/emulator/cpus/m68k/src/memory.rs @@ -142,7 +142,7 @@ impl M68kBusPort { 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), + address_mask: 1_u32.checked_shl(info.address_width as u32).unwrap_or(0).wrapping_sub(1), cycle_start_clock: clock, current_clock: clock, } diff --git a/emulator/cpus/m68k/src/moa.rs b/emulator/cpus/m68k/src/moa.rs index 46ac931..46a05cd 100644 --- a/emulator/cpus/m68k/src/moa.rs +++ b/emulator/cpus/m68k/src/moa.rs @@ -16,7 +16,7 @@ impl Steppable for M68k { let mut adapter: bus::BusAdapter = bus::BusAdapter::new( &mut *bus, |addr| addr as u64, - |err| err.try_into().unwrap(), + |err| err, ); let mut executor = cycle.begin(self, &mut adapter); @@ -24,7 +24,7 @@ impl Steppable for M68k { executor.step()?; let interrupt = system.get_interrupt_controller().check(); - if let (priority, Some(ack)) = executor.check_pending_interrupts(interrupt)? { + if let (priority, Some(_)) = executor.check_pending_interrupts(interrupt)? { log::debug!("interrupt: {:?} @ {} ns", priority, system.clock.as_duration().as_nanos()); system.get_interrupt_controller().acknowledge(priority as u8)?; } @@ -35,7 +35,7 @@ impl Steppable for M68k { fn on_error(&mut self, _system: &System) { let mut output = String::with_capacity(256); - self.dump_state(&mut output); + let _ = self.dump_state(&mut output); println!("{}", output); } } @@ -60,8 +60,8 @@ 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)), + Error::Breakpoint(_) => M68kError::Breakpoint, + Error::Other(msg) | Error::Assertion(msg) | Error::Emulator(_, msg) => M68kError::Other(msg.to_string()), } } } @@ -100,9 +100,17 @@ impl Debuggable for M68k { Ok(()) } - fn print_disassembly(&mut self, addr: Address, count: usize) { + fn print_disassembly(&mut self, system: &System, 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); + + let mut bus = system.bus.borrow_mut(); + let mut adapter: bus::BusAdapter = bus::BusAdapter::new( + &mut *bus, + |addr| addr as u64, + |err| err, + ); + + decoder.dump_disassembly(&mut adapter, addr as u32, count as u32); } fn run_command(&mut self, system: &System, args: &[&str]) -> Result { diff --git a/emulator/cpus/m68k/src/tests.rs b/emulator/cpus/m68k/src/tests.rs index 14d180b..a5bd84f 100644 --- a/emulator/cpus/m68k/src/tests.rs +++ b/emulator/cpus/m68k/src/tests.rs @@ -1,4 +1,4 @@ -/( + #[cfg(test)] mod decode_unit_tests { use femtos::Instant; @@ -12,7 +12,10 @@ mod decode_unit_tests { const INIT_ADDR: u32 = 0x00000000; - fn init_decode_test<'a>(cputype: M68kType) -> InstructionDecoding<'a, MemoryBlock> { + fn run_decode_test(cputype: M68kType, mut test_func: F) + where + F: FnMut(&mut InstructionDecoding<'_, MemoryBlock>), + { let mut memory = MemoryBlock::from(vec![0; 0x0000100]); let mut decoder = M68kDecoder::new(cputype, true, 0); let mut decoding = InstructionDecoding { @@ -20,7 +23,8 @@ mod decode_unit_tests { memory: &mut M68kBusPort::default(), decoder: &mut decoder, }; - decoding + + test_func(&mut decoding); } // @@ -29,224 +33,224 @@ mod decode_unit_tests { #[test] fn target_direct_d() { - let mut decoder = init_decode_test(M68kType::MC68010); + run_decode_test(M68kType::MC68010, |decoder| { + let size = Size::Word; - let size = Size::Word; - - let target = decoder.get_mode_as_target(0b000, 0b001, Some(size)).unwrap(); - assert_eq!(target, Target::DirectDReg(1)); + 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 decoder = init_decode_test(M68kType::MC68010); + run_decode_test(M68kType::MC68010, |decoder| { + let size = Size::Word; - let size = Size::Word; - - let target = decoder.get_mode_as_target(0b001, 0b010, Some(size)).unwrap(); - assert_eq!(target, Target::DirectAReg(2)); + 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 decoder = init_decode_test(M68kType::MC68010); + run_decode_test(M68kType::MC68010, |decoder| { + let size = Size::Long; + let expected = 0x12345678; - let size = Size::Long; - let expected = 0x12345678; + decoder.bus.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); - decoder.bus.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); - - let target = decoder.get_mode_as_target(0b010, 0b010, Some(size)).unwrap(); - assert_eq!(target, Target::IndirectAReg(2)); + 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 decoder = init_decode_test(M68kType::MC68010); + run_decode_test(M68kType::MC68010, |decoder| { + let size = Size::Long; + let expected = 0x12345678; - let size = Size::Long; - let expected = 0x12345678; + decoder.bus.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); - decoder.bus.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); - - let target = decoder.get_mode_as_target(0b011, 0b010, Some(size)).unwrap(); - assert_eq!(target, Target::IndirectARegInc(2)); + 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 decoder = init_decode_test(M68kType::MC68010); + run_decode_test(M68kType::MC68010, |decoder| { + let size = Size::Long; + let expected = 0x12345678; - let size = Size::Long; - let expected = 0x12345678; + decoder.bus.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); - decoder.bus.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); - - let target = decoder.get_mode_as_target(0b100, 0b010, Some(size)).unwrap(); - assert_eq!(target, Target::IndirectARegDec(2)); + 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 decoder = init_decode_test(M68kType::MC68010); + run_decode_test(M68kType::MC68010, |decoder| { + let size = Size::Long; + let offset = -8; - let size = Size::Long; - let offset = -8; + decoder.bus.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap(); - decoder.bus.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap(); - - let target = decoder.get_mode_as_target(0b101, 0b100, Some(size)).unwrap(); - assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(4), None, offset)); + 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 decoder = init_decode_test(M68kType::MC68010); + run_decode_test(M68kType::MC68010, |decoder| { + let size = Size::Long; + let offset = -8; + let brief_extension = 0x3800 | (((offset as i8) as u8) as u16); - let size = Size::Long; - let offset = -8; - let brief_extension = 0x3800 | (((offset as i8) as u8) as u16); + decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); + decoder.bus.write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16).unwrap(); - decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - decoder.bus.write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16).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)); + 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 decoder = init_decode_test(M68kType::MC68020); + run_decode_test(M68kType::MC68020, |decoder| { + let size = Size::Word; + let offset = -1843235 as i32; + let brief_extension = 0xF330; - let size = Size::Word; - let offset = -1843235 as i32; - let brief_extension = 0xF330; + decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); + decoder.bus.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); - decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - decoder.bus.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).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)); + 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 decoder = init_decode_test(M68kType::MC68020); + run_decode_test(M68kType::MC68020, |decoder| { + let size = Size::Word; + let offset = -1843235 as i32; + let brief_extension = 0xF3B0; - let size = Size::Word; - let offset = -1843235 as i32; - let brief_extension = 0xF3B0; + decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); + decoder.bus.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); - decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - decoder.bus.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).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)); + 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 decoder = init_decode_test(M68kType::MC68020); + run_decode_test(M68kType::MC68020, |decoder| { + let size = Size::Word; + let offset = -1843235 as i32; + let brief_extension = 0xF370; - let size = Size::Word; - let offset = -1843235 as i32; - let brief_extension = 0xF370; + decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); + decoder.bus.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); - decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - decoder.bus.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); - - let target = decoder.get_mode_as_target(0b110, 0b010, Some(size)).unwrap(); - assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(2), None, offset)); + 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 decoder = init_decode_test(M68kType::MC68010); + run_decode_test(M68kType::MC68010, |decoder| { + let size = Size::Long; + let offset = -8; - let size = Size::Long; - let offset = -8; + decoder.bus.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap(); - decoder.bus.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap(); - - let target = decoder.get_mode_as_target(0b111, 0b010, Some(size)).unwrap(); - assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, None, offset)); + 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 decoder = init_decode_test(M68kType::MC68010); + run_decode_test(M68kType::MC68010, |decoder| { + let size = Size::Word; + let offset = -8; + let brief_extension = 0x3000 | (((offset as i8) as u8) as u16); - let size = Size::Word; - let offset = -8; - let brief_extension = 0x3000 | (((offset as i8) as u8) as u16); + decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); + decoder.bus.write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16).unwrap(); - decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - decoder.bus.write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16).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)); + 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 decoder = init_decode_test(M68kType::MC68020); + run_decode_test(M68kType::MC68020, |decoder| { + let size = Size::Word; + let offset = -1843235 as i32; + let brief_extension = 0xF330; - let size = Size::Word; - let offset = -1843235 as i32; - let brief_extension = 0xF330; + decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); + decoder.bus.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap(); - decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - decoder.bus.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).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)); + 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 decoder = init_decode_test(M68kType::MC68010); + run_decode_test(M68kType::MC68010, |decoder| { + let size = Size::Word; + let expected = 0x1234; - let size = Size::Word; - let expected = 0x1234; + decoder.bus.write_beu16(Instant::START, INIT_ADDR, expected as u16).unwrap(); - decoder.bus.write_beu16(Instant::START, INIT_ADDR, expected as u16).unwrap(); - - let target = decoder.get_mode_as_target(0b111, 0b000, Some(size)).unwrap(); - assert_eq!(target, Target::IndirectMemory(expected, Size::Word)); + 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 decoder = init_decode_test(M68kType::MC68010); + run_decode_test(M68kType::MC68010, |decoder| { + let size = Size::Word; + let expected = 0x12345678; - let size = Size::Word; - let expected = 0x12345678; + decoder.bus.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); - decoder.bus.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); - - let target = decoder.get_mode_as_target(0b111, 0b001, Some(size)).unwrap(); - assert_eq!(target, Target::IndirectMemory(expected, Size::Long)); + 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 decoder = init_decode_test(M68kType::MC68010); + run_decode_test(M68kType::MC68010, |decoder| { + let size = Size::Word; + let expected = 0x1234; - let size = Size::Word; - let expected = 0x1234; + decoder.bus.write_beu16(Instant::START, INIT_ADDR, expected as u16).unwrap(); - decoder.bus.write_beu16(Instant::START, INIT_ADDR, expected as u16).unwrap(); - - let target = decoder.get_mode_as_target(0b111, 0b100, Some(size)).unwrap(); - assert_eq!(target, Target::Immediate(expected)); + let target = decoder.get_mode_as_target(0b111, 0b100, Some(size)).unwrap(); + assert_eq!(target, Target::Immediate(expected)); + }); } } #[cfg(test)] mod execute_unit_tests { use femtos::{Instant, Frequency}; - use emulator_hal::bus::{BusAdapter, BusAccess}; + use emulator_hal::bus::BusAccess; use emulator_hal::step::Step; use emulator_hal_memory::MemoryBlock; @@ -265,13 +269,14 @@ mod execute_unit_tests { // Insert basic initialization let len = 0x10_0000; let mut data = Vec::with_capacity(len); + unsafe { data.set_len(len); } let mut memory = MemoryBlock::from(data); memory.write_beu32(Instant::START, 0, INIT_STACK as u32).unwrap(); memory.write_beu32(Instant::START, 4, INIT_ADDR as u32).unwrap(); let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10)); cpu.step(Instant::START, &mut memory).unwrap(); - let mut cycle = M68kCycle::new(&mut cpu, Instant::START); + let cycle = M68kCycle::new(&mut cpu, Instant::START); let mut executor = cycle.begin(&mut cpu, &mut memory); executor.cycle.decoder.init(true, executor.state.pc); diff --git a/emulator/cpus/m68k/tests/decode_tests.rs b/emulator/cpus/m68k/tests/decode_tests.rs index 7ebbe09..10b145a 100644 --- a/emulator/cpus/m68k/tests/decode_tests.rs +++ b/emulator/cpus/m68k/tests/decode_tests.rs @@ -17,6 +17,7 @@ struct TestCase { ins: Option, } +#[rustfmt::skip] const DECODE_TESTS: &'static [TestCase] = &[ // MC68000 TestCase { cpu: M68kType::MC68000, data: &[0x4e71], ins: Some(Instruction::NOP) }, @@ -66,21 +67,16 @@ const DECODE_TESTS: &'static [TestCase] = &[ fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, MemoryBlock) { // Insert basic initialization - let len = 0x10_0000; + let len = 0x2000; let mut data = Vec::with_capacity(len); + unsafe { data.set_len(len); } let mut memory = MemoryBlock::from(data); memory.write_beu32(Instant::START, 0, INIT_STACK).unwrap(); memory.write_beu32(Instant::START, 4, INIT_ADDR).unwrap(); // Initialize the CPU and make sure it's in the expected state - let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10)); - //cpu.reset_cpu().unwrap(); - //assert_eq!(cpu.state.pc, INIT_ADDR); - //assert_eq!(cpu.state.ssp, INIT_STACK); - + let cpu = M68k::from_type(cputype, Frequency::from_mhz(10)); let cycle = M68kCycle::new(&cpu, Instant::START); - //assert_eq!(cycle.decoder.start, INIT_ADDR); - //assert_eq!(cycle.decoder.instruction, Instruction::NOP); (cpu, cycle, memory) } @@ -100,12 +96,16 @@ fn run_decode_test(case: &TestCase) { Some(ins) => { let mut executor = cycle.begin(&mut cpu, &mut memory); executor.reset_cpu().unwrap(); + assert_eq!(executor.state.pc, INIT_ADDR); + assert_eq!(executor.state.ssp, INIT_STACK); executor.decode_next().unwrap(); assert_eq!(executor.cycle.decoder.instruction, ins.clone()); }, None => { let mut executor = cycle.begin(&mut cpu, &mut memory); executor.reset_cpu().unwrap(); + assert_eq!(executor.state.pc, INIT_ADDR); + assert_eq!(executor.state.ssp, INIT_STACK); let next = executor.decode_next(); println!("{:?}", executor.cycle.decoder.instruction); assert!(next.is_err()); @@ -122,6 +122,7 @@ pub fn run_decode_tests() { } #[test] +#[ignore] pub fn run_assembler_tests() { let mut tests = 0; let mut errors = 0; diff --git a/emulator/cpus/m68k/tests/execute_tests.rs b/emulator/cpus/m68k/tests/execute_tests.rs index a34b6fd..95e7e99 100644 --- a/emulator/cpus/m68k/tests/execute_tests.rs +++ b/emulator/cpus/m68k/tests/execute_tests.rs @@ -44,6 +44,7 @@ where // Insert basic initialization let len = 0x10_0000; let mut data = Vec::with_capacity(len); + unsafe { data.set_len(len); } let mut memory = MemoryBlock::from(data); memory.write_beu32(Instant::START, 0, INIT_STACK).unwrap(); memory.write_beu32(Instant::START, 4, INIT_ADDR).unwrap(); @@ -75,11 +76,9 @@ fn build_state(state: &TestState) -> M68kState { } fn load_memory>(bus: &mut Bus, data: &[u16]) { - let mut addr = INIT_ADDR; - for word in data { - bus.write_beu16(Instant::START, addr, *word).unwrap(); - addr += 2; - } + for i in 0..data.len() { + bus.write_beu16(Instant::START, (i << 1) as u32, data[i]).unwrap(); + } } fn run_test(case: &TestCase) { @@ -111,6 +110,7 @@ pub fn run_execute_tests() { } #[test] +#[ignore] pub fn run_assembler_tests() { use moa_m68k::assembler::M68kAssembler; @@ -152,6 +152,7 @@ fn format_hex(data: &[u16]) -> String { .join(", ") } +#[rustfmt::skip] const TEST_CASES: &'static [TestCase] = &[ TestCase { name: "nop", @@ -218,7 +219,7 @@ const TEST_CASES: &'static [TestCase] = &[ fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x000000FE, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x270A, mem: 0x00000000 }, }, TestCase { - name: "addx with extend", + name: "addx with extend; zero flag not set", ins: Instruction::ADDX(Target::DirectDReg(1), Target::DirectDReg(0), Size::Byte), data: &[ 0xD101 ], cputype: M68kType::MC68010, @@ -226,11 +227,27 @@ const TEST_CASES: &'static [TestCase] = &[ fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x000000FF, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x270A, mem: 0x00000000 }, }, TestCase { - name: "addx with extend and carry", + name: "addx with extend; zero flag set", + ins: Instruction::ADDX(Target::DirectDReg(1), Target::DirectDReg(0), Size::Byte), + data: &[ 0xD101 ], + cputype: M68kType::MC68010, + init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x0000007F, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x2714, mem: 0x00000000 }, + fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x000000FF, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x270A, mem: 0x00000000 }, + }, + TestCase { + name: "addx with extend and carry; zero flag not set", ins: Instruction::ADDX(Target::DirectDReg(1), Target::DirectDReg(0), Size::Byte), data: &[ 0xD101 ], cputype: M68kType::MC68010, init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000080, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x2710, mem: 0x00000000 }, + fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x2711, mem: 0x00000000 }, + }, + TestCase { + name: "addx with extend and carry; zero flag set", + ins: Instruction::ADDX(Target::DirectDReg(1), Target::DirectDReg(0), Size::Byte), + data: &[ 0xD101 ], + cputype: M68kType::MC68010, + init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000080, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x2714, mem: 0x00000000 }, fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x2715, mem: 0x00000000 }, }, TestCase { @@ -239,7 +256,15 @@ const TEST_CASES: &'static [TestCase] = &[ data: &[ 0x027C, 0xF8FF ], cputype: M68kType::MC68010, init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0xA7AA, mem: 0x00000000 }, - fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0xA0AA, mem: 0x00000000 }, + fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0xA00A, mem: 0x00000000 }, + }, + TestCase { + name: "andi with sr 2", + ins: Instruction::ANDtoSR(0xF8FF), + data: &[ 0x027C, 0xF8FF ], + cputype: M68kType::MC68010, + init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0xA7FA, mem: 0x00000000 }, + fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0xA01A, mem: 0x00000000 }, }, TestCase { name: "asl", @@ -560,13 +585,14 @@ const TEST_CASES: &'static [TestCase] = &[ init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0xFF55FFAA }, fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x000055AA, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0xFF55FFAA }, }, + // TODO not sure if these cases are correct TestCase { name: "movep long from even memory upper", ins: Instruction::MOVEP(0, 0, 0, Size::Long, Direction::FromTarget), data: &[ 0x0148, 0x0000 ], cputype: M68kType::MC68010, init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0xAAFFBBFF }, - fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0xAABB0000, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0xAAFFBBFF }, + fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0xAABBCCDD, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0xAAFFBBFF }, }, TestCase { name: "movep long from even memory lower", @@ -603,7 +629,7 @@ const TEST_CASES: &'static [TestCase] = &[ data: &[ 0x007C, 0x00AA ], cputype: M68kType::MC68010, init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0xA755, mem: 0x00000000 }, - fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0xA7FF, mem: 0x00000000 }, + fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0xA71F, mem: 0x00000000 }, }, diff --git a/emulator/cpus/m68k/tests/musashi_timing_tests.rs b/emulator/cpus/m68k/tests/musashi_timing_tests.rs index 110c563..65c3cb5 100644 --- a/emulator/cpus/m68k/tests/musashi_timing_tests.rs +++ b/emulator/cpus/m68k/tests/musashi_timing_tests.rs @@ -17,6 +17,7 @@ fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, MemoryBlock (M68k, M68kCycle, MemoryBlock Result<(), String> { let mut executor = cycle.begin(&mut cpu, &mut memory); let mut timing = M68kInstructionTiming::new(case.cpu, 16); + executor.reset_cpu().unwrap(); + assert_eq!(executor.state.pc, INIT_ADDR); + assert_eq!(executor.state.ssp, INIT_STACK); + executor.decode_next().unwrap(); assert_eq!(executor.cycle.decoder.instruction, case.ins.clone()); @@ -67,15 +68,15 @@ fn run_timing_test(case: &TimingCase) -> Result<(), String> { } #[test] +#[ignore] pub fn run_timing_tests() { let mut errors = 0; for case in TIMING_TESTS { - // NOTE switched to only show the failures rather than all tests - //print!("Testing for {:?}...", case.ins); - //match run_timing_test(case) { - // Ok(()) => println!("ok"), - // Err(err) => { println!("{}", err.msg); errors += 1 }, - //} + print!("Testing for {:?}...", case.ins); + match run_timing_test(case) { + Ok(()) => println!("ok"), + Err(err) => { println!("{:?}", err); errors += 1 }, + } if let Err(_) = run_timing_test(case) { errors += 1; @@ -94,6 +95,7 @@ pub struct TimingCase { pub ins: Instruction, } +#[rustfmt::skip] pub const TIMING_TESTS: &'static [TimingCase] = &[ TimingCase { cpu: M68kType::MC68000, data: &[0xA000], timing: ( 4, 4, 4), ins: Instruction::UnimplementedA(0xA000) }, TimingCase { cpu: M68kType::MC68000, data: &[0xF000], timing: ( 4, 4, 4), ins: Instruction::UnimplementedF(0xF000) }, diff --git a/emulator/cpus/m68k/tests/timing_tests.rs b/emulator/cpus/m68k/tests/timing_tests.rs index 9144c8f..8700fe0 100644 --- a/emulator/cpus/m68k/tests/timing_tests.rs +++ b/emulator/cpus/m68k/tests/timing_tests.rs @@ -28,19 +28,14 @@ fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, MemoryBlock Result<(), String> { let mut executor = cycle.begin(&mut cpu, &mut memory); let mut timing = M68kInstructionTiming::new(case.cpu, 16); + executor.reset_cpu().unwrap(); + assert_eq!(executor.state.pc, INIT_ADDR); + assert_eq!(executor.state.ssp, INIT_STACK); + executor.decode_next().unwrap(); assert_eq!(executor.cycle.decoder.instruction, case.ins.clone()); @@ -83,12 +82,11 @@ fn run_timing_test(case: &TimingCase) -> Result<(), String> { pub fn run_timing_tests() { let mut errors = 0; for case in TIMING_TESTS { - // NOTE switched to only show the failures rather than all tests - //print!("Testing for {:?}...", case.ins); - //match run_timing_test(case) { - // Ok(()) => println!("ok"), - // Err(err) => { println!("{}", err.msg); errors += 1 }, - //} + print!("Testing for {:?}...", case.ins); + match run_timing_test(case) { + Ok(()) => println!("ok"), + Err(err) => { println!("{:?}", err); errors += 1 }, + } if let Err(_) = run_timing_test(case) { errors += 1; diff --git a/emulator/cpus/z80/src/debugger.rs b/emulator/cpus/z80/src/debugger.rs index 99427fb..5c0e5ce 100644 --- a/emulator/cpus/z80/src/debugger.rs +++ b/emulator/cpus/z80/src/debugger.rs @@ -30,7 +30,7 @@ impl Debuggable for Z80 { Ok(()) } - fn print_disassembly(&mut self, addr: Address, count: usize) { + fn print_disassembly(&mut self, _system: &System, addr: Address, count: usize) { let mut decoder = Z80Decoder::default(); decoder.dump_disassembly(&mut self.port, addr as u16, count as u16); } diff --git a/emulator/cpus/z80/src/decode.rs b/emulator/cpus/z80/src/decode.rs index 2a9c5d5..7875c80 100644 --- a/emulator/cpus/z80/src/decode.rs +++ b/emulator/cpus/z80/src/decode.rs @@ -1,4 +1,5 @@ +use core::fmt::Write; use femtos::Instant; use moa_core::{Address, Addressable}; @@ -6,11 +7,9 @@ use moa_core::{Address, Addressable}; use crate::state::Z80Error; use crate::instructions::{Direction, Condition, Register, RegisterPair, IndexRegister, IndexRegisterHalf, SpecialRegister, InterruptMode, Target, LoadTarget, UndocumentedCopy, Instruction}; -use emulator_hal::bus::{BusAccess}; - -struct Z80Bus; - -type Z80Address = (bool, u16); +//use emulator_hal::bus::BusAccess; +// +//type Z80Address = (bool, u16); #[derive(Clone)] pub struct Z80Decoder { @@ -554,10 +553,10 @@ impl Z80Decoder { } pub fn format_instruction_bytes(&mut self, memory: &mut dyn Addressable) -> String { - let ins_data: String = - (0..self.end.saturating_sub(self.start)).map(|offset| - format!("{:02x} ", memory.read_u8(self.clock, (self.start + offset) as Address).unwrap()) - ).collect(); + let mut ins_data = String::new(); + for offset in 0..self.end.saturating_sub(self.start) { + write!(ins_data, "{:02x} ", memory.read_u8(self.clock, (self.start + offset) as Address).unwrap()).unwrap() + } ins_data } diff --git a/emulator/cpus/z80/src/execute.rs b/emulator/cpus/z80/src/execute.rs index cc88890..a0d5fa4 100644 --- a/emulator/cpus/z80/src/execute.rs +++ b/emulator/cpus/z80/src/execute.rs @@ -8,8 +8,6 @@ use crate::state::{Z80, Z80Error, Status, Flags}; use crate::timing::Z80InstructionCycles; -const DEV_NAME: &str = "z80-cpu"; - const FLAGS_NUMERIC: u8 = 0xC0; const FLAGS_ARITHMETIC: u8 = 0x17; const FLAGS_CARRY_HALF_CARRY: u8 = 0x11; @@ -70,8 +68,8 @@ impl From for Z80Error { fn from(err: Error) -> Self { match err { Error::Processor(ex) => Z80Error::BusError(format!("processor error {}", ex)), - Error::Breakpoint(msg) => Z80Error::Breakpoint, - Error::Other(msg) | Error::Assertion(msg) | Error::Emulator(_, msg) => Z80Error::BusError(format!("{}", msg)), + Error::Breakpoint(_) => Z80Error::Breakpoint, + Error::Other(msg) | Error::Assertion(msg) | Error::Emulator(_, msg) => Z80Error::BusError(msg.to_string()), } } diff --git a/emulator/cpus/z80/src/state.rs b/emulator/cpus/z80/src/state.rs index 5a58db0..e738981 100644 --- a/emulator/cpus/z80/src/state.rs +++ b/emulator/cpus/z80/src/state.rs @@ -1,5 +1,4 @@ -use std::fmt; use std::rc::Rc; use std::cell::RefCell; use femtos::{Instant, Frequency}; diff --git a/emulator/frontends/common/src/cpal.rs b/emulator/frontends/common/src/cpal.rs index e503901..24e9910 100644 --- a/emulator/frontends/common/src/cpal.rs +++ b/emulator/frontends/common/src/cpal.rs @@ -1,5 +1,5 @@ -use cpal::{Stream, SampleRate, SampleFormat, StreamConfig, StreamInstant, OutputCallbackInfo, traits::{DeviceTrait, HostTrait, StreamTrait}}; +use cpal::{Stream, SampleRate, SampleFormat, StreamConfig, OutputCallbackInfo, traits::{DeviceTrait, HostTrait, StreamTrait}}; use crate::audio::{AudioOutput, SAMPLE_RATE}; @@ -22,7 +22,7 @@ impl CpalAudioOutput { .with_sample_rate(SampleRate(SAMPLE_RATE as u32)) .into(); - let data_callback = move |data: &mut [f32], info: &OutputCallbackInfo| { + let data_callback = move |data: &mut [f32], _info: &OutputCallbackInfo| { let mut index = 0; while index < data.len() { if let Some((clock, mut frame)) = output.receive() { diff --git a/emulator/frontends/console/src/bin/moa-bench.rs b/emulator/frontends/console/src/bin/moa-bench.rs index 366feef..898ce40 100644 --- a/emulator/frontends/console/src/bin/moa-bench.rs +++ b/emulator/frontends/console/src/bin/moa-bench.rs @@ -3,7 +3,7 @@ use std::thread; use std::time::Duration; use femtos::Frequency; -use moa_core::{System, MemoryBlock, BusPort, Device}; +use moa_core::{System, MemoryBlock, Device}; use moa_m68k::{M68k, M68kType}; use moa_peripherals_generic::AtaDevice; diff --git a/emulator/frontends/console/src/bin/moa-computie.rs b/emulator/frontends/console/src/bin/moa-computie.rs index eafe886..b073823 100644 --- a/emulator/frontends/console/src/bin/moa-computie.rs +++ b/emulator/frontends/console/src/bin/moa-computie.rs @@ -1,5 +1,5 @@ -use clap::{Arg, ArgAction}; +use clap::Arg; use moa_console::ConsoleFrontend; use moa_systems_computie::{build_computie, ComputieOptions}; @@ -18,9 +18,9 @@ fn main() { options.rom = filename.to_string(); } - let mut frontend = ConsoleFrontend::default(); + let frontend = ConsoleFrontend; - let system = build_computie(&mut frontend, options).unwrap(); + let system = build_computie(&frontend, options).unwrap(); frontend.start(matches, system); } diff --git a/emulator/frontends/console/src/bin/moa-console-genesis.rs b/emulator/frontends/console/src/bin/moa-console-genesis.rs index 561129a..dbbf581 100644 --- a/emulator/frontends/console/src/bin/moa-console-genesis.rs +++ b/emulator/frontends/console/src/bin/moa-console-genesis.rs @@ -10,7 +10,7 @@ fn main() { .help("ROM file to load (must be flat binary)")) .get_matches(); - let mut frontend = ConsoleFrontend::default(); + let mut frontend = ConsoleFrontend; let mut options = SegaGenesisOptions::default(); if let Some(filename) = matches.get_one::("ROM") { diff --git a/emulator/frontends/console/src/lib.rs b/emulator/frontends/console/src/lib.rs index b7c08d8..1d5727c 100644 --- a/emulator/frontends/console/src/lib.rs +++ b/emulator/frontends/console/src/lib.rs @@ -14,7 +14,7 @@ impl Host for ConsoleFrontend { fn add_pty(&self) -> Result, HostError> { use moa_common::tty::SimplePty; - Ok(Box::new(SimplePty::open().map_err(|err| HostError::TTYNotSupported)?)) //.map_err(|err| Error::new(format!("console: error opening pty: {:?}", err)))?)) + Ok(Box::new(SimplePty::open().map_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/debugger/src/lib.rs b/emulator/libraries/debugger/src/lib.rs index b559060..9149f3b 100644 --- a/emulator/libraries/debugger/src/lib.rs +++ b/emulator/libraries/debugger/src/lib.rs @@ -154,7 +154,7 @@ impl Debugger { }; if let Some(device) = system.get_next_debuggable_device() { - device.borrow_mut().as_debuggable().unwrap().print_disassembly(addr, count); + device.borrow_mut().as_debuggable().unwrap().print_disassembly(system, addr, count); } }, "c" | "continue" => { diff --git a/emulator/peripherals/yamaha/src/ym2612.rs b/emulator/peripherals/yamaha/src/ym2612.rs index 10aceb4..eb4340f 100644 --- a/emulator/peripherals/yamaha/src/ym2612.rs +++ b/emulator/peripherals/yamaha/src/ym2612.rs @@ -725,13 +725,18 @@ pub struct Ym2612 { channels: Vec, dac: Dac, + // TODO the timer hasn't been implemented yet + #[allow(dead_code)] timer_a_enable: bool, timer_a: u16, + #[allow(dead_code)] timer_a_current: u16, timer_a_overflow: bool, + #[allow(dead_code)] timer_b_enable: bool, timer_b: u8, + #[allow(dead_code)] timer_b_current: u8, timer_b_overflow: bool, @@ -856,8 +861,8 @@ impl Ym2612 { 0x28 => { let num = (data as usize) & 0x07; let ch = match num { - 0 | 1 | 2 => num, - 4 | 5 | 6 => num - 1, + 0..=2 => num, + 4..=6 => num - 1, _ => { log::warn!("{}: attempted key on/off to invalid channel {}", DEV_NAME, num); return; @@ -1025,7 +1030,7 @@ impl Addressable for Ym2612 { fn read(&mut self, _clock: Instant, addr: Address, data: &mut [u8]) -> Result<(), Error> { match addr { - 0 | 1 | 2 | 3 => { + 0..=3 => { // Read the status byte (busy/overflow) data[0] = ((self.timer_a_overflow as u8) << 1) | (self.timer_b_overflow as u8); } diff --git a/emulator/systems/genesis/src/peripherals/ym7101.rs b/emulator/systems/genesis/src/peripherals/ym7101.rs index cd4becf..4f203be 100644 --- a/emulator/systems/genesis/src/peripherals/ym7101.rs +++ b/emulator/systems/genesis/src/peripherals/ym7101.rs @@ -818,7 +818,7 @@ impl Addressable for Ym7101 { 0x00 | 0x02 => self.state.memory.read_data_port(addr, data)?, // Read from Control Port - 0x04 | 0x05 | 0x06 | 0x07 => { + 0x04..=0x07 => { log::debug!("{}: read status byte {:x}", DEV_NAME, self.state.status); for item in data { *item = if (addr % 2) == 0 { diff --git a/tests/harte_tests/Cargo.toml b/tests/harte_tests/Cargo.toml index 7b35f4c..833791e 100644 --- a/tests/harte_tests/Cargo.toml +++ b/tests/harte_tests/Cargo.toml @@ -7,11 +7,8 @@ edition = "2021" femtos = "0.1" emulator-hal = { path = "../../emulator/libraries/emulator-hal/emulator-hal" } emulator-hal-memory = { path = "../../emulator/libraries/emulator-hal/emulator-hal-memory" } +moa-m68k = { path = "../../emulator/cpus/m68k" } -moa-core = { path = "../../emulator/core" } -moa-m68k = { path = "../../emulator/cpus/m68k", features = ["moa"] } - -#thiserror = "1.0" 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 53bdaa2..5e57181 100644 --- a/tests/harte_tests/latest.txt +++ b/tests/harte_tests/latest.txt @@ -1,4 +1,4 @@ -Last run on 2024-03-15 at commit 59306bceff1a5964902118f33034086a349e2fd3 +Last run on 2024-03-16 at commit c20d7afe6e8005ab272602953154280f0e1aa944 ABCD.json.gz completed: 7993 passed, 72 FAILED ADD.b.json.gz completed, all passed! @@ -11,3 +11,119 @@ ADDX.l.json.gz completed: 5472 passed, 2593 FAILED ADDX.w.json.gz completed, all passed! AND.b.json.gz completed, all passed! AND.l.json.gz completed: 7779 passed, 286 FAILED +AND.w.json.gz completed: 7764 passed, 301 FAILED +ANDItoCCR.json.gz completed, all passed! +ANDItoSR.json.gz completed, all passed! +ASL.b.json.gz completed: 8063 passed, 2 FAILED +ASL.l.json.gz completed, all passed! +ASL.w.json.gz completed: 7896 passed, 169 FAILED +ASR.b.json.gz completed: 7783 passed, 282 FAILED +ASR.l.json.gz completed: 8029 passed, 36 FAILED +ASR.w.json.gz completed: 7891 passed, 174 FAILED +BCHG.json.gz completed, all passed! +BCLR.json.gz completed, all passed! +BSET.json.gz completed, all passed! +BSR.json.gz completed, all passed! +BTST.json.gz completed: 8051 passed, 14 FAILED +Bcc.json.gz completed, all passed! +CHK.json.gz completed: 7744 passed, 321 FAILED +CLR.b.json.gz completed, all passed! +CLR.l.json.gz completed: 7472 passed, 593 FAILED +CLR.w.json.gz completed: 7465 passed, 600 FAILED +CMP.b.json.gz completed, all passed! +CMP.l.json.gz completed, all passed! +CMP.w.json.gz completed, all passed! +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: 966036, failed: 34024, total 97% +completed in 0m 7s diff --git a/tests/rad_tests/src/main.rs b/tests/rad_tests/src/main.rs index a5061df..408f338 100644 --- a/tests/rad_tests/src/main.rs +++ b/tests/rad_tests/src/main.rs @@ -449,10 +449,8 @@ fn is_undocumented_instruction(name: &str) -> bool { (0xFD, op) => { let upper = op & 0xF0; let lower = op & 0x0F; - !(lower == 0x06 && (0x30..=0xB0).contains(&upper) && upper != 0x70) && - !(lower == 0x0E && (0x40..=0xB0).contains(&upper)) && - !((0x70..=0x77).contains(&op) && op != 0x76) && - !(op >= 0x21 && op <= 0x23 && op >= 0x34 && op <= 0x36 && op >= 0x29 && op <= 0x2B) && + !(lower == 0x0E && (0x40..=0xB0).contains(&upper) || (0x70..=0x77).contains(&op) && op != 0x76 || op != 0x76 && (0x70..=0x77).contains(&op) || lower == 0x06 && (0x30..=0xB0).contains(&upper) && upper != 0x70) && + !((0x21..=0x23).contains(&op) || (0x34..=0x36).contains(&op) || (0x29..=0x2B).contains(&op)) && !(lower == 0x09 && upper <= 0x30) && !(op == 0xE1 || op == 0xE3 || op == 0xE5 || op == 0xE9 || op == 0xF9) }, diff --git a/todo.txt b/todo.txt index ae0b299..a5b6825 100644 --- a/todo.txt +++ b/todo.txt @@ -1,5 +1,5 @@ -* fix dump_state everywhere, which now requires a writer. Is there an easier way? Maybe serde? Is there a way that doesn't require std +* fix dump_state everywhere, which now requires a writer. Is there an easier way? Is there a way that doesn't require std * can you clean it up more? * implement the inspect and debug traits * move the interrupt controller logic to the step() function only, and have a customish interrupt interface into the sim From 661a4302efe49c03a8be761aca018f8c3cea6965 Mon Sep 17 00:00:00 2001 From: transistor Date: Sat, 16 Mar 2024 18:48:33 -0700 Subject: [PATCH 9/9] Added workspace exclusion for emulator-hal --- Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index a235837..9146329 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,8 @@ members = [ exclude = [ "emulator/frontends/pixels", "emulator/frontends/macroquad", + "emulator/libraries/femtos", + "emulator/libraries/emulator-hal", ] default-members = ["emulator/frontends/minifb"]