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..70d773e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -420,6 +420,17 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "emulator-hal" version = "0.1.0" +dependencies = [ + "femtos", + "fugit", +] + +[[package]] +name = "emulator-hal-memory" +version = "0.1.0" +dependencies = [ + "emulator-hal", +] [[package]] name = "env_logger" @@ -480,6 +491,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" @@ -491,9 +517,10 @@ name = "harte-tests" version = "0.1.0" dependencies = [ "clap 3.2.25", + "emulator-hal", + "emulator-hal-memory", "femtos", "flate2", - "moa-core", "moa-m68k", "serde", "serde_derive", @@ -755,6 +782,8 @@ dependencies = [ "log", "moa-common", "moa-core", + "moa-debugger", + "moa-host", "moa-m68k", "moa-peripherals-generic", "moa-peripherals-motorola", @@ -794,6 +823,7 @@ name = "moa-m68k" version = "0.1.0" dependencies = [ "emulator-hal", + "emulator-hal-memory", "femtos", "log", "moa-core", diff --git a/Cargo.toml b/Cargo.toml index 7450c3d..9146329 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,5 @@ [workspace] +resolver = "2" members = [ "emulator/core", "emulator/frontends/common", @@ -10,6 +11,8 @@ members = [ exclude = [ "emulator/frontends/pixels", "emulator/frontends/macroquad", + "emulator/libraries/femtos", + "emulator/libraries/emulator-hal", ] default-members = ["emulator/frontends/minifb"] @@ -18,5 +21,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..980a358 100644 --- a/docs/log.txt +++ b/docs/log.txt @@ -479,3 +479,15 @@ 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 + +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/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/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/core/src/error.rs b/emulator/core/src/error.rs index cdc5ea8..cd10af0 100644 --- a/emulator/core/src/error.rs +++ b/emulator/core/src/error.rs @@ -1,6 +1,5 @@ use std::fmt; -use std::error::{Error as StdError}; use moa_host::HostError; #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -75,8 +74,8 @@ impl fmt::Display for Error { } impl From> for Error { - fn from(err: HostError) -> Self { - Self::Other(format!("other")) + fn from(_err: HostError) -> Self { + Self::Other("other".to_string()) } } 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 e76553f..09c44da 100644 --- a/emulator/core/src/memory.rs +++ b/emulator/core/src/memory.rs @@ -358,3 +358,47 @@ 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 &mut dyn Addressable { + type Error = Error; + + fn read(&mut self, now: Instant, addr: Address, data: &mut [u8]) -> Result { + (*self).read(now, addr, data)?; + Ok(data.len()) + } + + fn write(&mut self, now: Instant, addr: Address, data: &[u8]) -> Result { + (*self).write(now, addr, data)?; + Ok(data.len()) + } +} + diff --git a/emulator/cpus/m68k/Cargo.toml b/emulator/cpus/m68k/Cargo.toml index 483a72f..ee4eb8f 100644 --- a/emulator/cpus/m68k/Cargo.toml +++ b/emulator/cpus/m68k/Cargo.toml @@ -7,6 +7,13 @@ edition = "2021" log = "0.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" } + +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/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/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 9849c14..7f5c709 100644 --- a/emulator/cpus/m68k/src/debugger.rs +++ b/emulator/cpus/m68k/src/debugger.rs @@ -1,9 +1,10 @@ -use moa_core::{System, Error, Address, Addressable, Debuggable}; +use femtos::Instant; +use emulator_hal::bus::BusAccess; -use super::state::M68k; -use super::decode::M68kDecoder; +use super::state::M68kError; use super::execute::M68kCycleExecutor; +use super::memory::M68kAddress; #[derive(Clone, Default)] pub struct StackTracer { @@ -25,54 +26,16 @@ 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, } -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}", self.port.read_beu32(system.clock, *addr as Address)?); - } - }, - "so" | "stepout" => { - self.debugger.step_until_return = Some(self.debugger.stack_tracer.calls.len() - 1); - }, - _ => { return Ok(true); }, - } - Ok(false) - } -} - -impl<'a> M68kCycleExecutor<'a> { - pub fn check_breakpoints(&mut self) -> Result<(), Error> { +impl<'a, Bus, BusError> M68kCycleExecutor<'a, Bus> +where + Bus: BusAccess, +{ + 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 { @@ -80,7 +43,7 @@ impl<'a> M68kCycleExecutor<'a> { 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 fc94bf2..8c31f66 100644 --- a/emulator/cpus/m68k/src/decode.rs +++ b/emulator/cpus/m68k/src/decode.rs @@ -1,10 +1,9 @@ use femtos::Instant; - -use moa_core::{Address, Addressable, BusPort}; +use emulator_hal::bus::BusAccess; use crate::state::{M68kType, M68kError, Exceptions}; -use crate::memory::M68kBusPort; +use crate::memory::{M68kBusPort, M68kAddress}; use crate::instructions::{ Size, Sign, @@ -49,10 +48,13 @@ pub struct M68kDecoder { pub instruction: Instruction, } -pub struct InstructionDecoding<'a> { - port: &'a mut BusPort, - memory: &'a mut M68kBusPort, - decoder: &'a mut M68kDecoder, +pub struct InstructionDecoding<'a, Bus> +where + Bus: BusAccess, +{ + pub(crate) bus: &'a mut Bus, + pub(crate) memory: &'a mut M68kBusPort, + pub(crate) decoder: &'a mut M68kDecoder, } impl M68kDecoder { @@ -76,10 +78,13 @@ 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, 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, }; @@ -87,21 +92,22 @@ 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, 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(port, memory, self.is_supervisor, next) { + match self.decode_at(bus, &mut 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 as Address).unwrap()); - }, - _ => { }, + if let M68kError::Exception(Exceptions::IllegalInstruction) = err { + println!(" at {:08x}: {:04x}", self.start, bus.read_beu16(memory.current_clock, self.start).unwrap()); } return; }, @@ -109,18 +115,24 @@ 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, 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)) as Address).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); } } -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 +158,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 +233,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 +251,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 +262,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 +433,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 +471,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 +487,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 +497,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 +521,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 +552,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 +579,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 +612,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 +642,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 +728,31 @@ impl<'a> InstructionDecoding<'a> { } } - fn read_instruction_word(&mut self) -> Result { - let word = self.memory.read_instruction_word(self.port, self.decoder.is_supervisor, self.decoder.end)?; + fn read_instruction_word(&mut self) -> Result> { + 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)?; + fn read_instruction_long(&mut self) -> Result> { + let word = self.memory.read_instruction_long(self.bus, 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 +762,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 +815,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..8aeca3c 100644 --- a/emulator/cpus/m68k/src/execute.rs +++ b/emulator/cpus/m68k/src/execute.rs @@ -1,10 +1,10 @@ -use femtos::{Instant, Duration}; +use femtos::Instant; +use emulator_hal::bus::{self, BusAccess}; +use emulator_hal::step::Step; -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::state::{M68k, M68kType, M68kError, M68kState, Status, Flags, Exceptions, InterruptPriority}; +use crate::memory::{MemType, MemAccess, M68kBusPort, M68kAddress}; use crate::decode::M68kDecoder; use crate::debugger::M68kDebugger; use crate::timing::M68kInstructionTiming; @@ -48,7 +48,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, } } @@ -59,162 +59,126 @@ 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> { + pub fn begin(self, cpu: &mut M68k, bus: Bus) -> M68kCycleExecutor<'_, Bus> + where + Bus: BusAccess, + { + cpu.stats.cycle_number += 1; + if cpu.stats.cycle_number > 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; + } + M68kCycleExecutor { state: &mut cpu.state, - port: &mut cpu.port, + bus, debugger: &mut cpu.debugger, cycle: self, } } } -pub struct M68kCycleExecutor<'a> { +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: &'a mut BusPort, + pub bus: Bus, pub debugger: &'a mut M68kDebugger, pub cycle: M68kCycle, } -impl<'a> M68kCycleExecutor<'a> { - #[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(self.port, self.state.ssp, 0x40); - println!(); - } - +impl<'a, Bus> M68kCycleExecutor<'a, Bus> +where + Bus: BusAccess, +{ 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::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> M68kCycleExecutor<'a> { +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(()) } #[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) -> Result<(), M68kError> { self.check_breakpoints()?; - self.decode_and_execute()?; + let result = self.decode_and_execute(); + self.process_error(result)?; - self.check_pending_interrupts(system)?; - Ok(self.cycle.timing.calculate_clocks(false, 1)) + // 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 - self.state.pending_ipl = match system.get_interrupt_controller().check() { - (true, priority) => InterruptPriority::from_u8(priority), - (false, _) => 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; @@ -224,11 +188,12 @@ impl<'a> M68kCycleExecutor<'a> { 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 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))); } } @@ -236,39 +201,10 @@ impl<'a> M68kCycleExecutor<'a> { self.state.current_ipl = self.state.pending_ipl; } - Ok(()) + Ok((self.state.current_ipl, None)) } - /* - #[inline] - pub fn check_pending_interrupts2(&mut self, interrupt: Option<(InterruptPriority, u8)>) -> Result { - self.state.pending_ipl = interrupt.unwrap_or(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 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(()); - } - } - - if pending_ipl < current_ipl { - self.state.current_ipl = self.state.pending_ipl; - } - - Ok(()) - } - */ - - 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 +220,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(); @@ -307,13 +243,13 @@ impl<'a> M68kCycleExecutor<'a> { 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(()) } - 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; @@ -332,23 +268,39 @@ impl<'a> M68kCycleExecutor<'a> { 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 decode_and_execute(&mut self) -> Result<(), M68kError> { + 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, false)?; + Ok(()) + }, + Err(err) => Err(err), + } + } + + #[inline] + 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)?; + 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); @@ -358,7 +310,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 +406,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 +430,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 +441,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 +449,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 +470,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 +479,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 +510,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 +543,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 +554,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 +562,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 +573,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 +582,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 +591,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 +600,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 +617,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 +627,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 +643,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 +653,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 +663,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 +672,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 +688,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 +700,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 +709,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 +718,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 +733,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 +773,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 +806,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 +815,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 +834,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 +847,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 +861,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,24 +876,24 @@ 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); - 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(()) } - 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 +905,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 +928,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 +943,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 +979,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,17 +1026,17 @@ 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; + 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; @@ -1092,10 +1044,10 @@ 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)?; + self.set_address_sized(addr, self.state.d_reg[i], size)?; addr += size.in_bytes(); } mask >>= 1; @@ -1103,7 +1055,7 @@ impl<'a> M68kCycleExecutor<'a> { 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; @@ -1111,30 +1063,30 @@ 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); 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; } 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; - 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)?; @@ -1144,7 +1096,7 @@ impl<'a> M68kCycleExecutor<'a> { }, 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; @@ -1156,14 +1108,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 +1124,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 +1137,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 +1153,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 +1170,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 +1190,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 +1198,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 +1207,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 +1241,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 +1252,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 +1264,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 +1283,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 +1300,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 +1311,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 +1321,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 +1331,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 +1346,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 +1367,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 +1378,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 +1386,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 +1407,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 +1424,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,60 +1451,60 @@ 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)), 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) }, } } - 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); @@ -1562,42 +1514,42 @@ impl<'a> M68kCycleExecutor<'a> { }, 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)), } 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) => { @@ -1608,13 +1560,13 @@ impl<'a> M68kCycleExecutor<'a> { 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, _) => { @@ -1652,47 +1604,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: M68kAddress, size: Size) -> Result> { + let is_supervisor = self.is_supervisor(); + self.cycle.memory.read_data_sized(&mut self.bus, 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: M68kAddress, value: u32, size: Size) -> Result<(), M68kError> { + let is_supervisor = self.is_supervisor(); + self.cycle.memory.write_data_sized(&mut self.bus, is_supervisor, addr, size, value) } - fn push_word(&mut self, value: u16) -> Result<(), M68kError> { + 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)?; + self.cycle.memory.write_data_sized(&mut self.bus, is_supervisor, addr, Size::Word, value as u32)?; Ok(()) } - fn pop_word(&mut self) -> Result { + 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)?; + let value = self.cycle.memory.read_data_sized(&mut self.bus, 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> { + 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)?; + self.cycle.memory.write_data_sized(&mut self.bus, is_supervisor, addr, Size::Long, value)?; Ok(()) } - fn pop_long(&mut self) -> Result { + 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)?; + let value = self.cycle.memory.read_data_sized(&mut self.bus, is_supervisor, addr, Size::Long)?; *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(()) @@ -1725,7 +1679,7 @@ impl<'a> M68kCycleExecutor<'a> { 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], } } @@ -1769,7 +1723,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/lib.rs b/emulator/cpus/m68k/src/lib.rs index c70c624..a8253e4 100644 --- a/emulator/cpus/m68k/src/lib.rs +++ b/emulator/cpus/m68k/src/lib.rs @@ -9,5 +9,9 @@ pub mod memory; pub mod timing; pub mod tests; -pub use self::state::{M68k, M68kType, M68kError}; +#[cfg(feature = "moa")] +pub mod moa; + +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 9a1c921..5826802 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::{BusType, BusAccess}; +use emulator_hal::bus::BusAccess; -use moa_core::{Address, Addressable, BusPort}; - -use crate::state::{M68k, M68kError, Exceptions}; +use crate::state::{M68k, M68kError, CpuInfo, Exceptions}; use crate::instructions::Size; #[repr(u8)] @@ -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,9 @@ impl MemoryRequest { } } +//pub type M68kAddress = (FunctionCode, u32); +pub type M68kAddress = u32; +pub type M68kAddressSpace = (FunctionCode, u32); #[derive(Clone, Debug)] pub struct InstructionRequest { @@ -110,8 +113,9 @@ pub struct InstructionRequest { #[derive(Clone, Debug)] pub struct M68kBusPort { - //pub port: BusPort, pub request: MemoryRequest, + pub data_bytewidth: usize, + pub address_mask: u32, pub cycle_start_clock: Instant, pub current_clock: Instant, } @@ -122,10 +126,11 @@ impl M68k { } impl Default for M68kBusPort { - fn default(/* port: BusPort */) -> Self { + fn default() -> Self { Self { - //port, request: Default::default(), + data_bytewidth: 32 / 8, + address_mask: 0xFFFF_FFFF, cycle_start_clock: Instant::START, current_clock: Instant::START, } @@ -133,43 +138,101 @@ 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.checked_shl(info.address_width as u32).unwrap_or(0).wrapping_sub(1), cycle_start_clock: clock, current_clock: clock, } } - pub(crate) fn read_data_sized(&mut self, port: &mut BusPort, is_supervisor: bool, addr: Address, size: Size) -> Result { - 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), - }?) + 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) { + let addr_index = (addr + i as M68kAddress) & self.address_mask; + 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))?; + } + Ok(()) } - pub(crate) fn write_data_sized(&mut self, port: &mut BusPort, is_supervisor: bool, addr: Address, value: u32, size: Size) -> Result<(), M68kError> { - 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), - }?) + 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) { + let addr_index = (addr + i as M68kAddress) & self.address_mask; + let end = cmp::min(i + self.data_bytewidth, data.len()); + bus.write(clock, addr_index, &data[i..end]) + .map_err(|err| M68kError::BusError(err))?; + } + Ok(()) } - pub(crate) fn read_instruction_word(&mut self, port: &mut BusPort, is_supervisor: bool, addr: u32) -> Result { + 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, bus: &mut Bus, is_supervisor: bool, addr: M68kAddress, size: Size) -> Result> + where + Bus: BusAccess, + { + self.start_request(is_supervisor, addr, size, MemAccess::Read, MemType::Data, false)?; + self.read_sized(bus, addr, size) + } + + 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, size, MemAccess::Write, MemType::Data, false)?; + self.write_sized(bus, addr, size, value) + } + + 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(port.read_beu16(self.current_clock, addr as Address)?) + Ok(self.read_sized(bus, addr, Size::Word)? as u16) } - 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, bus: &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)?) + 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 { + 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), @@ -185,13 +248,9 @@ impl M68kBusPort { validate_address(addr) } } - - 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); - } } -fn validate_address(addr: u32) -> Result { +fn validate_address(addr: u32) -> Result> { if addr & 0x1 == 0 { Ok(addr) } else { @@ -199,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..46a05cd --- /dev/null +++ b/emulator/cpus/m68k/src/moa.rs @@ -0,0 +1,132 @@ + +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, + ); + + let mut executor = cycle.begin(self, &mut adapter); + executor.check_breakpoints()?; + executor.step()?; + + let interrupt = system.get_interrupt_controller().check(); + 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)?; + } + + self.cycle = Some(executor.end()); + Ok(self.last_cycle_duration()) + } + + fn on_error(&mut self, _system: &System) { + let mut output = String::with_capacity(256); + let _ = 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(_) => M68kError::Breakpoint, + Error::Other(msg) | Error::Assertion(msg) | Error::Emulator(_, msg) => M68kError::Other(msg.to_string()), + } + } +} + +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.bus, true, self.state.pc); + //self.decoder.dump_decoded(&mut self.bus); + //self.dump_state(); + Ok(()) + } + + fn print_disassembly(&mut self, system: &System, addr: Address, count: usize) { + let mut decoder = M68kDecoder::new(self.info.chip, true, 0); + + 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 { + 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 00a7f7b..c2a46aa 100644 --- a/emulator/cpus/m68k/src/state.rs +++ b/emulator/cpus/m68k/src/state.rs @@ -1,12 +1,8 @@ -use std::rc::Rc; -use std::cell::RefCell; -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; @@ -81,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, @@ -178,7 +174,7 @@ pub struct M68kState { } #[derive(Clone, Debug, thiserror::Error)] -pub enum M68kError { +pub enum M68kError { #[error("cpu halted")] Halted, #[error("processor exception {0:?}")] @@ -189,16 +185,35 @@ 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), } +#[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, } @@ -221,20 +236,51 @@ impl Default for M68kState { } } +impl M68kState { + 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)?; + 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(&self, writer: &mut W) -> Result<(), fmt::Error> { + self.state.dump_state(writer)?; + + if let Some(cycle) = self.cycle.as_ref() { + 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); + writeln!(writer)?; + Ok(()) + } + + #[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..a5bd84f 100644 --- a/emulator/cpus/m68k/src/tests.rs +++ b/emulator/cpus/m68k/src/tests.rs @@ -1,31 +1,30 @@ #[cfg(test)] mod decode_unit_tests { - use std::rc::Rc; - use std::cell::RefCell; use femtos::Instant; - - use moa_core::{Bus, BusPort, Address, Addressable, MemoryBlock, Device}; + use emulator_hal::bus::BusAccess; + use emulator_hal_memory::MemoryBlock; 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) { - 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)) + 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 { + bus: &mut memory, + memory: &mut M68kBusPort::default(), + decoder: &mut decoder, }; - let decoder = M68kDecoder::new(cputype, true, 0); - (port, decoder) + + test_func(&mut decoding); } // @@ -34,250 +33,252 @@ mod decode_unit_tests { #[test] fn target_direct_d() { - let (mut port, 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(&mut port, 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 port, 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(&mut port, 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 port, 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(); - port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); - - let target = decoder.get_mode_as_target(&mut port, 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 port, 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(); - port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); - - let target = decoder.get_mode_as_target(&mut port, 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 port, 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(); - port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); - - let target = decoder.get_mode_as_target(&mut port, 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 port, 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(); - port.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(); - 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 port, 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(); - 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(); - - let target = decoder.get_mode_as_target(&mut port, 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 port, 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(); - port.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - port.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(); - 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 port, 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(); - port.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - port.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(); - 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 port, 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(); - port.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - port.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(); - 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 port, 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(); - port.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(); - 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 port, 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(); - 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(); - - let target = decoder.get_mode_as_target(&mut port, 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 port, 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(); - port.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap(); - port.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(); - 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 port, 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(); - port.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(); - 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 port, 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(); - port.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap(); - - let target = decoder.get_mode_as_target(&mut port, 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 port, 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(); - port.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(); - 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 moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Steppable, Device}; + use emulator_hal::bus::BusAccess; + use emulator_hal::step::Step; + use emulator_hal_memory::MemoryBlock; 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; + #[allow(clippy::uninit_vec)] fn run_execute_test(cputype: M68kType, mut test_func: F) where - F: FnMut(M68kCycleExecutor), + 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); + 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), system.bus.clone(), 0); - cpu.step(&system).unwrap(); - let mut cycle = M68kCycle::new(&mut cpu, system.clock); - let mut executor = cycle.begin(&mut cpu); + let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10)); + cpu.step(Instant::START, &mut memory).unwrap(); + 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); assert_eq!(executor.state.pc, INIT_ADDR as u32); assert_eq!(executor.state.ssp, INIT_STACK as u32); @@ -322,7 +323,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.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(); @@ -336,7 +337,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.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(); @@ -351,7 +352,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.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(); @@ -374,5 +375,3 @@ mod execute_unit_tests { }); } } - - 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/m68k/tests/decode_tests.rs b/emulator/cpus/m68k/tests/decode_tests.rs index 93b2d00..10b145a 100644 --- a/emulator/cpus/m68k/tests/decode_tests.rs +++ b/emulator/cpus/m68k/tests/decode_tests.rs @@ -1,15 +1,15 @@ use femtos::{Instant, Frequency}; +use emulator_hal::bus::BusAccess; +use emulator_hal_memory::MemoryBlock; -use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Device}; - -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, @@ -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) }, @@ -64,47 +65,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 = 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), 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); - - let cycle = M68kCycle::new(&cpu, system.clock); - assert_eq!(cycle.decoder.start, INIT_ADDR as u32); - assert_eq!(cycle.decoder.instruction, Instruction::NOP); - (cpu, cycle, system) + let cpu = M68k::from_type(cputype, Frequency::from_mhz(10)); + let cycle = M68kCycle::new(&cpu, Instant::START); + (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 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); + 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); + 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()); @@ -121,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 aa5652d..95e7e99 100644 --- a/emulator/cpus/m68k/tests/execute_tests.rs +++ b/emulator/cpus/m68k/tests/execute_tests.rs @@ -1,15 +1,16 @@ use femtos::{Instant, Frequency}; +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}; - -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; @@ -35,30 +36,30 @@ struct TestCase { } +#[allow(clippy::uninit_vec)] fn run_execute_test(cputype: M68kType, mut test_func: F) where - F: FnMut(M68kCycleExecutor, 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); + 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(); - let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0); - cpu.step(&system).unwrap(); + let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10)); + cpu.step(Instant::START, &mut memory).unwrap(); - let cycle = M68kCycle::new(&cpu, system.clock); - let mut executor = cycle.begin(&mut cpu); + let cycle = M68kCycle::new(&cpu, Instant::START); + let executor = cycle.begin(&mut cpu, &mut memory); - 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 { @@ -74,19 +75,19 @@ fn build_state(state: &TestState) -> M68kState { new_state } -fn load_memory(system: &System, data: &[u16]) { +fn load_memory>(bus: &mut Bus, data: &[u16]) { for i in 0..data.len() { - system.get_bus().write_beu16(system.clock, (i << 1) as Address, data[i]).unwrap(); + bus.write_beu16(Instant::START, (i << 1) as u32, data[i]).unwrap(); } } 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(); @@ -95,7 +96,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); }); } @@ -109,6 +110,7 @@ pub fn run_execute_tests() { } #[test] +#[ignore] pub fn run_assembler_tests() { use moa_m68k::assembler::M68kAssembler; @@ -150,6 +152,7 @@ fn format_hex(data: &[u16]) -> String { .join(", ") } +#[rustfmt::skip] const TEST_CASES: &'static [TestCase] = &[ TestCase { name: "nop", @@ -216,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, @@ -224,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 { @@ -237,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", @@ -558,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", @@ -601,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 c22bb9b..65c3cb5 100644 --- a/emulator/cpus/m68k/tests/musashi_timing_tests.rs +++ b/emulator/cpus/m68k/tests/musashi_timing_tests.rs @@ -1,56 +1,57 @@ use femtos::{Instant, Frequency}; +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); + 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 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); - assert_eq!(cycle.decoder.instruction, Instruction::NOP); - (cpu, cycle, system) + let cpu = M68k::from_type(cputype, Frequency::from_mhz(10)); + let cycle = M68kCycle::new(&cpu, Instant::START); + (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); - let mut executor = cycle.begin(&mut 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 executor = cycle.begin(&mut cpu, &mut memory); let mut timing = M68kInstructionTiming::new(case.cpu, 16); - load_memory(&system, case.data); + 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()); 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, @@ -62,20 +63,20 @@ 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)) } } #[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 489b557..8700fe0 100644 --- a/emulator/cpus/m68k/tests/timing_tests.rs +++ b/emulator/cpus/m68k/tests/timing_tests.rs @@ -1,15 +1,15 @@ use femtos::{Instant, Frequency}; +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 { @@ -24,47 +24,45 @@ 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); + 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 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); - - let cycle = M68kCycle::new(&cpu, system.clock); - assert_eq!(cycle.decoder.start, INIT_ADDR as u32); - assert_eq!(cycle.decoder.instruction, Instruction::NOP); - (cpu, cycle, system) + let cpu = M68k::from_type(cputype, Frequency::from_mhz(10)); + let cycle = M68kCycle::new(&cpu, Instant::START); + (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); - let mut executor = cycle.begin(&mut 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 executor = cycle.begin(&mut cpu, &mut memory); let mut timing = M68kInstructionTiming::new(case.cpu, 16); - load_memory(&system, case.data); + 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()); 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, @@ -76,7 +74,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)) } } @@ -84,12 +82,11 @@ fn run_timing_test(case: &TimingCase) -> Result<(), Error> { 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/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/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 c394caa..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,17 +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::{BusType, BusAccess}; - -struct Z80Bus; - -type Z80Address = (bool, u16); - -impl BusType for Z80Bus { - //type Address = (bool, u16); - type Error = Z80Error; - type Instant = Instant; -} +//use emulator_hal::bus::BusAccess; +// +//type Z80Address = (bool, u16); #[derive(Clone)] pub struct Z80Decoder { @@ -560,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/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/bin/moa-bench.rs b/emulator/frontends/console/src/bin/moa-bench.rs index 5391d09..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; @@ -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..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::new(); + 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 9b4c8b7..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::new(); + 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 91d89b6..1d5727c 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(|_| HostError::TTYNotSupported)?)) //.map_err(|err| Error::new(format!("console: error opening pty: {:?}", err)))?)) } fn add_video_source(&mut self, _receiver: FrameReceiver) -> Result<(), HostError> { @@ -32,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/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/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 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 698de50..4e5164b 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))) } } @@ -266,8 +272,6 @@ impl<'input> AssemblyLexer<'input> { break; } } - } else { - } } else if *ch == ' ' || *ch == '\t' || *ch == '\r' { self.chars.next(); @@ -301,28 +305,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/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/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/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/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..833791e 100644 --- a/tests/harte_tests/Cargo.toml +++ b/tests/harte_tests/Cargo.toml @@ -5,9 +5,10 @@ edition = "2021" [dependencies] femtos = "0.1" - -moa-core = { path = "../../emulator/core" } +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" } + 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 a6c947f..5e57181 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-16 at commit c20d7afe6e8005ab272602953154280f0e1aa944 -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: 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: 957924, failed: 42136, total 96% -completed in 24m 47s +passed: 966036, failed: 34024, total 97% +completed in 0m 7s diff --git a/tests/harte_tests/src/main.rs b/tests/harte_tests/src/main.rs index 0c4490b..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}; @@ -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,20 @@ impl TestCase { } -fn init_execute_test(cputype: M68kType, state: &TestState) -> Result<(M68k, System), Error> { - let mut system = System::default(); - +#[allow(clippy::uninit_vec)] +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::new(cputype, Frequency::from_mhz(10), port); + 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 +169,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 +197,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 +232,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.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.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,22 +266,24 @@ 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(()), 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) }, @@ -303,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; } @@ -391,7 +400,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); } diff --git a/tests/rad_tests/src/main.rs b/tests/rad_tests/src/main.rs index 20b9555..408f338 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,10 +449,8 @@ 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) && - !(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 5fd526f..a5b6825 100644 --- a/todo.txt +++ b/todo.txt @@ -1,24 +1,18 @@ -* 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 +* 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 -* 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 - -* 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? @@ -47,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?