Fixed alloc in harte_tests that was taking all the time

This commit is contained in:
transistor 2024-03-14 22:35:02 -07:00
parent 545f339fe2
commit 59306bceff
17 changed files with 227 additions and 84 deletions

9
Cargo.lock generated
View File

@ -425,6 +425,13 @@ dependencies = [
"fugit", "fugit",
] ]
[[package]]
name = "emulator-hal-memory"
version = "0.1.0"
dependencies = [
"emulator-hal",
]
[[package]] [[package]]
name = "env_logger" name = "env_logger"
version = "0.8.4" version = "0.8.4"
@ -510,6 +517,8 @@ name = "harte-tests"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"clap 3.2.25", "clap 3.2.25",
"emulator-hal",
"emulator-hal-memory",
"femtos", "femtos",
"flate2", "flate2",
"moa-core", "moa-core",

View File

@ -1,10 +1,7 @@
use std::fmt; use std::fmt;
use std::error::{Error as StdError};
use moa_host::HostError; use moa_host::HostError;
use emulator_hal::bus;
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum EmulatorErrorKind { pub enum EmulatorErrorKind {
Misc, Misc,
@ -78,7 +75,7 @@ impl fmt::Display for Error {
impl<E> From<HostError<E>> for Error { impl<E> From<HostError<E>> for Error {
fn from(err: HostError<E>) -> Self { fn from(err: HostError<E>) -> Self {
Self::Other(format!("other")) Self::Other("other".to_string())
} }
} }

View File

@ -13,4 +13,4 @@ emulator-hal = { path = "../../libraries/emulator-hal/emulator-hal" }
moa-core = { path = "../../core", optional = true } moa-core = { path = "../../core", optional = true }
[features] [features]
moa = [] moa = ["moa-core"]

View File

@ -17,7 +17,7 @@ fn main() {
for word in words.iter() { for word in words.iter() {
print!("{:04x} ", word); print!("{:04x} ", word);
} }
println!(""); println!();
}, },
Err(err) => { Err(err) => {
println!("{:?}", err); println!("{:?}", err);

View File

@ -1,9 +1,8 @@
use femtos::Instant; use femtos::Instant;
use emulator_hal::bus::{self, BusAccess}; use emulator_hal::bus::BusAccess;
use super::state::{M68k, M68kError}; use super::state::M68kError;
use super::decode::M68kDecoder;
use super::execute::M68kCycleExecutor; use super::execute::M68kCycleExecutor;
use super::memory::M68kAddress; use super::memory::M68kAddress;

View File

@ -52,7 +52,7 @@ pub struct InstructionDecoding<'a, Bus>
where where
Bus: BusAccess<M68kAddress, Instant>, Bus: BusAccess<M68kAddress, Instant>,
{ {
pub(crate) port: &'a mut Bus, pub(crate) bus: &'a mut Bus,
pub(crate) memory: &'a mut M68kBusPort, pub(crate) memory: &'a mut M68kBusPort,
pub(crate) decoder: &'a mut M68kDecoder, pub(crate) decoder: &'a mut M68kDecoder,
} }
@ -78,13 +78,13 @@ impl M68kDecoder {
} }
#[inline] #[inline]
pub fn decode_at<Bus>(&mut self, port: &mut Bus, memory: &mut M68kBusPort, is_supervisor: bool, start: u32) -> Result<(), M68kError<Bus::Error>> pub fn decode_at<Bus>(&mut self, bus: &mut Bus, memory: &mut M68kBusPort, is_supervisor: bool, start: u32) -> Result<(), M68kError<Bus::Error>>
where where
Bus: BusAccess<M68kAddress, Instant>, Bus: BusAccess<M68kAddress, Instant>,
{ {
self.init(is_supervisor, start); self.init(is_supervisor, start);
let mut decoding = InstructionDecoding { let mut decoding = InstructionDecoding {
port, bus,
memory, memory,
decoder: self, decoder: self,
}; };
@ -92,22 +92,22 @@ impl M68kDecoder {
Ok(()) Ok(())
} }
pub fn dump_disassembly<Bus>(&mut self, port: &mut Bus, memory: &mut M68kBusPort, start: u32, length: u32) pub fn dump_disassembly<Bus>(&mut self, bus: &mut Bus, memory: &mut M68kBusPort, start: u32, length: u32)
where where
Bus: BusAccess<M68kAddress, Instant>, Bus: BusAccess<M68kAddress, Instant>,
{ {
let mut next = start; let mut next = start;
while next < (start + length) { 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(()) => { Ok(()) => {
self.dump_decoded(memory.current_clock, port); self.dump_decoded(memory.current_clock, bus);
next = self.end; next = self.end;
}, },
Err(err) => { Err(err) => {
println!("{:?}", err); println!("{:?}", err);
match err { match err {
M68kError::Exception(ex) if ex == Exceptions::IllegalInstruction => { 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<Bus>(&mut self, clock: Instant, port: &mut Bus) pub fn dump_decoded<Bus>(&mut self, clock: Instant, bus: &mut Bus)
where where
Bus: BusAccess<M68kAddress, Instant>, Bus: BusAccess<M68kAddress, Instant>,
{ {
let ins_data: Result<String, M68kError<Bus::Error>> = let ins_data: Result<String, M68kError<Bus::Error>> =
(0..((self.end - self.start) / 2)).map(|offset| (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(); ).collect();
println!("{:#010x}: {}\n\t{}\n", self.start, ins_data.unwrap(), self.instruction); println!("{:#010x}: {}\n\t{}\n", self.start, ins_data.unwrap(), self.instruction);
} }
@ -731,13 +731,13 @@ where
} }
fn read_instruction_word(&mut self) -> Result<u16, M68kError<Bus::Error>> { fn read_instruction_word(&mut self) -> Result<u16, M68kError<Bus::Error>> {
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; self.decoder.end += 2;
Ok(word) Ok(word)
} }
fn read_instruction_long(&mut self) -> Result<u32, M68kError<Bus::Error>> { fn read_instruction_long(&mut self) -> Result<u32, M68kError<Bus::Error>> {
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; self.decoder.end += 4;
Ok(word) Ok(word)
} }

View File

@ -1,6 +1,7 @@
use femtos::Instant; 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::state::{M68k, M68kType, M68kError, M68kState, Status, Flags, Exceptions, InterruptPriority};
use crate::memory::{MemType, MemAccess, M68kBusPort, M68kAddress}; use crate::memory::{MemType, MemAccess, M68kBusPort, M68kAddress};
@ -64,7 +65,7 @@ impl M68kCycle {
} }
#[inline] #[inline]
pub fn begin<'a, Bus>(mut self, cpu: &'a mut M68k, bus: Bus) -> M68kCycleExecutor<'a, Bus> pub fn begin<Bus>(self, cpu: &mut M68k, bus: Bus) -> M68kCycleExecutor<'_, Bus>
where where
Bus: BusAccess<M68kAddress, Instant>, Bus: BusAccess<M68kAddress, Instant>,
{ {
@ -78,19 +79,52 @@ impl M68kCycle {
M68kCycleExecutor { M68kCycleExecutor {
state: &mut cpu.state, state: &mut cpu.state,
port: bus, bus: bus,
debugger: &mut cpu.debugger, debugger: &mut cpu.debugger,
cycle: self, cycle: self,
} }
} }
} }
impl<Bus, BusError> Step<M68kAddress, Instant, Bus> for M68k
where
BusError: bus::Error,
Bus: BusAccess<M68kAddress, Instant, Error = BusError>,
{
type Error = M68kError<BusError>;
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<Instant, Self::Error> {
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> pub struct M68kCycleExecutor<'a, Bus>
where where
Bus: BusAccess<M68kAddress, Instant>, Bus: BusAccess<M68kAddress, Instant>,
{ {
pub state: &'a mut M68kState, pub state: &'a mut M68kState,
pub port: Bus, pub bus: Bus,
pub debugger: &'a mut M68kDebugger, pub debugger: &'a mut M68kDebugger,
pub cycle: M68kCycle, pub cycle: M68kCycle,
} }
@ -298,7 +332,7 @@ where
#[inline] #[inline]
pub fn decode_next(&mut self) -> Result<(), M68kError<Bus::Error>> { pub fn decode_next(&mut self) -> Result<(), M68kError<Bus::Error>> {
let is_supervisor = self.is_supervisor(); 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); 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<u32, M68kError<Bus::Error>> { fn get_address_sized(&mut self, addr: M68kAddress, size: Size) -> Result<u32, M68kError<Bus::Error>> {
let is_supervisor = self.is_supervisor(); 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<Bus::Error>> { fn set_address_sized(&mut self, addr: M68kAddress, value: u32, size: Size) -> Result<(), M68kError<Bus::Error>> {
let is_supervisor = self.is_supervisor(); 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<Bus::Error>> { fn push_word(&mut self, value: u16) -> Result<(), M68kError<Bus::Error>> {
let is_supervisor = self.is_supervisor(); let is_supervisor = self.is_supervisor();
*self.get_stack_pointer_mut() -= 2; *self.get_stack_pointer_mut() -= 2;
let addr = *self.get_stack_pointer_mut(); 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(()) Ok(())
} }
fn pop_word(&mut self) -> Result<u16, M68kError<Bus::Error>> { fn pop_word(&mut self) -> Result<u16, M68kError<Bus::Error>> {
let is_supervisor = self.is_supervisor(); let is_supervisor = self.is_supervisor();
let addr = *self.get_stack_pointer_mut(); 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; *self.get_stack_pointer_mut() += 2;
Ok(value as u16) Ok(value as u16)
} }
@ -1632,14 +1666,14 @@ where
let is_supervisor = self.is_supervisor(); let is_supervisor = self.is_supervisor();
*self.get_stack_pointer_mut() -= 4; *self.get_stack_pointer_mut() -= 4;
let addr = *self.get_stack_pointer_mut(); 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(()) Ok(())
} }
fn pop_long(&mut self) -> Result<u32, M68kError<Bus::Error>> { fn pop_long(&mut self) -> Result<u32, M68kError<Bus::Error>> {
let is_supervisor = self.is_supervisor(); let is_supervisor = self.is_supervisor();
let addr = *self.get_stack_pointer_mut(); 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; *self.get_stack_pointer_mut() += 4;
Ok(value) Ok(value)
} }
@ -1677,7 +1711,7 @@ where
match base_reg { match base_reg {
BaseRegister::None => 0, BaseRegister::None => 0,
BaseRegister::PC => self.cycle.decoder.start + 2, 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], BaseRegister::AReg(reg) => self.state.a_reg[reg as usize],
} }
} }

View File

@ -200,36 +200,36 @@ impl M68kBusPort {
} }
} }
pub(crate) fn read_data_sized<Bus, BusError>(&mut self, port: &mut Bus, is_supervisor: bool, addr: M68kAddress, size: Size) -> Result<u32, M68kError<BusError>> pub(crate) fn read_data_sized<Bus, BusError>(&mut self, bus: &mut Bus, is_supervisor: bool, addr: M68kAddress, size: Size) -> Result<u32, M68kError<BusError>>
where where
Bus: BusAccess<M68kAddress, Instant, Error = BusError>, Bus: BusAccess<M68kAddress, Instant, Error = BusError>,
{ {
self.start_request(is_supervisor, addr as u32, size, MemAccess::Read, MemType::Data, false)?; 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<Bus, BusError>(&mut self, port: &mut Bus, is_supervisor: bool, addr: M68kAddress, size: Size, value: u32) -> Result<(), M68kError<BusError>> pub(crate) fn write_data_sized<Bus, BusError>(&mut self, bus: &mut Bus, is_supervisor: bool, addr: M68kAddress, size: Size, value: u32) -> Result<(), M68kError<BusError>>
where where
Bus: BusAccess<M68kAddress, Instant, Error = BusError>, Bus: BusAccess<M68kAddress, Instant, Error = BusError>,
{ {
self.start_request(is_supervisor, addr as u32, size, MemAccess::Write, MemType::Data, false)?; 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<Bus, BusError>(&mut self, port: &mut Bus, is_supervisor: bool, addr: u32) -> Result<u16, M68kError<BusError>> pub(crate) fn read_instruction_word<Bus, BusError>(&mut self, bus: &mut Bus, is_supervisor: bool, addr: u32) -> Result<u16, M68kError<BusError>>
where where
Bus: BusAccess<M68kAddress, Instant, Error = BusError>, Bus: BusAccess<M68kAddress, Instant, Error = BusError>,
{ {
self.request.instruction(is_supervisor, addr)?; 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<Bus, BusError>(&mut self, port: &mut Bus, is_supervisor: bool, addr: u32) -> Result<u32, M68kError<BusError>> pub(crate) fn read_instruction_long<Bus, BusError>(&mut self, bus: &mut Bus, is_supervisor: bool, addr: u32) -> Result<u32, M68kError<BusError>>
where where
Bus: BusAccess<M68kAddress, Instant, Error = BusError>, Bus: BusAccess<M68kAddress, Instant, Error = BusError>,
{ {
self.request.instruction(is_supervisor, addr)?; 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<BusError>(&mut self, is_supervisor: bool, addr: u32, size: Size, access: MemAccess, mtype: MemType, i_n_bit: bool) -> Result<u32, M68kError<BusError>> { pub(crate) fn start_request<BusError>(&mut self, is_supervisor: bool, addr: u32, size: Size, access: MemAccess, mtype: MemType, i_n_bit: bool) -> Result<u32, M68kError<BusError>> {

View File

@ -94,15 +94,15 @@ impl Debuggable for M68k {
fn print_current_step(&mut self, _system: &System) -> Result<(), Error> { fn print_current_step(&mut self, _system: &System) -> Result<(), Error> {
// TODO this is called by the debugger, but should be called some other way // 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); //let _ = self.decoder.decode_at(&mut self.bus, true, self.state.pc);
//self.decoder.dump_decoded(&mut self.port); //self.decoder.dump_decoded(&mut self.bus);
//self.dump_state(); //self.dump_state();
Ok(()) Ok(())
} }
fn print_disassembly(&mut self, addr: Address, count: usize) { fn print_disassembly(&mut self, addr: Address, count: usize) {
let mut decoder = M68kDecoder::new(self.info.chip, true, 0); 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<bool, Error> { fn run_command(&mut self, system: &System, args: &[&str]) -> Result<bool, Error> {

View File

@ -272,7 +272,7 @@ impl M68k {
println!("Current Instruction: {:#010x} {:?}", cycle.decoder.start, cycle.decoder.instruction); println!("Current Instruction: {:#010x} {:?}", cycle.decoder.start, cycle.decoder.instruction);
println!(); 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!(); println!();
} }

View File

@ -28,7 +28,7 @@ fn main() {
system.add_addressable_device(0x00700000, Device::new(serial)).unwrap(); 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.enable_tracing();
//cpu.add_breakpoint(0x10781a); //cpu.add_breakpoint(0x10781a);

View File

@ -18,7 +18,7 @@ fn main() {
options.rom = filename.to_string(); options.rom = filename.to_string();
} }
let mut frontend = ConsoleFrontend::new(); let mut frontend = ConsoleFrontend::default();
let system = build_computie(&mut frontend, options).unwrap(); let system = build_computie(&mut frontend, options).unwrap();
frontend.start(matches, system); frontend.start(matches, system);

View File

@ -10,7 +10,7 @@ fn main() {
.help("ROM file to load (must be flat binary)")) .help("ROM file to load (must be flat binary)"))
.get_matches(); .get_matches();
let mut frontend = ConsoleFrontend::new(); let mut frontend = ConsoleFrontend::default();
let mut options = SegaGenesisOptions::default(); let mut options = SegaGenesisOptions::default();
if let Some(filename) = matches.get_one::<String>("ROM") { if let Some(filename) = matches.get_one::<String>("ROM") {

View File

@ -33,11 +33,13 @@ impl Host for ConsoleFrontend {
} }
} }
impl ConsoleFrontend { impl Default for ConsoleFrontend {
pub fn new() -> Self { fn default() -> Self {
Self Self
} }
}
impl ConsoleFrontend {
pub fn args(application_name: &'static str) -> Command { pub fn args(application_name: &'static str) -> Command {
Command::new(application_name) Command::new(application_name)
.arg(Arg::new("log-level") .arg(Arg::new("log-level")

View File

@ -5,9 +5,13 @@ edition = "2021"
[dependencies] [dependencies]
femtos = "0.1" 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-core = { path = "../../emulator/core" }
moa-m68k = { path = "../../emulator/cpus/m68k", features = ["moa"] } moa-m68k = { path = "../../emulator/cpus/m68k", features = ["moa"] }
#thiserror = "1.0"
serde = "1.0" serde = "1.0"
serde_json = "1.0" serde_json = "1.0"
serde_derive = "1.0" serde_derive = "1.0"

View File

@ -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 ABCD.json.gz completed: 7993 passed, 72 FAILED
ADD.b.json.gz completed, all passed! 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! CMPA.w.json.gz completed, all passed!
DBcc.json.gz completed, all passed! DBcc.json.gz completed, all passed!
DIVS.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

View File

@ -10,13 +10,22 @@ use std::fs::{self, File};
use clap::{Parser, ArgEnum}; use clap::{Parser, ArgEnum};
use flate2::read::GzDecoder; use flate2::read::GzDecoder;
use serde_derive::Deserialize; 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::{M68k, M68kType};
use moa_m68k::state::Status; use moa_m68k::state::Status;
#[derive(Clone, Debug)]
enum Error {
Assertion(String),
Bus(String),
Step(String),
}
#[derive(Copy, Clone, PartialEq, Eq, ArgEnum)] #[derive(Copy, Clone, PartialEq, Eq, ArgEnum)]
enum Selection { enum Selection {
Include, Include,
@ -106,7 +115,7 @@ impl TestState {
for word in self.prefetch.iter() { for word in self.prefetch.iter() {
print!("{:04x} ", *word); print!("{:04x} ", *word);
} }
println!(""); println!();
println!("ram: "); println!("ram: ");
for (addr, byte) in self.ram.iter() { 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> { fn init_execute_test(cputype: M68kType, state: &TestState) -> Result<(M68k, MemoryBlock<u32, Instant>), Error> {
let mut system = System::default();
// Insert basic initialization // Insert basic initialization
let data = vec![0; 0x01000000]; let len = 0x100_0000;
let mem = MemoryBlock::new(data); let mut data = Vec::with_capacity(len);
system.add_addressable_device(0x00000000, Device::new(mem)).unwrap(); unsafe { data.set_len(len); }
let mut memory = MemoryBlock::<u32, Instant>::from(data);
let port = if cputype <= M68kType::MC68010 { let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10));
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);
cpu.state.status = Status::Running; 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<T>(actual: T, expected: T, message: &str) -> Result<(), Error> fn assert_value<T>(actual: T, expected: T, message: &str) -> Result<(), Error>
@ -165,11 +168,11 @@ where
if actual == expected { if actual == expected {
Ok(()) Ok(())
} else { } 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<u32, Instant>, initial: &TestState) -> Result<(), Error> {
cpu.state.d_reg[0] = initial.d0; cpu.state.d_reg[0] = initial.d0;
cpu.state.d_reg[1] = initial.d1; cpu.state.d_reg[1] = initial.d1;
cpu.state.d_reg[2] = initial.d2; 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 // Load instructions into memory
for (i, ins) in initial.prefetch.iter().enumerate() { 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 // Load data bytes into memory
for (addr, byte) in initial.ram.iter() { 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(()) Ok(())
} }
fn assert_state(cpu: &M68k, system: &System, expected: &TestState) -> Result<(), Error> { fn assert_state(cpu: &M68k, memory: &mut MemoryBlock<u32, Instant>, expected: &TestState) -> Result<(), Error> {
assert_value(cpu.state.d_reg[0], expected.d0, "d0")?; 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[1], expected.d1, "d1")?;
assert_value(cpu.state.d_reg[2], expected.d2, "d2")?; 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.sr, expected.sr, "sr")?;
assert_value(cpu.state.pc, expected.pc, "pc")?; 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 // Load instructions into memory
for (i, ins) in expected.prefetch.iter().enumerate() { for (i, ins) in expected.prefetch.iter().enumerate() {
let addr = expected.pc + (i as u32 * 2); 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))?; assert_value(actual, *ins, &format!("prefetch at {:x}", addr))?;
} }
// Load data bytes into memory // Load data bytes into memory
for (addr, byte) in expected.ram.iter() { 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))?; assert_value(actual, *byte, &format!("ram at {:x}", addr))?;
} }
Ok(()) Ok(())
} }
fn step_cpu_and_assert(cpu: &mut M68k, system: &System, case: &TestCase, test_timing: bool) -> Result<(), Error> { fn step_cpu_and_assert(cpu: &mut M68k, memory: &mut MemoryBlock<u32, Instant>, case: &TestCase, test_timing: bool) -> Result<(), Error> {
let clock_elapsed = cpu.step(&system)?; let clock_elapsed = cpu.step(Instant::START, memory)
let cycles = clock_elapsed / cpu.info.frequency.period_duration(); .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 { if test_timing {
assert_value(cycles, case.length as u64, "clock cycles")?; 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> { fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> {
let (mut cpu, system) = init_execute_test(M68kType::MC68000, &case.initial_state).unwrap(); let (mut cpu, mut memory) = init_execute_test(M68kType::MC68000, &case.initial_state).unwrap();
let mut initial_cpu = cpu.clone(); 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 { match result {
Ok(()) => Ok(()), Ok(()) => Ok(()),
@ -268,7 +276,7 @@ fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> {
if !args.quiet { if !args.quiet {
if args.debug { if args.debug {
case.dump(); case.dump();
println!(""); println!();
//initial_cpu.dump_state(); //initial_cpu.dump_state();
//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!("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); println!("completed in {}m {}s", elapsed_secs / 60, elapsed_secs % 60);
} }