diff --git a/Cargo.lock b/Cargo.lock index 38dd4a3..94c30ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -425,6 +425,13 @@ dependencies = [ "fugit", ] +[[package]] +name = "emulator-hal-memory" +version = "0.1.0" +dependencies = [ + "emulator-hal", +] + [[package]] name = "env_logger" version = "0.8.4" @@ -510,6 +517,8 @@ name = "harte-tests" version = "0.1.0" dependencies = [ "clap 3.2.25", + "emulator-hal", + "emulator-hal-memory", "femtos", "flate2", "moa-core", diff --git a/emulator/core/src/error.rs b/emulator/core/src/error.rs index d438343..0ffe7f6 100644 --- a/emulator/core/src/error.rs +++ b/emulator/core/src/error.rs @@ -1,10 +1,7 @@ use std::fmt; -use std::error::{Error as StdError}; use moa_host::HostError; -use emulator_hal::bus; - #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum EmulatorErrorKind { Misc, @@ -78,7 +75,7 @@ impl fmt::Display for Error { impl From> for Error { fn from(err: HostError) -> Self { - Self::Other(format!("other")) + Self::Other("other".to_string()) } } diff --git a/emulator/cpus/m68k/Cargo.toml b/emulator/cpus/m68k/Cargo.toml index 12bcfe0..6143ee6 100644 --- a/emulator/cpus/m68k/Cargo.toml +++ b/emulator/cpus/m68k/Cargo.toml @@ -13,4 +13,4 @@ emulator-hal = { path = "../../libraries/emulator-hal/emulator-hal" } moa-core = { path = "../../core", optional = true } [features] -moa = [] +moa = ["moa-core"] diff --git a/emulator/cpus/m68k/src/bin/m68kas.rs b/emulator/cpus/m68k/src/bin/m68kas.rs index 9cb662c..5681b9b 100644 --- a/emulator/cpus/m68k/src/bin/m68kas.rs +++ b/emulator/cpus/m68k/src/bin/m68kas.rs @@ -17,7 +17,7 @@ fn main() { for word in words.iter() { print!("{:04x} ", word); } - println!(""); + println!(); }, Err(err) => { println!("{:?}", err); diff --git a/emulator/cpus/m68k/src/debugger.rs b/emulator/cpus/m68k/src/debugger.rs index a5ebc54..827dfb5 100644 --- a/emulator/cpus/m68k/src/debugger.rs +++ b/emulator/cpus/m68k/src/debugger.rs @@ -1,9 +1,8 @@ use femtos::Instant; -use emulator_hal::bus::{self, BusAccess}; +use emulator_hal::bus::BusAccess; -use super::state::{M68k, M68kError}; -use super::decode::M68kDecoder; +use super::state::M68kError; use super::execute::M68kCycleExecutor; use super::memory::M68kAddress; diff --git a/emulator/cpus/m68k/src/decode.rs b/emulator/cpus/m68k/src/decode.rs index 8ab5930..83e965a 100644 --- a/emulator/cpus/m68k/src/decode.rs +++ b/emulator/cpus/m68k/src/decode.rs @@ -52,7 +52,7 @@ pub struct InstructionDecoding<'a, Bus> where Bus: BusAccess, { - pub(crate) port: &'a mut Bus, + pub(crate) bus: &'a mut Bus, pub(crate) memory: &'a mut M68kBusPort, pub(crate) decoder: &'a mut M68kDecoder, } @@ -78,13 +78,13 @@ impl M68kDecoder { } #[inline] - pub fn decode_at(&mut self, port: &mut Bus, memory: &mut M68kBusPort, is_supervisor: bool, start: u32) -> Result<(), M68kError> + pub fn decode_at(&mut self, bus: &mut Bus, memory: &mut M68kBusPort, is_supervisor: bool, start: u32) -> Result<(), M68kError> where Bus: BusAccess, { self.init(is_supervisor, start); let mut decoding = InstructionDecoding { - port, + bus, memory, decoder: self, }; @@ -92,22 +92,22 @@ impl M68kDecoder { Ok(()) } - pub fn dump_disassembly(&mut self, port: &mut Bus, memory: &mut M68kBusPort, start: u32, length: u32) + pub fn dump_disassembly(&mut self, bus: &mut Bus, memory: &mut M68kBusPort, start: u32, length: u32) where Bus: BusAccess, { let mut next = start; while next < (start + length) { - match self.decode_at(port, memory, self.is_supervisor, next) { + match self.decode_at(bus, memory, self.is_supervisor, next) { Ok(()) => { - self.dump_decoded(memory.current_clock, port); + self.dump_decoded(memory.current_clock, bus); next = self.end; }, Err(err) => { println!("{:?}", err); match err { M68kError::Exception(ex) if ex == Exceptions::IllegalInstruction => { - println!(" at {:08x}: {:04x}", self.start, port.read_beu16(memory.current_clock, self.start).unwrap()); + println!(" at {:08x}: {:04x}", self.start, bus.read_beu16(memory.current_clock, self.start).unwrap()); }, _ => { }, } @@ -117,13 +117,13 @@ impl M68kDecoder { } } - pub fn dump_decoded(&mut self, clock: Instant, port: &mut Bus) + pub fn dump_decoded(&mut self, clock: Instant, bus: &mut Bus) where Bus: BusAccess, { let ins_data: Result> = (0..((self.end - self.start) / 2)).map(|offset| - Ok(format!("{:04x} ", port.read_beu16(clock, self.start + (offset * 2)).unwrap())) + Ok(format!("{:04x} ", bus.read_beu16(clock, self.start + (offset * 2)).unwrap())) ).collect(); println!("{:#010x}: {}\n\t{}\n", self.start, ins_data.unwrap(), self.instruction); } @@ -731,13 +731,13 @@ where } fn read_instruction_word(&mut self) -> Result> { - let word = self.memory.read_instruction_word(self.port, self.decoder.is_supervisor, self.decoder.end)?; + let word = self.memory.read_instruction_word(self.bus, self.decoder.is_supervisor, self.decoder.end)?; self.decoder.end += 2; Ok(word) } fn read_instruction_long(&mut self) -> Result> { - let word = self.memory.read_instruction_long(self.port, self.decoder.is_supervisor, self.decoder.end)?; + let word = self.memory.read_instruction_long(self.bus, self.decoder.is_supervisor, self.decoder.end)?; self.decoder.end += 4; Ok(word) } diff --git a/emulator/cpus/m68k/src/execute.rs b/emulator/cpus/m68k/src/execute.rs index da852cb..7fb1e91 100644 --- a/emulator/cpus/m68k/src/execute.rs +++ b/emulator/cpus/m68k/src/execute.rs @@ -1,6 +1,7 @@ use femtos::Instant; -use emulator_hal::bus::BusAccess; +use emulator_hal::bus::{self, BusAccess}; +use emulator_hal::step::Step; use crate::state::{M68k, M68kType, M68kError, M68kState, Status, Flags, Exceptions, InterruptPriority}; use crate::memory::{MemType, MemAccess, M68kBusPort, M68kAddress}; @@ -64,7 +65,7 @@ impl M68kCycle { } #[inline] - pub fn begin<'a, Bus>(mut self, cpu: &'a mut M68k, bus: Bus) -> M68kCycleExecutor<'a, Bus> + pub fn begin(self, cpu: &mut M68k, bus: Bus) -> M68kCycleExecutor<'_, Bus> where Bus: BusAccess, { @@ -78,19 +79,52 @@ impl M68kCycle { M68kCycleExecutor { state: &mut cpu.state, - port: bus, + bus: bus, debugger: &mut cpu.debugger, cycle: self, } } } +impl Step for M68k +where + BusError: bus::Error, + Bus: BusAccess, +{ + type Error = M68kError; + + fn is_running(&mut self) -> bool { + self.state.status == Status::Running + } + + fn reset(&mut self, now: Instant, bus: &mut Bus) -> Result<(), Self::Error> { + Ok(()) + } + + fn step(&mut self, now: Instant, bus: &mut Bus) -> Result { + let cycle = M68kCycle::new(self, now); + + let mut executor = cycle.begin(self, &mut *bus); + executor.check_breakpoints()?; + executor.step()?; + + //let interrupt = system.get_interrupt_controller().check(); + //if let (priority, Some(ack)) = executor.check_pending_interrupts(interrupt)? { + // log::debug!("interrupt: {:?} @ {} ns", priority, system.clock.as_duration().as_nanos()); + // system.get_interrupt_controller().acknowledge(priority as u8)?; + //} + + self.cycle = Some(executor.end()); + Ok(now + self.last_cycle_duration()) + } +} + pub struct M68kCycleExecutor<'a, Bus> where Bus: BusAccess, { pub state: &'a mut M68kState, - pub port: Bus, + pub bus: Bus, pub debugger: &'a mut M68kDebugger, pub cycle: M68kCycle, } @@ -298,7 +332,7 @@ where #[inline] pub fn decode_next(&mut self) -> Result<(), M68kError> { let is_supervisor = self.is_supervisor(); - self.cycle.decoder.decode_at(&mut self.port, &mut self.cycle.memory, is_supervisor, self.state.pc)?; + self.cycle.decoder.decode_at(&mut self.bus, &mut self.cycle.memory, is_supervisor, self.state.pc)?; self.cycle.timing.add_instruction(&self.cycle.decoder.instruction); @@ -1604,26 +1638,26 @@ where fn get_address_sized(&mut self, addr: M68kAddress, size: Size) -> Result> { let is_supervisor = self.is_supervisor(); - self.cycle.memory.read_data_sized(&mut self.port, is_supervisor, addr, size) + self.cycle.memory.read_data_sized(&mut self.bus, is_supervisor, addr, size) } fn set_address_sized(&mut self, addr: M68kAddress, value: u32, size: Size) -> Result<(), M68kError> { let is_supervisor = self.is_supervisor(); - self.cycle.memory.write_data_sized(&mut self.port, is_supervisor, addr, size, value) + self.cycle.memory.write_data_sized(&mut self.bus, is_supervisor, addr, size, value) } fn push_word(&mut self, value: u16) -> Result<(), M68kError> { let is_supervisor = self.is_supervisor(); *self.get_stack_pointer_mut() -= 2; let addr = *self.get_stack_pointer_mut(); - self.cycle.memory.write_data_sized(&mut self.port, is_supervisor, addr, Size::Word, value as u32)?; + self.cycle.memory.write_data_sized(&mut self.bus, is_supervisor, addr, Size::Word, value as u32)?; Ok(()) } fn pop_word(&mut self) -> Result> { let is_supervisor = self.is_supervisor(); let addr = *self.get_stack_pointer_mut(); - let value = self.cycle.memory.read_data_sized(&mut self.port, is_supervisor, addr, Size::Word)?; + let value = self.cycle.memory.read_data_sized(&mut self.bus, is_supervisor, addr, Size::Word)?; *self.get_stack_pointer_mut() += 2; Ok(value as u16) } @@ -1632,14 +1666,14 @@ where let is_supervisor = self.is_supervisor(); *self.get_stack_pointer_mut() -= 4; let addr = *self.get_stack_pointer_mut(); - self.cycle.memory.write_data_sized(&mut self.port, is_supervisor, addr, Size::Long, value)?; + self.cycle.memory.write_data_sized(&mut self.bus, is_supervisor, addr, Size::Long, value)?; Ok(()) } fn pop_long(&mut self) -> Result> { let is_supervisor = self.is_supervisor(); let addr = *self.get_stack_pointer_mut(); - let value = self.cycle.memory.read_data_sized(&mut self.port, is_supervisor, addr, Size::Long)?; + let value = self.cycle.memory.read_data_sized(&mut self.bus, is_supervisor, addr, Size::Long)?; *self.get_stack_pointer_mut() += 4; Ok(value) } @@ -1677,7 +1711,7 @@ where match base_reg { BaseRegister::None => 0, BaseRegister::PC => self.cycle.decoder.start + 2, - BaseRegister::AReg(reg) if reg == 7 => if self.is_supervisor() { self.state.ssp } else { self.state.usp }, + BaseRegister::AReg(7) => if self.is_supervisor() { self.state.ssp } else { self.state.usp }, BaseRegister::AReg(reg) => self.state.a_reg[reg as usize], } } diff --git a/emulator/cpus/m68k/src/memory.rs b/emulator/cpus/m68k/src/memory.rs index d9783c2..6f1e7b1 100644 --- a/emulator/cpus/m68k/src/memory.rs +++ b/emulator/cpus/m68k/src/memory.rs @@ -200,36 +200,36 @@ impl M68kBusPort { } } - pub(crate) fn read_data_sized(&mut self, port: &mut Bus, is_supervisor: bool, addr: M68kAddress, size: Size) -> Result> + pub(crate) fn read_data_sized(&mut self, bus: &mut Bus, is_supervisor: bool, addr: M68kAddress, size: Size) -> Result> where Bus: BusAccess, { self.start_request(is_supervisor, addr as u32, size, MemAccess::Read, MemType::Data, false)?; - self.read_sized(port, addr, size) + self.read_sized(bus, addr, size) } - pub(crate) fn write_data_sized(&mut self, port: &mut Bus, is_supervisor: bool, addr: M68kAddress, size: Size, value: u32) -> Result<(), M68kError> + pub(crate) fn write_data_sized(&mut self, bus: &mut Bus, is_supervisor: bool, addr: M68kAddress, size: Size, value: u32) -> Result<(), M68kError> where Bus: BusAccess, { self.start_request(is_supervisor, addr as u32, size, MemAccess::Write, MemType::Data, false)?; - self.write_sized(port, addr, size, value) + self.write_sized(bus, addr, size, value) } - pub(crate) fn read_instruction_word(&mut self, port: &mut Bus, is_supervisor: bool, addr: u32) -> Result> + pub(crate) fn read_instruction_word(&mut self, bus: &mut Bus, is_supervisor: bool, addr: u32) -> Result> where Bus: BusAccess, { self.request.instruction(is_supervisor, addr)?; - Ok(self.read_sized(port, addr, Size::Word)? as u16) + Ok(self.read_sized(bus, addr, Size::Word)? as u16) } - pub(crate) fn read_instruction_long(&mut self, port: &mut Bus, is_supervisor: bool, addr: u32) -> Result> + pub(crate) fn read_instruction_long(&mut self, bus: &mut Bus, is_supervisor: bool, addr: u32) -> Result> where Bus: BusAccess, { self.request.instruction(is_supervisor, addr)?; - self.read_sized(port, addr, Size::Long) + self.read_sized(bus, addr, Size::Long) } pub(crate) fn start_request(&mut self, is_supervisor: bool, addr: u32, size: Size, access: MemAccess, mtype: MemType, i_n_bit: bool) -> Result> { diff --git a/emulator/cpus/m68k/src/moa.rs b/emulator/cpus/m68k/src/moa.rs index 7caf40b..76940b1 100644 --- a/emulator/cpus/m68k/src/moa.rs +++ b/emulator/cpus/m68k/src/moa.rs @@ -94,15 +94,15 @@ impl Debuggable for M68k { fn print_current_step(&mut self, _system: &System) -> Result<(), Error> { // TODO this is called by the debugger, but should be called some other way - //let _ = self.decoder.decode_at(&mut self.port, true, self.state.pc); - //self.decoder.dump_decoded(&mut self.port); + //let _ = self.decoder.decode_at(&mut self.bus, true, self.state.pc); + //self.decoder.dump_decoded(&mut self.bus); //self.dump_state(); Ok(()) } fn print_disassembly(&mut self, addr: Address, count: usize) { let mut decoder = M68kDecoder::new(self.info.chip, true, 0); - //decoder.dump_disassembly(&mut self.port, self.cycle.memory, addr as u32, count as u32); + //decoder.dump_disassembly(&mut self.bus, self.cycle.memory, addr as u32, count as u32); } fn run_command(&mut self, system: &System, args: &[&str]) -> Result { diff --git a/emulator/cpus/m68k/src/state.rs b/emulator/cpus/m68k/src/state.rs index 91de783..04249fc 100644 --- a/emulator/cpus/m68k/src/state.rs +++ b/emulator/cpus/m68k/src/state.rs @@ -272,7 +272,7 @@ impl M68k { println!("Current Instruction: {:#010x} {:?}", cycle.decoder.start, cycle.decoder.instruction); println!(); } - //memory::dump_memory(&mut self.port, self.cycle.current_clock, self.state.ssp, 0x40); + //memory::dump_memory(&mut self.bus, self.cycle.current_clock, self.state.ssp, 0x40); println!(); } diff --git a/emulator/frontends/console/src/bin/moa-bench.rs b/emulator/frontends/console/src/bin/moa-bench.rs index 5391d09..366feef 100644 --- a/emulator/frontends/console/src/bin/moa-bench.rs +++ b/emulator/frontends/console/src/bin/moa-bench.rs @@ -28,7 +28,7 @@ fn main() { system.add_addressable_device(0x00700000, Device::new(serial)).unwrap(); - let cpu = M68k::from_type(M68kType::MC68010, Frequency::from_mhz(8), system.bus.clone(), 0); + let cpu = M68k::from_type(M68kType::MC68010, Frequency::from_mhz(8)); //cpu.enable_tracing(); //cpu.add_breakpoint(0x10781a); diff --git a/emulator/frontends/console/src/bin/moa-computie.rs b/emulator/frontends/console/src/bin/moa-computie.rs index 1331894..eafe886 100644 --- a/emulator/frontends/console/src/bin/moa-computie.rs +++ b/emulator/frontends/console/src/bin/moa-computie.rs @@ -18,7 +18,7 @@ fn main() { options.rom = filename.to_string(); } - let mut frontend = ConsoleFrontend::new(); + let mut frontend = ConsoleFrontend::default(); let system = build_computie(&mut frontend, options).unwrap(); frontend.start(matches, system); diff --git a/emulator/frontends/console/src/bin/moa-console-genesis.rs b/emulator/frontends/console/src/bin/moa-console-genesis.rs index 9b4c8b7..561129a 100644 --- a/emulator/frontends/console/src/bin/moa-console-genesis.rs +++ b/emulator/frontends/console/src/bin/moa-console-genesis.rs @@ -10,7 +10,7 @@ fn main() { .help("ROM file to load (must be flat binary)")) .get_matches(); - let mut frontend = ConsoleFrontend::new(); + let mut frontend = ConsoleFrontend::default(); let mut options = SegaGenesisOptions::default(); if let Some(filename) = matches.get_one::("ROM") { diff --git a/emulator/frontends/console/src/lib.rs b/emulator/frontends/console/src/lib.rs index bbe80a4..b7c08d8 100644 --- a/emulator/frontends/console/src/lib.rs +++ b/emulator/frontends/console/src/lib.rs @@ -33,11 +33,13 @@ impl Host for ConsoleFrontend { } } -impl ConsoleFrontend { - pub fn new() -> Self { +impl Default for ConsoleFrontend { + fn default() -> Self { Self } +} +impl ConsoleFrontend { pub fn args(application_name: &'static str) -> Command { Command::new(application_name) .arg(Arg::new("log-level") diff --git a/tests/harte_tests/Cargo.toml b/tests/harte_tests/Cargo.toml index d7af02b..7b35f4c 100644 --- a/tests/harte_tests/Cargo.toml +++ b/tests/harte_tests/Cargo.toml @@ -5,9 +5,13 @@ edition = "2021" [dependencies] femtos = "0.1" +emulator-hal = { path = "../../emulator/libraries/emulator-hal/emulator-hal" } +emulator-hal-memory = { path = "../../emulator/libraries/emulator-hal/emulator-hal-memory" } moa-core = { path = "../../emulator/core" } moa-m68k = { path = "../../emulator/cpus/m68k", features = ["moa"] } + +#thiserror = "1.0" serde = "1.0" serde_json = "1.0" serde_derive = "1.0" diff --git a/tests/harte_tests/latest.txt b/tests/harte_tests/latest.txt index 3db3c97..2f284a3 100644 --- a/tests/harte_tests/latest.txt +++ b/tests/harte_tests/latest.txt @@ -1,4 +1,4 @@ -Last run on 2024-03-13 at commit af1c660dc0682a62c123b1d7577f2ce2b5f3d8ad +Last run on 2024-03-14 at commit 545f339fe2714cc648bd4a01506518a13c1faf39 ABCD.json.gz completed: 7993 passed, 72 FAILED ADD.b.json.gz completed, all passed! @@ -37,3 +37,93 @@ CMPA.l.json.gz completed, all passed! CMPA.w.json.gz completed, all passed! DBcc.json.gz completed, all passed! DIVS.json.gz completed, all passed! +DIVU.json.gz completed: 8064 passed, 1 FAILED +EOR.b.json.gz completed, all passed! +EOR.l.json.gz completed: 7519 passed, 546 FAILED +EOR.w.json.gz completed: 7525 passed, 540 FAILED +EORItoCCR.json.gz completed, all passed! +EORItoSR.json.gz completed, all passed! +EXG.json.gz completed, all passed! +EXT.l.json.gz completed, all passed! +EXT.w.json.gz completed, all passed! +JMP.json.gz completed, all passed! +JSR.json.gz completed, all passed! +LEA.json.gz completed, all passed! +LINK.json.gz completed, all passed! +LSL.b.json.gz completed, all passed! +LSL.l.json.gz completed, all passed! +LSL.w.json.gz completed: 7910 passed, 155 FAILED +LSR.b.json.gz completed, all passed! +LSR.l.json.gz completed, all passed! +LSR.w.json.gz completed: 7909 passed, 156 FAILED +MOVE.b.json.gz completed, all passed! +MOVE.l.json.gz completed: 5827 passed, 2238 FAILED +MOVE.q.json.gz completed, all passed! +MOVE.w.json.gz completed: 5855 passed, 2210 FAILED +MOVEA.l.json.gz completed, all passed! +MOVEA.w.json.gz completed, all passed! +MOVEM.l.json.gz completed: 6035 passed, 2030 FAILED +MOVEM.w.json.gz completed: 6431 passed, 1634 FAILED +MOVEP.l.json.gz completed: 4036 passed, 4029 FAILED +MOVEP.w.json.gz completed: 4046 passed, 4019 FAILED +MOVEfromSR.json.gz completed: 6896 passed, 1169 FAILED +MOVEfromUSP.json.gz completed, all passed! +MOVEtoCCR.json.gz completed, all passed! +MOVEtoSR.json.gz completed, all passed! +MOVEtoUSP.json.gz completed, all passed! +MULS.json.gz completed, all passed! +MULU.json.gz completed, all passed! +NBCD.json.gz completed: 8037 passed, 28 FAILED +NEG.b.json.gz completed, all passed! +NEG.l.json.gz completed: 7552 passed, 513 FAILED +NEG.w.json.gz completed: 7531 passed, 534 FAILED +NEGX.b.json.gz completed, all passed! +NEGX.l.json.gz completed: 7520 passed, 545 FAILED +NEGX.w.json.gz completed: 7510 passed, 555 FAILED +NOP.json.gz completed, all passed! +NOT.b.json.gz completed, all passed! +NOT.l.json.gz completed: 7512 passed, 553 FAILED +NOT.w.json.gz completed: 7530 passed, 535 FAILED +OR.b.json.gz completed, all passed! +OR.l.json.gz completed: 7756 passed, 309 FAILED +OR.w.json.gz completed: 7765 passed, 300 FAILED +ORItoCCR.json.gz completed, all passed! +ORItoSR.json.gz completed, all passed! +PEA.json.gz completed, all passed! +RESET.json.gz completed, all passed! +ROL.b.json.gz completed, all passed! +ROL.l.json.gz completed, all passed! +ROL.w.json.gz completed: 7898 passed, 167 FAILED +ROR.b.json.gz completed, all passed! +ROR.l.json.gz completed, all passed! +ROR.w.json.gz completed: 7932 passed, 133 FAILED +ROXL.b.json.gz completed: 8032 passed, 33 FAILED +ROXL.l.json.gz completed: 8029 passed, 36 FAILED +ROXL.w.json.gz completed: 7890 passed, 175 FAILED +ROXR.b.json.gz completed: 8027 passed, 38 FAILED +ROXR.l.json.gz completed: 8039 passed, 26 FAILED +ROXR.w.json.gz completed: 7880 passed, 185 FAILED +RTE.json.gz completed, all passed! +RTR.json.gz completed, all passed! +RTS.json.gz completed, all passed! +SBCD.json.gz completed: 6809 passed, 1256 FAILED +SUB.b.json.gz completed, all passed! +SUB.l.json.gz completed: 7747 passed, 318 FAILED +SUB.w.json.gz completed: 7716 passed, 349 FAILED +SUBA.l.json.gz completed, all passed! +SUBA.w.json.gz completed, all passed! +SUBX.b.json.gz completed, all passed! +SUBX.l.json.gz completed: 5481 passed, 2584 FAILED +SUBX.w.json.gz completed, all passed! +SWAP.json.gz completed, all passed! +Scc.json.gz completed, all passed! +TAS.json.gz completed, all passed! +TRAP.json.gz completed, all passed! +TRAPV.json.gz completed, all passed! +TST.b.json.gz completed, all passed! +TST.l.json.gz completed, all passed! +TST.w.json.gz completed, all passed! +UNLINK.json.gz completed, all passed! + +passed: 966037, failed: 34023, total 97% +completed in 15m 0s diff --git a/tests/harte_tests/src/main.rs b/tests/harte_tests/src/main.rs index 45aec0e..f6240e4 100644 --- a/tests/harte_tests/src/main.rs +++ b/tests/harte_tests/src/main.rs @@ -10,13 +10,22 @@ use std::fs::{self, File}; use clap::{Parser, ArgEnum}; use flate2::read::GzDecoder; use serde_derive::Deserialize; -use femtos::Frequency; +use femtos::{Instant, Frequency}; -use moa_core::{System, Error, MemoryBlock, BusPort, Address, Addressable, Steppable, Device}; +use emulator_hal::bus::BusAccess; +use emulator_hal::step::Step; +use emulator_hal_memory::MemoryBlock; use moa_m68k::{M68k, M68kType}; use moa_m68k::state::Status; +#[derive(Clone, Debug)] +enum Error { + Assertion(String), + Bus(String), + Step(String), +} + #[derive(Copy, Clone, PartialEq, Eq, ArgEnum)] enum Selection { Include, @@ -106,7 +115,7 @@ impl TestState { for word in self.prefetch.iter() { print!("{:04x} ", *word); } - println!(""); + println!(); println!("ram: "); for (addr, byte) in self.ram.iter() { @@ -137,25 +146,19 @@ impl TestCase { } -fn init_execute_test(cputype: M68kType, state: &TestState) -> Result<(M68k, System), Error> { - let mut system = System::default(); - +fn init_execute_test(cputype: M68kType, state: &TestState) -> Result<(M68k, MemoryBlock), Error> { // Insert basic initialization - let data = vec![0; 0x01000000]; - let mem = MemoryBlock::new(data); - system.add_addressable_device(0x00000000, Device::new(mem)).unwrap(); + let len = 0x100_0000; + let mut data = Vec::with_capacity(len); + unsafe { data.set_len(len); } + let mut memory = MemoryBlock::::from(data); - let port = if cputype <= M68kType::MC68010 { - BusPort::new(0, 24, 16, system.bus.clone()) - } else { - BusPort::new(0, 32, 32, system.bus.clone()) - }; - let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0); + let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10)); cpu.state.status = Status::Running; - load_state(&mut cpu, &mut system, state)?; + load_state(&mut cpu, &mut memory, state)?; - Ok((cpu, system)) + Ok((cpu, memory)) } fn assert_value(actual: T, expected: T, message: &str) -> Result<(), Error> @@ -165,11 +168,11 @@ where if actual == expected { Ok(()) } else { - Err(Error::assertion(&format!("{:#X} != {:#X}, {}", actual, expected, message))) + Err(Error::Assertion(format!("{:#X} != {:#X}, {}", actual, expected, message))) } } -fn load_state(cpu: &mut M68k, system: &mut System, initial: &TestState) -> Result<(), Error> { +fn load_state(cpu: &mut M68k, memory: &mut MemoryBlock, initial: &TestState) -> Result<(), Error> { cpu.state.d_reg[0] = initial.d0; cpu.state.d_reg[1] = initial.d1; cpu.state.d_reg[2] = initial.d2; @@ -193,18 +196,20 @@ fn load_state(cpu: &mut M68k, system: &mut System, initial: &TestState) -> Resul // Load instructions into memory for (i, ins) in initial.prefetch.iter().enumerate() { - system.get_bus().write_beu16(system.clock, (initial.pc + (i as u32 * 2)) as u64, *ins)?; + memory.write_beu16(Instant::START, initial.pc + (i as u32 * 2), *ins) + .map_err(|err| Error::Bus(format!("{:?}", err)))?; } // Load data bytes into memory for (addr, byte) in initial.ram.iter() { - system.get_bus().write_u8(system.clock, *addr as u64, *byte)?; + memory.write_u8(Instant::START, *addr, *byte) + .map_err(|err| Error::Bus(format!("{:?}", err)))?; } Ok(()) } -fn assert_state(cpu: &M68k, system: &System, expected: &TestState) -> Result<(), Error> { +fn assert_state(cpu: &M68k, memory: &mut MemoryBlock, expected: &TestState) -> Result<(), Error> { assert_value(cpu.state.d_reg[0], expected.d0, "d0")?; assert_value(cpu.state.d_reg[1], expected.d1, "d1")?; assert_value(cpu.state.d_reg[2], expected.d2, "d2")?; @@ -226,29 +231,32 @@ fn assert_state(cpu: &M68k, system: &System, expected: &TestState) -> Result<(), assert_value(cpu.state.sr, expected.sr, "sr")?; assert_value(cpu.state.pc, expected.pc, "pc")?; - let addr_mask = cpu.port.address_mask(); + let addr_mask = 1_u32.wrapping_shl(cpu.info.address_width as u32).wrapping_sub(1); // Load instructions into memory for (i, ins) in expected.prefetch.iter().enumerate() { let addr = expected.pc + (i as u32 * 2); - let actual = system.get_bus().read_beu16(system.clock, addr as Address & addr_mask)?; + let actual = memory.read_beu16(Instant::START, addr & addr_mask) + .map_err(|err| Error::Bus(format!("{:?}", err)))?; assert_value(actual, *ins, &format!("prefetch at {:x}", addr))?; } // Load data bytes into memory for (addr, byte) in expected.ram.iter() { - let actual = system.get_bus().read_u8(system.clock, *addr as Address & addr_mask)?; + let actual = memory.read_u8(Instant::START, *addr & addr_mask) + .map_err(|err| Error::Bus(format!("{:?}", err)))?; assert_value(actual, *byte, &format!("ram at {:x}", addr))?; } Ok(()) } -fn step_cpu_and_assert(cpu: &mut M68k, system: &System, case: &TestCase, test_timing: bool) -> Result<(), Error> { - let clock_elapsed = cpu.step(&system)?; - let cycles = clock_elapsed / cpu.info.frequency.period_duration(); +fn step_cpu_and_assert(cpu: &mut M68k, memory: &mut MemoryBlock, case: &TestCase, test_timing: bool) -> Result<(), Error> { + let clock_elapsed = cpu.step(Instant::START, memory) + .map_err(|err| Error::Step(format!("{:?}", err)))?; + let cycles = clock_elapsed.as_duration() / cpu.info.frequency.period_duration(); - assert_state(&cpu, &system, &case.final_state)?; + assert_state(cpu, memory, &case.final_state)?; if test_timing { assert_value(cycles, case.length as u64, "clock cycles")?; @@ -257,10 +265,10 @@ fn step_cpu_and_assert(cpu: &mut M68k, system: &System, case: &TestCase, test_ti } fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> { - let (mut cpu, system) = init_execute_test(M68kType::MC68000, &case.initial_state).unwrap(); - let mut initial_cpu = cpu.clone(); + let (mut cpu, mut memory) = init_execute_test(M68kType::MC68000, &case.initial_state).unwrap(); + let initial_cpu = cpu.clone(); - let result = step_cpu_and_assert(&mut cpu, &system, case, args.timing); + let result = step_cpu_and_assert(&mut cpu, &mut memory, case, args.timing); match result { Ok(()) => Ok(()), @@ -268,7 +276,7 @@ fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> { if !args.quiet { if args.debug { case.dump(); - println!(""); + println!(); //initial_cpu.dump_state(); //cpu.dump_state(); } @@ -391,7 +399,7 @@ fn run_all_tests(args: &Args) { } } - println!(""); + println!(); println!("passed: {}, failed: {}, total {:.0}%", passed, failed, ((passed as f32) / (passed as f32 + failed as f32)) * 100.0); println!("completed in {}m {}s", elapsed_secs / 60, elapsed_secs % 60); }