mirror of
https://github.com/transistorfet/moa.git
synced 2025-02-22 06:29:02 +00:00
Fixed m68k tests after refactor
This commit is contained in:
parent
cff6a48cc7
commit
54ebcce94c
13
docs/log.txt
13
docs/log.txt
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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());
|
||||
},
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user