Fixed m68k tests after refactor

This commit is contained in:
transistor 2024-03-03 13:26:15 -08:00
parent cff6a48cc7
commit 54ebcce94c
6 changed files with 74 additions and 51 deletions

View File

@ -466,3 +466,16 @@ General Work
shift instructions pass now, but there are lots but fewer than before failures for the asl and
asr instructions, some movem and movep errors and some bcd instruction errors, mostly
2024-03-02
- I'm trying to extract the memory/bus interface, and pass it in at the start of each cycle instead
of having the BusPort permanently embedded, which will allow migrating to emulator-hal.
- The functional way would be argument drilling; passing an extra argument to each function in the
entire execution core. The problem is that it's messy, so a solution that is still functional is to
implement all of the execution logic on a newtype that contains a reference to the mutable state and
the owned cycle data, and at the end of the cycle, decompose the M68kCycleGuard that holds the
reference, and keep the cycle data for debugging purposes.
- 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

View File

@ -50,7 +50,7 @@ impl M68kCycle {
}
}
pub fn new(cpu: &mut M68k, clock: Instant) -> Self {
pub fn new(cpu: &M68k, clock: Instant) -> Self {
let is_supervisor = cpu.state.sr & (Flags:: Supervisor as u16) != 0;
let pc = cpu.state.pc;
let data_width = cpu.port.data_width();
@ -99,17 +99,17 @@ impl<'a> M68kCycleGuard<'a> {
println!();
}
pub fn finalize(self) -> M68kCycle {
pub fn end(self) -> M68kCycle {
self.cycle
}
}
impl Steppable for M68k {
fn step(&mut self, system: &System) -> Result<Duration, Error> {
let mut cycle = M68kCycle::new(self, system.clock);
let cycle = M68kCycle::new(self, system.clock);
let mut execution = cycle.begin(self);
let clocks = execution.step(system)?;
self.cycle = execution.finalize();
self.cycle = execution.end();
Ok(self.frequency.period_duration() * clocks as u64)
}
@ -193,8 +193,7 @@ impl<'a> M68kCycleGuard<'a> {
pub fn cycle_one(&mut self, system: &System) -> Result<ClockCycles, M68kError> {
self.check_breakpoints()?;
self.decode_next()?;
self.execute_current()?;
self.decode_and_execute()?;
self.check_pending_interrupts(system)?;
Ok(self.cycle.timing.calculate_clocks(false, 1))
@ -299,6 +298,13 @@ impl<'a> M68kCycleGuard<'a> {
Ok(())
}
#[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> {
let is_supervisor = self.is_supervisor();

View File

@ -80,7 +80,7 @@ fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, System) {
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);
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)
@ -95,18 +95,18 @@ fn load_memory(system: &System, data: &[u16]) {
}
fn run_decode_test(case: &TestCase) {
let (mut cpu, mut cycle, system) = init_decode_test(case.cpu);
let (mut cpu, cycle, system) = init_decode_test(case.cpu);
load_memory(&system, case.data);
match &case.ins {
Some(ins) => {
let mut execution = cycle.begin(cpu);
execution.decode_next().unwrap();
assert_eq!(cpu.decoder.instruction, ins.clone());
let mut executor = cycle.begin(&mut cpu);
executor.decode_next().unwrap();
assert_eq!(executor.cycle.decoder.instruction, ins.clone());
},
None => {
let mut execution = cycle.begin(cpu);
let next = execution.decode_next();
println!("{:?}", cpu.decoder.instruction);
let mut executor = cycle.begin(&mut cpu);
let next = executor.decode_next();
println!("{:?}", executor.cycle.decoder.instruction);
assert!(next.is_err());
},
}

View File

@ -5,7 +5,7 @@ use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Steppable, De
use moa_m68k::{M68k, M68kType};
use moa_m68k::state::M68kState;
use moa_m68k::execute::M68kCycle;
use moa_m68k::execute::{M68kCycle, M68kCycleGuard};
use moa_m68k::instructions::{Instruction, Target, Size, Sign, Direction, Condition};
const INIT_STACK: Address = 0x00002000;
@ -37,7 +37,7 @@ struct TestCase {
fn run_execute_test<F>(cputype: M68kType, mut test_func: F)
where
F: FnMut(M68kCycle, System),
F: FnMut(M68kCycleGuard, System),
{
let mut system = System::default();
@ -51,12 +51,14 @@ where
let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0);
cpu.step(&system).unwrap();
let cycle = M68kCycle::new(cpu);
assert_eq!(cycle.state.pc, INIT_ADDR as u32);
assert_eq!(cycle.state.ssp, INIT_STACK as u32);
assert_eq!(cycle.decoder.instruction, Instruction::NOP);
let cycle = M68kCycle::new(&cpu, system.clock);
let mut executor = cycle.begin(&mut cpu);
test_func(cycle, system)
assert_eq!(executor.state.pc, INIT_ADDR as u32);
assert_eq!(executor.state.ssp, INIT_STACK as u32);
assert_eq!(executor.cycle.decoder.instruction, Instruction::NOP);
test_func(executor, system)
}
fn build_state(state: &TestState) -> M68kState {
@ -79,19 +81,19 @@ fn load_memory(system: &System, data: &[u16]) {
}
fn run_test(case: &TestCase) {
run_execute_test(case.cputype, |mut cycle, system| {
run_execute_test(case.cputype, |mut executor, system| {
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();
load_memory(&system, case.data);
*cycle.state = init_state;
*executor.state = init_state;
cycle.decode_next().unwrap();
assert_eq!(cycle.decoder.instruction, case.ins);
executor.decode_next().unwrap();
assert_eq!(executor.cycle.decoder.instruction, case.ins);
cycle.execute_current().unwrap();
assert_eq!(*cycle.state, expected_state);
executor.execute_current().unwrap();
assert_eq!(*executor.state, expected_state);
let mem = system.get_bus().read_beu32(system.clock, MEM_ADDR as Address).unwrap();
assert_eq!(mem, case.fini.mem);

View File

@ -1,17 +1,18 @@
use femtos::{Instant, Frequency};
use moa_core::{System, Error, MemoryBlock, BusPort, Address, Addressable, Device};
use moa_core::{System, Error, MemoryBlock, Address, Addressable, Device};
use moa_m68k::{M68k, M68kType};
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, System) {
fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, System) {
let mut system = System::default();
// Insert basic initialization
@ -22,15 +23,13 @@ fn init_decode_test(cputype: M68kType) -> (M68k, System) {
system.get_bus().write_beu32(Instant::START, 4, INIT_ADDR as u32).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.init_cycle(Instant::START);
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);
cpu.decoder.init(true, INIT_ADDR as u32);
assert_eq!(cpu.decoder.start, INIT_ADDR as u32);
assert_eq!(cpu.decoder.instruction, Instruction::NOP);
(cpu, system)
assert_eq!(cycle.decoder.start, INIT_ADDR as u32);
assert_eq!(cycle.decoder.instruction, Instruction::NOP);
(cpu, cycle, system)
}
fn load_memory(system: &System, data: &[u16]) {
@ -42,14 +41,15 @@ fn load_memory(system: &System, data: &[u16]) {
}
fn run_timing_test(case: &TimingCase) -> Result<(), Error> {
let (mut cpu, system) = init_decode_test(case.cpu);
let (mut cpu, cycle, system) = init_decode_test(case.cpu);
let mut executor = cycle.begin(&mut cpu);
let mut timing = M68kInstructionTiming::new(case.cpu, 16);
load_memory(&system, case.data);
cpu.decode_next().unwrap();
assert_eq!(cpu.decoder.instruction, case.ins.clone());
executor.decode_next().unwrap();
assert_eq!(executor.cycle.decoder.instruction, case.ins.clone());
timing.add_instruction(&cpu.decoder.instruction);
timing.add_instruction(&executor.cycle.decoder.instruction);
let result = timing.calculate_clocks(false, 1);
let expected = match case.cpu {
M68kType::MC68000 => case.timing.0,

View File

@ -6,6 +6,7 @@ use moa_core::{System, Error, MemoryBlock, BusPort, Address, Addressable, Device
use moa_m68k::{M68k, M68kType};
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;
@ -23,7 +24,7 @@ const TIMING_TESTS: &'static [TimingCase] = &[
];
fn init_decode_test(cputype: M68kType) -> (M68k, System) {
fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, System) {
let mut system = System::default();
// Insert basic initialization
@ -34,15 +35,15 @@ fn init_decode_test(cputype: M68kType) -> (M68k, System) {
system.get_bus().write_beu32(Instant::START, 4, INIT_ADDR as u32).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();
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);
cpu.decoder.init(true, INIT_ADDR as u32);
assert_eq!(cpu.decoder.start, INIT_ADDR as u32);
assert_eq!(cpu.decoder.instruction, Instruction::NOP);
(cpu, system)
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)
}
fn load_memory(system: &System, data: &[u16]) {
@ -54,14 +55,15 @@ fn load_memory(system: &System, data: &[u16]) {
}
fn run_timing_test(case: &TimingCase) -> Result<(), Error> {
let (mut cpu, system) = init_decode_test(case.cpu);
let (mut cpu, cycle, system) = init_decode_test(case.cpu);
let mut executor = cycle.begin(&mut cpu);
let mut timing = M68kInstructionTiming::new(case.cpu, 16);
load_memory(&system, case.data);
cpu.decode_next().unwrap();
assert_eq!(cpu.decoder.instruction, case.ins.clone());
executor.decode_next().unwrap();
assert_eq!(executor.cycle.decoder.instruction, case.ins.clone());
timing.add_instruction(&cpu.decoder.instruction);
timing.add_instruction(&executor.cycle.decoder.instruction);
let result = timing.calculate_clocks(false, 1);
let expected = match case.cpu {
M68kType::MC68000 => case.timing.0,