moa/emulator/cpus/m68k/tests/timing_tests.rs

103 lines
3.1 KiB
Rust
Raw Normal View History

2023-03-26 04:27:02 +00:00
2024-02-24 21:02:09 +00:00
use femtos::{Instant, Frequency};
2024-03-16 06:01:41 +00:00
use emulator_hal::bus::BusAccess;
use emulator_hal_memory::MemoryBlock;
2024-02-24 21:02:09 +00:00
2024-03-16 06:01:41 +00:00
use moa_m68k::{M68k, M68kType, M68kAddress};
2023-03-26 04:27:02 +00:00
use moa_m68k::instructions::{Instruction, Target, Size};
use moa_m68k::timing::M68kInstructionTiming;
2024-03-03 21:26:15 +00:00
use moa_m68k::execute::M68kCycle;
2023-03-26 04:27:02 +00:00
2024-03-16 06:01:41 +00:00
const INIT_STACK: M68kAddress = 0x00002000;
const INIT_ADDR: M68kAddress = 0x00000010;
2023-03-26 04:27:02 +00:00
struct TimingCase {
cpu: M68kType,
data: &'static [u16],
timing: (u16, u16, u16),
ins: Instruction,
}
const TIMING_TESTS: &'static [TimingCase] = &[
TimingCase { cpu: M68kType::MC68000, data: &[0xD090], timing: ( 14, 14, 6), ins: Instruction::ADD(Target::IndirectAReg(0), Target::DirectDReg(0), Size::Long) },
];
2024-03-16 06:01:41 +00:00
fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, MemoryBlock<u32, Instant>) {
2023-03-26 04:27:02 +00:00
// Insert basic initialization
2024-03-16 06:01:41 +00:00
let len = 0x10_0000;
let mut data = Vec::with_capacity(len);
let mut memory = MemoryBlock::from(data);
memory.write_beu32(Instant::START, 0, INIT_STACK).unwrap();
memory.write_beu32(Instant::START, 4, INIT_ADDR).unwrap();
2023-03-26 04:27:02 +00:00
// Initialize the CPU and make sure it's in the expected state
2024-03-16 06:01:41 +00:00
let cpu = M68k::from_type(cputype, Frequency::from_mhz(10));
2024-03-03 21:26:15 +00:00
//cpu.reset_cpu().unwrap();
2024-03-16 06:01:41 +00:00
assert_eq!(cpu.state.pc, INIT_ADDR);
assert_eq!(cpu.state.ssp, INIT_STACK);
2023-03-26 04:27:02 +00:00
2024-03-16 06:01:41 +00:00
let cycle = M68kCycle::new(&cpu, Instant::START);
assert_eq!(cycle.decoder.start, INIT_ADDR);
2024-03-03 21:26:15 +00:00
assert_eq!(cycle.decoder.instruction, Instruction::NOP);
2024-03-16 06:01:41 +00:00
(cpu, cycle, memory)
2023-03-26 04:27:02 +00:00
}
2024-03-16 06:01:41 +00:00
fn load_memory<Bus: BusAccess<u32, Instant>>(bus: &mut Bus, data: &[u16]) {
2023-03-26 04:27:02 +00:00
let mut addr = INIT_ADDR;
for word in data {
2024-03-16 06:01:41 +00:00
bus.write_beu16(Instant::START, addr, *word).unwrap();
2023-03-26 04:27:02 +00:00
addr += 2;
}
}
2024-03-16 06:01:41 +00:00
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);
2024-03-16 06:01:41 +00:00
let mut executor = cycle.begin(&mut cpu, &mut memory);
2023-03-26 04:27:02 +00:00
let mut timing = M68kInstructionTiming::new(case.cpu, 16);
2024-03-03 21:26:15 +00:00
executor.decode_next().unwrap();
assert_eq!(executor.cycle.decoder.instruction, case.ins.clone());
2023-03-26 04:27:02 +00:00
2024-03-03 21:26:15 +00:00
timing.add_instruction(&executor.cycle.decoder.instruction);
let result = timing.calculate_clocks();
2023-03-26 04:27:02 +00:00
let expected = match case.cpu {
M68kType::MC68000 => case.timing.0,
M68kType::MC68010 => case.timing.1,
_ => case.timing.2,
};
//assert_eq!(expected, result);
if expected == result {
Ok(())
} else {
println!("{:?}", timing);
2024-03-16 06:01:41 +00:00
Err(format!("expected {} but found {}", expected, result))
2023-03-26 04:27:02 +00:00
}
}
#[test]
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 },
//}
if let Err(_) = run_timing_test(case) {
errors += 1;
}
}
if errors > 0 {
panic!("{} errors", errors);
}
}