mirror of
https://github.com/transistorfet/moa.git
synced 2024-11-21 04:31:35 +00:00
Fixed some tests
This commit is contained in:
parent
59306bceff
commit
c20d7afe6e
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -824,6 +824,7 @@ name = "moa-m68k"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"emulator-hal",
|
||||
"emulator-hal-memory",
|
||||
"femtos",
|
||||
"log",
|
||||
"moa-core",
|
||||
|
@ -484,3 +484,10 @@ General Work
|
||||
- the emulator-hal conversion is going well. I'm thinking it makes more sense for the Address of
|
||||
BusAccess to be a generic instead of an associated type, but I'll need to finish converting
|
||||
everything to get a better sense of it. There's a lot of cleanup to do
|
||||
|
||||
2024-03-14
|
||||
- I finally took a look at a flamegraph of the harte_test runner, and almost the entirety of the time
|
||||
spent running tests was in zeroing of the array of memory at the start of each test. I really
|
||||
should use MaybeUninit, but I instead used Vec::with_capacity/.set_len(). It went from 15-24 minutes
|
||||
down to 6 seconds.
|
||||
|
||||
|
@ -74,7 +74,7 @@ impl fmt::Display for Error {
|
||||
}
|
||||
|
||||
impl<E> From<HostError<E>> for Error {
|
||||
fn from(err: HostError<E>) -> Self {
|
||||
fn from(_err: HostError<E>) -> Self {
|
||||
Self::Other("other".to_string())
|
||||
}
|
||||
}
|
||||
|
@ -12,5 +12,8 @@ emulator-hal = { path = "../../libraries/emulator-hal/emulator-hal" }
|
||||
|
||||
moa-core = { path = "../../core", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
emulator-hal-memory = { path = "../../libraries/emulator-hal/emulator-hal-memory" }
|
||||
|
||||
[features]
|
||||
moa = ["moa-core"]
|
||||
|
@ -26,6 +26,7 @@ impl StackTracer {
|
||||
pub struct M68kDebugger {
|
||||
pub(crate) skip_breakpoint: usize,
|
||||
pub(crate) breakpoints: Vec<u32>,
|
||||
#[allow(dead_code)]
|
||||
pub(crate) step_until_return: Option<usize>,
|
||||
pub(crate) stack_tracer: StackTracer,
|
||||
}
|
||||
|
@ -105,11 +105,8 @@ impl M68kDecoder {
|
||||
},
|
||||
Err(err) => {
|
||||
println!("{:?}", err);
|
||||
match err {
|
||||
M68kError::Exception(ex) if ex == Exceptions::IllegalInstruction => {
|
||||
println!(" at {:08x}: {:04x}", self.start, bus.read_beu16(memory.current_clock, self.start).unwrap());
|
||||
},
|
||||
_ => { },
|
||||
if let M68kError::Exception(Exceptions::IllegalInstruction) = err {
|
||||
println!(" at {:08x}: {:04x}", self.start, bus.read_beu16(memory.current_clock, self.start).unwrap());
|
||||
}
|
||||
return;
|
||||
},
|
||||
|
@ -71,7 +71,7 @@ impl M68kCycle {
|
||||
{
|
||||
cpu.stats.cycle_number += 1;
|
||||
if cpu.stats.cycle_number > cpu.stats.last_update {
|
||||
cpu.stats.last_update = cpu.stats.last_update + 1_000_000;
|
||||
cpu.stats.last_update += 1_000_000;
|
||||
let now = std::time::SystemTime::now();
|
||||
log::warn!("{} per million", now.duration_since(cpu.stats.last_time).unwrap().as_micros());
|
||||
cpu.stats.last_time = now;
|
||||
@ -79,7 +79,7 @@ impl M68kCycle {
|
||||
|
||||
M68kCycleExecutor {
|
||||
state: &mut cpu.state,
|
||||
bus: bus,
|
||||
bus,
|
||||
debugger: &mut cpu.debugger,
|
||||
cycle: self,
|
||||
}
|
||||
@ -97,7 +97,7 @@ where
|
||||
self.state.status == Status::Running
|
||||
}
|
||||
|
||||
fn reset(&mut self, now: Instant, bus: &mut Bus) -> Result<(), Self::Error> {
|
||||
fn reset(&mut self, _now: Instant, _bus: &mut Bus) -> Result<(), Self::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -173,38 +173,6 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/*
|
||||
#[inline]
|
||||
pub fn check_pending_interrupts(&mut self, system: &System) -> Result<(), M68kError<Bus::Error>> {
|
||||
// TODO this could move somewhere else
|
||||
self.state.pending_ipl = match system.get_interrupt_controller().check() {
|
||||
(true, priority) => InterruptPriority::from_u8(priority),
|
||||
(false, _) => InterruptPriority::NoInterrupt,
|
||||
};
|
||||
|
||||
let current_ipl = self.state.current_ipl as u8;
|
||||
let pending_ipl = self.state.pending_ipl as u8;
|
||||
|
||||
if self.state.pending_ipl != InterruptPriority::NoInterrupt {
|
||||
let priority_mask = ((self.state.sr & Flags::IntMask as u16) >> 8) as u8;
|
||||
|
||||
if (pending_ipl > priority_mask || pending_ipl == 7) && pending_ipl >= current_ipl {
|
||||
log::debug!("{} interrupt: {} @ {} ns", DEV_NAME, pending_ipl, system.clock.as_duration().as_nanos());
|
||||
self.state.current_ipl = self.state.pending_ipl;
|
||||
let ack_num = system.get_interrupt_controller().acknowledge(self.state.current_ipl as u8)?;
|
||||
self.exception(ack_num, true)?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
if pending_ipl < current_ipl {
|
||||
self.state.current_ipl = self.state.pending_ipl;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
*/
|
||||
|
||||
#[inline]
|
||||
pub fn check_pending_interrupts(&mut self, interrupt: (bool, u8, u8)) -> Result<(InterruptPriority, Option<u8>), M68kError<Bus::Error>> {
|
||||
let ack_num;
|
||||
@ -315,7 +283,7 @@ where
|
||||
Ok(())
|
||||
},
|
||||
Err(M68kError::Interrupt(ex)) => {
|
||||
self.exception(ex as u8, false)?;
|
||||
self.exception(ex, false)?;
|
||||
Ok(())
|
||||
},
|
||||
Err(err) => Err(err),
|
||||
|
@ -12,5 +12,6 @@ pub mod tests;
|
||||
#[cfg(feature = "moa")]
|
||||
pub mod moa;
|
||||
|
||||
pub use self::state::{M68k, M68kType, M68kError};
|
||||
pub use crate::state::{M68k, M68kType, M68kError};
|
||||
pub use crate::memory::{M68kAddress, M68kAddressSpace};
|
||||
|
||||
|
@ -153,9 +153,9 @@ impl M68kBusPort {
|
||||
Bus: BusAccess<M68kAddress, Instant, Error = BusError>,
|
||||
{
|
||||
let addr = addr & self.address_mask;
|
||||
for i in (0..data.len()).step_by(self.data_bytewidth as usize) {
|
||||
for i in (0..data.len()).step_by(self.data_bytewidth) {
|
||||
let addr_index = (addr + i as M68kAddress) & self.address_mask;
|
||||
let end = cmp::min(i + self.data_bytewidth as usize, data.len());
|
||||
let end = cmp::min(i + self.data_bytewidth, data.len());
|
||||
bus.read(clock, addr_index, &mut data[i..end])
|
||||
.map_err(|err| M68kError::BusError(err))?;
|
||||
}
|
||||
@ -167,9 +167,9 @@ impl M68kBusPort {
|
||||
Bus: BusAccess<M68kAddress, Instant, Error = BusError>,
|
||||
{
|
||||
let addr = addr & self.address_mask;
|
||||
for i in (0..data.len()).step_by(self.data_bytewidth as usize) {
|
||||
for i in (0..data.len()).step_by(self.data_bytewidth) {
|
||||
let addr_index = (addr + i as M68kAddress) & self.address_mask;
|
||||
let end = cmp::min(i + self.data_bytewidth as usize, data.len());
|
||||
let end = cmp::min(i + self.data_bytewidth, data.len());
|
||||
bus.write(clock, addr_index, &data[i..end])
|
||||
.map_err(|err| M68kError::BusError(err))?;
|
||||
}
|
||||
@ -204,7 +204,7 @@ impl M68kBusPort {
|
||||
where
|
||||
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, size, MemAccess::Read, MemType::Data, false)?;
|
||||
self.read_sized(bus, addr, size)
|
||||
}
|
||||
|
||||
@ -212,7 +212,7 @@ impl M68kBusPort {
|
||||
where
|
||||
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, size, MemAccess::Write, MemType::Data, false)?;
|
||||
self.write_sized(bus, addr, size, value)
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ impl Debuggable for M68k {
|
||||
|
||||
fn print_disassembly(&mut self, addr: Address, count: usize) {
|
||||
let mut decoder = M68kDecoder::new(self.info.chip, true, 0);
|
||||
//decoder.dump_disassembly(&mut self.bus, 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> {
|
||||
|
@ -237,7 +237,7 @@ impl Default for M68kState {
|
||||
}
|
||||
|
||||
impl M68kState {
|
||||
pub fn dump_state<W: Write>(&mut self, writer: &mut W) -> Result<(), fmt::Error> {
|
||||
pub fn dump_state<W: Write>(&self, writer: &mut W) -> Result<(), fmt::Error> {
|
||||
writeln!(writer, "Status: {:?}", self.status)?;
|
||||
writeln!(writer, "PC: {:#010x}", self.pc)?;
|
||||
writeln!(writer, "SR: {:#06x}", self.sr)?;
|
||||
@ -265,15 +265,16 @@ impl M68k {
|
||||
Self::new(CpuInfo::from_type(cputype, freq))
|
||||
}
|
||||
|
||||
pub fn dump_state<W: Write>(&mut self, writer: &mut W) {
|
||||
self.state.dump_state(writer);
|
||||
pub fn dump_state<W: Write>(&self, writer: &mut W) -> Result<(), fmt::Error> {
|
||||
self.state.dump_state(writer)?;
|
||||
|
||||
if let Some(cycle) = self.cycle.as_ref() {
|
||||
println!("Current Instruction: {:#010x} {:?}", cycle.decoder.start, cycle.decoder.instruction);
|
||||
println!();
|
||||
writeln!(writer, "Current Instruction: {:#010x} {:?}", cycle.decoder.start, cycle.decoder.instruction)?;
|
||||
writeln!(writer)?;
|
||||
}
|
||||
//memory::dump_memory(&mut self.bus, self.cycle.current_clock, self.state.ssp, 0x40);
|
||||
println!();
|
||||
writeln!(writer)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -1,12 +1,9 @@
|
||||
|
||||
/(
|
||||
#[cfg(test)]
|
||||
mod decode_unit_tests {
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use femtos::Instant;
|
||||
use emulator_hal::bus::{BusAccess, BusAdapter};
|
||||
|
||||
use moa_core::{Bus, BusPort, Address, Addressable, MemoryBlock, Device, Error};
|
||||
use emulator_hal::bus::BusAccess;
|
||||
use emulator_hal_memory::MemoryBlock;
|
||||
|
||||
use crate::M68kType;
|
||||
use crate::instructions::{Target, Size, XRegister, BaseRegister, IndexRegister};
|
||||
@ -15,21 +12,11 @@ mod decode_unit_tests {
|
||||
|
||||
const INIT_ADDR: u32 = 0x00000000;
|
||||
|
||||
fn init_decode_test<'a>(cputype: M68kType) -> InstructionDecoding<'a, BusAdapter<u32, u64, Instant, &'a mut dyn Addressable, Error>> {
|
||||
let bus = Rc::new(RefCell::new(Bus::default()));
|
||||
let mem = MemoryBlock::new(vec![0; 0x0000100]);
|
||||
bus.borrow_mut().insert(0x00000000, Device::new(mem));
|
||||
|
||||
let mut bus = bus.borrow_mut();
|
||||
let mut adapter: BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error> = BusAdapter::new(
|
||||
&mut *bus,
|
||||
|addr| addr as u64,
|
||||
|err| err.try_into().unwrap(),
|
||||
);
|
||||
|
||||
fn init_decode_test<'a>(cputype: M68kType) -> InstructionDecoding<'a, MemoryBlock<u32, Instant>> {
|
||||
let mut memory = MemoryBlock::from(vec![0; 0x0000100]);
|
||||
let mut decoder = M68kDecoder::new(cputype, true, 0);
|
||||
let mut decoding = InstructionDecoding {
|
||||
port: &mut adapter,
|
||||
bus: &mut memory,
|
||||
memory: &mut M68kBusPort::default(),
|
||||
decoder: &mut decoder,
|
||||
};
|
||||
@ -67,7 +54,7 @@ mod decode_unit_tests {
|
||||
let size = Size::Long;
|
||||
let expected = 0x12345678;
|
||||
|
||||
decoder.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
|
||||
decoder.bus.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
|
||||
|
||||
let target = decoder.get_mode_as_target(0b010, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectAReg(2));
|
||||
@ -80,7 +67,7 @@ mod decode_unit_tests {
|
||||
let size = Size::Long;
|
||||
let expected = 0x12345678;
|
||||
|
||||
decoder.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
|
||||
decoder.bus.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
|
||||
|
||||
let target = decoder.get_mode_as_target(0b011, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectARegInc(2));
|
||||
@ -93,7 +80,7 @@ mod decode_unit_tests {
|
||||
let size = Size::Long;
|
||||
let expected = 0x12345678;
|
||||
|
||||
decoder.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
|
||||
decoder.bus.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
|
||||
|
||||
let target = decoder.get_mode_as_target(0b100, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectARegDec(2));
|
||||
@ -106,7 +93,7 @@ mod decode_unit_tests {
|
||||
let size = Size::Long;
|
||||
let offset = -8;
|
||||
|
||||
decoder.port.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap();
|
||||
decoder.bus.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap();
|
||||
|
||||
let target = decoder.get_mode_as_target(0b101, 0b100, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(4), None, offset));
|
||||
@ -120,8 +107,8 @@ mod decode_unit_tests {
|
||||
let offset = -8;
|
||||
let brief_extension = 0x3800 | (((offset as i8) as u8) as u16);
|
||||
|
||||
decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
|
||||
decoder.port.write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16).unwrap();
|
||||
decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
|
||||
decoder.bus.write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16).unwrap();
|
||||
|
||||
let target = decoder.get_mode_as_target(0b110, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(2), Some(IndexRegister { xreg: XRegister::DReg(3), scale: 0, size: size }), offset));
|
||||
@ -135,8 +122,8 @@ mod decode_unit_tests {
|
||||
let offset = -1843235 as i32;
|
||||
let brief_extension = 0xF330;
|
||||
|
||||
decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
|
||||
decoder.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap();
|
||||
decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
|
||||
decoder.bus.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap();
|
||||
|
||||
let target = decoder.get_mode_as_target(0b110, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(2), Some(IndexRegister { xreg: XRegister::AReg(7), scale: 1, size: size }), offset));
|
||||
@ -150,8 +137,8 @@ mod decode_unit_tests {
|
||||
let offset = -1843235 as i32;
|
||||
let brief_extension = 0xF3B0;
|
||||
|
||||
decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
|
||||
decoder.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap();
|
||||
decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
|
||||
decoder.bus.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap();
|
||||
|
||||
let target = decoder.get_mode_as_target(0b110, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::None, Some(IndexRegister { xreg: XRegister::AReg(7), scale: 1, size: size }), offset));
|
||||
@ -165,8 +152,8 @@ mod decode_unit_tests {
|
||||
let offset = -1843235 as i32;
|
||||
let brief_extension = 0xF370;
|
||||
|
||||
decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
|
||||
decoder.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap();
|
||||
decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
|
||||
decoder.bus.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap();
|
||||
|
||||
let target = decoder.get_mode_as_target(0b110, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(2), None, offset));
|
||||
@ -179,7 +166,7 @@ mod decode_unit_tests {
|
||||
let size = Size::Long;
|
||||
let offset = -8;
|
||||
|
||||
decoder.port.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap();
|
||||
decoder.bus.write_beu16(Instant::START, INIT_ADDR, (offset as i16) as u16).unwrap();
|
||||
|
||||
let target = decoder.get_mode_as_target(0b111, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, None, offset));
|
||||
@ -193,8 +180,8 @@ mod decode_unit_tests {
|
||||
let offset = -8;
|
||||
let brief_extension = 0x3000 | (((offset as i8) as u8) as u16);
|
||||
|
||||
decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
|
||||
decoder.port.write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16).unwrap();
|
||||
decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
|
||||
decoder.bus.write_beu16(Instant::START, INIT_ADDR + 2, (offset as i16) as u16).unwrap();
|
||||
|
||||
let target = decoder.get_mode_as_target(0b111, 0b011, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, Some(IndexRegister { xreg: XRegister::DReg(3), scale: 0, size: size }), offset));
|
||||
@ -208,8 +195,8 @@ mod decode_unit_tests {
|
||||
let offset = -1843235 as i32;
|
||||
let brief_extension = 0xF330;
|
||||
|
||||
decoder.port.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
|
||||
decoder.port.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap();
|
||||
decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
|
||||
decoder.bus.write_beu32(Instant::START, INIT_ADDR + 2, offset as u32).unwrap();
|
||||
|
||||
let target = decoder.get_mode_as_target(0b111, 0b011, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, Some(IndexRegister { xreg: XRegister::AReg(7), scale: 1, size: size }), offset));
|
||||
@ -223,7 +210,7 @@ mod decode_unit_tests {
|
||||
let size = Size::Word;
|
||||
let expected = 0x1234;
|
||||
|
||||
decoder.port.write_beu16(Instant::START, INIT_ADDR, expected as u16).unwrap();
|
||||
decoder.bus.write_beu16(Instant::START, INIT_ADDR, expected as u16).unwrap();
|
||||
|
||||
let target = decoder.get_mode_as_target(0b111, 0b000, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectMemory(expected, Size::Word));
|
||||
@ -236,7 +223,7 @@ mod decode_unit_tests {
|
||||
let size = Size::Word;
|
||||
let expected = 0x12345678;
|
||||
|
||||
decoder.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
|
||||
decoder.bus.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
|
||||
|
||||
let target = decoder.get_mode_as_target(0b111, 0b001, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectMemory(expected, Size::Long));
|
||||
@ -249,20 +236,19 @@ mod decode_unit_tests {
|
||||
let size = Size::Word;
|
||||
let expected = 0x1234;
|
||||
|
||||
decoder.port.write_beu16(Instant::START, INIT_ADDR, expected as u16).unwrap();
|
||||
decoder.bus.write_beu16(Instant::START, INIT_ADDR, expected as u16).unwrap();
|
||||
|
||||
let target = decoder.get_mode_as_target(0b111, 0b100, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::Immediate(expected));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod execute_unit_tests {
|
||||
use femtos::{Instant, Frequency};
|
||||
use emulator_hal::bus::{BusAdapter, BusAccess};
|
||||
|
||||
use moa_core::{System, MemoryBlock, Addressable, Steppable, Device, Error};
|
||||
use emulator_hal::step::Step;
|
||||
use emulator_hal_memory::MemoryBlock;
|
||||
|
||||
use crate::{M68k, M68kType};
|
||||
use crate::execute::{Used, M68kCycle, M68kCycleExecutor};
|
||||
@ -271,31 +257,23 @@ mod execute_unit_tests {
|
||||
const INIT_STACK: u32 = 0x00002000;
|
||||
const INIT_ADDR: u32 = 0x00000010;
|
||||
|
||||
#[allow(clippy::uninit_vec)]
|
||||
fn run_execute_test<F>(cputype: M68kType, mut test_func: F)
|
||||
where
|
||||
F: FnMut(M68kCycleExecutor<&mut BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error>>),
|
||||
F: FnMut(M68kCycleExecutor<&mut MemoryBlock<u32, Instant>>),
|
||||
{
|
||||
let mut system = System::default();
|
||||
|
||||
// Insert basic initialization
|
||||
let data = vec![0; 0x00100000];
|
||||
let mem = MemoryBlock::new(data);
|
||||
system.add_addressable_device(0x00000000, Device::new(mem)).unwrap();
|
||||
system.get_bus().write_beu32(system.clock, 0, INIT_STACK as u32).unwrap();
|
||||
system.get_bus().write_beu32(system.clock, 4, INIT_ADDR as u32).unwrap();
|
||||
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 as u32).unwrap();
|
||||
memory.write_beu32(Instant::START, 4, INIT_ADDR as u32).unwrap();
|
||||
|
||||
let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10));
|
||||
cpu.step(&system).unwrap();
|
||||
let mut cycle = M68kCycle::new(&mut cpu, system.clock);
|
||||
cpu.step(Instant::START, &mut memory).unwrap();
|
||||
let mut cycle = M68kCycle::new(&mut cpu, Instant::START);
|
||||
|
||||
let mut bus = system.bus.borrow_mut();
|
||||
let mut adapter: BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error> = BusAdapter::new(
|
||||
&mut *bus,
|
||||
|addr| addr as u64,
|
||||
|err| err.try_into().unwrap(),
|
||||
);
|
||||
|
||||
let mut executor = cycle.begin(&mut cpu, &mut adapter);
|
||||
let mut executor = cycle.begin(&mut cpu, &mut memory);
|
||||
executor.cycle.decoder.init(true, executor.state.pc);
|
||||
assert_eq!(executor.state.pc, INIT_ADDR as u32);
|
||||
assert_eq!(executor.state.ssp, INIT_STACK as u32);
|
||||
@ -340,7 +318,7 @@ mod execute_unit_tests {
|
||||
let size = Size::Long;
|
||||
let expected = 0x12345678;
|
||||
let target = Target::IndirectAReg(2);
|
||||
cycle.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
|
||||
cycle.bus.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
|
||||
|
||||
cycle.state.a_reg[2] = INIT_ADDR as u32;
|
||||
let result = cycle.get_target_value(target, size, Used::Once).unwrap();
|
||||
@ -354,7 +332,7 @@ mod execute_unit_tests {
|
||||
let size = Size::Long;
|
||||
let expected = 0x12345678;
|
||||
let target = Target::IndirectARegInc(2);
|
||||
cycle.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
|
||||
cycle.bus.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
|
||||
|
||||
cycle.state.a_reg[2] = INIT_ADDR as u32;
|
||||
let result = cycle.get_target_value(target, size, Used::Once).unwrap();
|
||||
@ -369,7 +347,7 @@ mod execute_unit_tests {
|
||||
let size = Size::Long;
|
||||
let expected = 0x12345678;
|
||||
let target = Target::IndirectARegDec(2);
|
||||
cycle.port.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
|
||||
cycle.bus.write_beu32(Instant::START, INIT_ADDR, expected).unwrap();
|
||||
|
||||
cycle.state.a_reg[2] = (INIT_ADDR as u32) + 4;
|
||||
let result = cycle.get_target_value(target, size, Used::Once).unwrap();
|
||||
|
@ -1,16 +1,15 @@
|
||||
|
||||
use femtos::{Instant, Frequency};
|
||||
use emulator_hal::bus::BusAdapter;
|
||||
use emulator_hal::bus::BusAccess;
|
||||
use emulator_hal_memory::MemoryBlock;
|
||||
|
||||
use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Device, Error};
|
||||
|
||||
use moa_m68k::{M68k, M68kType};
|
||||
use moa_m68k::{M68k, M68kType, M68kAddress};
|
||||
use moa_m68k::instructions::{Instruction, Target, Size, Sign, XRegister, BaseRegister, IndexRegister, Direction};
|
||||
use moa_m68k::assembler::M68kAssembler;
|
||||
use moa_m68k::execute::M68kCycle;
|
||||
|
||||
const INIT_STACK: Address = 0x00002000;
|
||||
const INIT_ADDR: Address = 0x00000010;
|
||||
const INIT_STACK: M68kAddress = 0x00002000;
|
||||
const INIT_ADDR: M68kAddress = 0x00000010;
|
||||
|
||||
struct TestCase {
|
||||
cpu: M68kType,
|
||||
@ -65,56 +64,47 @@ const DECODE_TESTS: &'static [TestCase] = &[
|
||||
];
|
||||
|
||||
|
||||
fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, System) {
|
||||
let mut system = System::default();
|
||||
|
||||
fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, MemoryBlock<u32, Instant>) {
|
||||
// Insert basic initialization
|
||||
let data = vec![0; 0x00100000];
|
||||
let mem = MemoryBlock::new(data);
|
||||
system.add_addressable_device(0x00000000, Device::new(mem)).unwrap();
|
||||
system.get_bus().write_beu32(Instant::START, 0, INIT_STACK as u32).unwrap();
|
||||
system.get_bus().write_beu32(Instant::START, 4, INIT_ADDR as u32).unwrap();
|
||||
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();
|
||||
|
||||
// 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);
|
||||
let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10));
|
||||
//cpu.reset_cpu().unwrap();
|
||||
//assert_eq!(cpu.state.pc, INIT_ADDR as u32);
|
||||
//assert_eq!(cpu.state.ssp, INIT_STACK as u32);
|
||||
//assert_eq!(cpu.state.pc, INIT_ADDR);
|
||||
//assert_eq!(cpu.state.ssp, INIT_STACK);
|
||||
|
||||
let cycle = M68kCycle::new(&cpu, system.clock);
|
||||
//assert_eq!(cycle.decoder.start, INIT_ADDR as u32);
|
||||
let cycle = M68kCycle::new(&cpu, Instant::START);
|
||||
//assert_eq!(cycle.decoder.start, INIT_ADDR);
|
||||
//assert_eq!(cycle.decoder.instruction, Instruction::NOP);
|
||||
(cpu, cycle, system)
|
||||
(cpu, cycle, memory)
|
||||
}
|
||||
|
||||
fn load_memory(system: &System, data: &[u16]) {
|
||||
fn load_memory<Bus: BusAccess<u32, Instant>>(memory: &mut Bus, data: &[u16]) {
|
||||
let mut addr = INIT_ADDR;
|
||||
for word in data {
|
||||
system.get_bus().write_beu16(system.clock, addr, *word).unwrap();
|
||||
memory.write_beu16(Instant::START, addr, *word).unwrap();
|
||||
addr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
fn run_decode_test(case: &TestCase) {
|
||||
let (mut cpu, cycle, system) = init_decode_test(case.cpu);
|
||||
load_memory(&system, case.data);
|
||||
|
||||
let mut bus = system.bus.borrow_mut();
|
||||
let mut adapter: BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error> = BusAdapter::new(
|
||||
&mut *bus,
|
||||
|addr| addr as u64,
|
||||
|err| err.try_into().unwrap(),
|
||||
);
|
||||
let (mut cpu, cycle, mut memory) = init_decode_test(case.cpu);
|
||||
load_memory(&mut memory, case.data);
|
||||
|
||||
match &case.ins {
|
||||
Some(ins) => {
|
||||
let mut executor = cycle.begin(&mut cpu, &mut adapter);
|
||||
let mut executor = cycle.begin(&mut cpu, &mut memory);
|
||||
executor.reset_cpu().unwrap();
|
||||
executor.decode_next().unwrap();
|
||||
assert_eq!(executor.cycle.decoder.instruction, ins.clone());
|
||||
},
|
||||
None => {
|
||||
let mut executor = cycle.begin(&mut cpu, &mut adapter);
|
||||
let mut executor = cycle.begin(&mut cpu, &mut memory);
|
||||
executor.reset_cpu().unwrap();
|
||||
let next = executor.decode_next();
|
||||
println!("{:?}", executor.cycle.decoder.instruction);
|
||||
|
@ -1,16 +1,16 @@
|
||||
|
||||
use femtos::{Instant, Frequency};
|
||||
use emulator_hal::bus::BusAdapter;
|
||||
use emulator_hal::bus::BusAccess;
|
||||
use emulator_hal::step::Step;
|
||||
use emulator_hal_memory::MemoryBlock;
|
||||
|
||||
use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Steppable, Device, Error};
|
||||
|
||||
use moa_m68k::{M68k, M68kType};
|
||||
use moa_m68k::{M68k, M68kType, M68kAddress};
|
||||
use moa_m68k::state::M68kState;
|
||||
use moa_m68k::execute::{M68kCycle, M68kCycleExecutor};
|
||||
use moa_m68k::instructions::{Instruction, Target, Size, Sign, Direction, Condition};
|
||||
|
||||
const INIT_STACK: Address = 0x00002000;
|
||||
const INIT_ADDR: Address = 0x00000010;
|
||||
const INIT_STACK: M68kAddress = 0x00002000;
|
||||
const INIT_ADDR: M68kAddress = 0x00000010;
|
||||
|
||||
const MEM_ADDR: u32 = 0x00001234;
|
||||
|
||||
@ -36,37 +36,29 @@ struct TestCase {
|
||||
}
|
||||
|
||||
|
||||
#[allow(clippy::uninit_vec)]
|
||||
fn run_execute_test<F>(cputype: M68kType, mut test_func: F)
|
||||
where
|
||||
F: FnMut(M68kCycleExecutor<&mut BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error>>, &System),
|
||||
F: FnMut(M68kCycleExecutor<&mut MemoryBlock<u32, Instant>>),
|
||||
{
|
||||
let mut system = System::default();
|
||||
|
||||
// Insert basic initialization
|
||||
let data = vec![0; 0x00100000];
|
||||
let mem = MemoryBlock::new(data);
|
||||
system.add_addressable_device(0x00000000, Device::new(mem)).unwrap();
|
||||
system.get_bus().write_beu32(Instant::START, 0, INIT_STACK as u32).unwrap();
|
||||
system.get_bus().write_beu32(Instant::START, 4, INIT_ADDR as u32).unwrap();
|
||||
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();
|
||||
|
||||
let mut bus = system.bus.borrow_mut();
|
||||
let mut adapter: BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error> = BusAdapter::new(
|
||||
&mut *bus,
|
||||
|addr| addr as u64,
|
||||
|err| err.try_into().unwrap(),
|
||||
);
|
||||
let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10));
|
||||
cpu.step(Instant::START, &mut memory).unwrap();
|
||||
|
||||
let mut cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0);
|
||||
cpu.step(&system).unwrap();
|
||||
let cycle = M68kCycle::new(&cpu, Instant::START);
|
||||
let executor = cycle.begin(&mut cpu, &mut memory);
|
||||
|
||||
let cycle = M68kCycle::new(&cpu, system.clock);
|
||||
let executor = cycle.begin(&mut cpu, &mut adapter);
|
||||
|
||||
assert_eq!(executor.state.pc, INIT_ADDR as u32);
|
||||
assert_eq!(executor.state.ssp, INIT_STACK as u32);
|
||||
assert_eq!(executor.state.pc, INIT_ADDR);
|
||||
assert_eq!(executor.state.ssp, INIT_STACK);
|
||||
assert_eq!(executor.cycle.decoder.instruction, Instruction::NOP);
|
||||
|
||||
test_func(executor, &system)
|
||||
test_func(executor)
|
||||
}
|
||||
|
||||
fn build_state(state: &TestState) -> M68kState {
|
||||
@ -82,19 +74,21 @@ fn build_state(state: &TestState) -> M68kState {
|
||||
new_state
|
||||
}
|
||||
|
||||
fn load_memory(system: &System, data: &[u16]) {
|
||||
for i in 0..data.len() {
|
||||
system.get_bus().write_beu16(system.clock, (i << 1) as Address, data[i]).unwrap();
|
||||
}
|
||||
fn load_memory<Bus: BusAccess<u32, Instant>>(bus: &mut Bus, data: &[u16]) {
|
||||
let mut addr = INIT_ADDR;
|
||||
for word in data {
|
||||
bus.write_beu16(Instant::START, addr, *word).unwrap();
|
||||
addr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
fn run_test(case: &TestCase) {
|
||||
run_execute_test(case.cputype, |mut executor, system| {
|
||||
run_execute_test(case.cputype, |mut executor| {
|
||||
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();
|
||||
executor.bus.write_beu32(Instant::START, MEM_ADDR, case.init.mem).unwrap();
|
||||
|
||||
load_memory(&system, case.data);
|
||||
load_memory(&mut executor.bus, case.data);
|
||||
*executor.state = init_state;
|
||||
|
||||
executor.decode_next().unwrap();
|
||||
@ -103,7 +97,7 @@ fn run_test(case: &TestCase) {
|
||||
executor.execute_current().unwrap();
|
||||
assert_eq!(*executor.state, expected_state);
|
||||
|
||||
let mem = system.get_bus().read_beu32(system.clock, MEM_ADDR as Address).unwrap();
|
||||
let mem = executor.bus.read_beu32(Instant::START, MEM_ADDR).unwrap();
|
||||
assert_eq!(mem, case.fini.mem);
|
||||
});
|
||||
}
|
||||
|
@ -1,60 +1,51 @@
|
||||
|
||||
use femtos::{Instant, Frequency};
|
||||
use emulator_hal::bus::BusAdapter;
|
||||
use emulator_hal::bus::BusAccess;
|
||||
use emulator_hal_memory::MemoryBlock;
|
||||
|
||||
use moa_core::{System, Error, MemoryBlock, Address, Addressable, Device};
|
||||
|
||||
use moa_m68k::{M68k, M68kType};
|
||||
use moa_m68k::{M68k, M68kType, M68kAddress};
|
||||
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, M68kCycle, System) {
|
||||
let mut system = System::default();
|
||||
const INIT_STACK: M68kAddress = 0x00002000;
|
||||
const INIT_ADDR: M68kAddress = 0x00000010;
|
||||
|
||||
#[allow(clippy::uninit_vec)]
|
||||
fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, MemoryBlock<u32, Instant>) {
|
||||
// Insert basic initialization
|
||||
let data = vec![0; 0x00100000];
|
||||
let mem = MemoryBlock::new(data);
|
||||
system.add_addressable_device(0x00000000, Device::new(mem)).unwrap();
|
||||
system.get_bus().write_beu32(Instant::START, 0, INIT_STACK as u32).unwrap();
|
||||
system.get_bus().write_beu32(Instant::START, 4, INIT_ADDR as u32).unwrap();
|
||||
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();
|
||||
|
||||
// Initialize the CPU and make sure it's in the expected state
|
||||
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);
|
||||
assert_eq!(cycle.decoder.start, INIT_ADDR as u32);
|
||||
let cpu = M68k::from_type(cputype, Frequency::from_mhz(10));
|
||||
let cycle = M68kCycle::new(&cpu, Instant::START);
|
||||
assert_eq!(cpu.state.pc, INIT_ADDR);
|
||||
assert_eq!(cpu.state.ssp, INIT_STACK);
|
||||
assert_eq!(cycle.decoder.start, INIT_ADDR);
|
||||
assert_eq!(cycle.decoder.instruction, Instruction::NOP);
|
||||
(cpu, cycle, system)
|
||||
(cpu, cycle, memory)
|
||||
}
|
||||
|
||||
fn load_memory(system: &System, data: &[u16]) {
|
||||
fn load_memory<Bus: BusAccess<u32, Instant>>(bus: &mut Bus, data: &[u16]) {
|
||||
let mut addr = INIT_ADDR;
|
||||
for word in data {
|
||||
system.get_bus().write_beu16(system.clock, addr, *word).unwrap();
|
||||
bus.write_beu16(Instant::START, addr, *word).unwrap();
|
||||
addr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
fn run_timing_test(case: &TimingCase) -> Result<(), Error> {
|
||||
let (mut cpu, cycle, system) = init_decode_test(case.cpu);
|
||||
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);
|
||||
|
||||
let mut bus = system.bus.borrow_mut();
|
||||
let mut adapter: BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error> = BusAdapter::new(
|
||||
&mut *bus,
|
||||
|addr| addr as u64,
|
||||
|err| err.try_into().unwrap(),
|
||||
);
|
||||
|
||||
let mut executor = cycle.begin(&mut cpu, &mut adapter);
|
||||
let mut executor = cycle.begin(&mut cpu, &mut memory);
|
||||
let mut timing = M68kInstructionTiming::new(case.cpu, 16);
|
||||
|
||||
load_memory(&system, case.data);
|
||||
executor.decode_next().unwrap();
|
||||
assert_eq!(executor.cycle.decoder.instruction, case.ins.clone());
|
||||
|
||||
@ -71,7 +62,7 @@ fn run_timing_test(case: &TimingCase) -> Result<(), Error> {
|
||||
Ok(())
|
||||
} else {
|
||||
println!("{:?}", timing);
|
||||
Err(Error::new(format!("expected {} but found {}", expected, result)))
|
||||
Err(format!("expected {} but found {}", expected, result))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,16 +1,15 @@
|
||||
|
||||
use femtos::{Instant, Frequency};
|
||||
use emulator_hal::bus::BusAdapter;
|
||||
use emulator_hal::bus::BusAccess;
|
||||
use emulator_hal_memory::MemoryBlock;
|
||||
|
||||
use moa_core::{System, Error, MemoryBlock, BusPort, Address, Addressable, Device};
|
||||
|
||||
use moa_m68k::{M68k, M68kType};
|
||||
use moa_m68k::{M68k, M68kType, M68kAddress};
|
||||
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;
|
||||
const INIT_STACK: M68kAddress = 0x00002000;
|
||||
const INIT_ADDR: M68kAddress = 0x00000010;
|
||||
|
||||
|
||||
struct TimingCase {
|
||||
@ -25,50 +24,41 @@ const TIMING_TESTS: &'static [TimingCase] = &[
|
||||
];
|
||||
|
||||
|
||||
fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, System) {
|
||||
let mut system = System::default();
|
||||
|
||||
fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, MemoryBlock<u32, Instant>) {
|
||||
// Insert basic initialization
|
||||
let data = vec![0; 0x00100000];
|
||||
let mem = MemoryBlock::new(data);
|
||||
system.add_addressable_device(0x00000000, Device::new(mem)).unwrap();
|
||||
system.get_bus().write_beu32(Instant::START, 0, INIT_STACK as u32).unwrap();
|
||||
system.get_bus().write_beu32(Instant::START, 4, INIT_ADDR as u32).unwrap();
|
||||
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();
|
||||
|
||||
// Initialize the CPU and make sure it's in the expected state
|
||||
let cpu = M68k::from_type(cputype, Frequency::from_mhz(10), system.bus.clone(), 0);
|
||||
let cpu = M68k::from_type(cputype, Frequency::from_mhz(10));
|
||||
//cpu.reset_cpu().unwrap();
|
||||
assert_eq!(cpu.state.pc, INIT_ADDR as u32);
|
||||
assert_eq!(cpu.state.ssp, INIT_STACK as u32);
|
||||
assert_eq!(cpu.state.pc, INIT_ADDR);
|
||||
assert_eq!(cpu.state.ssp, INIT_STACK);
|
||||
|
||||
let cycle = M68kCycle::new(&cpu, system.clock);
|
||||
assert_eq!(cycle.decoder.start, INIT_ADDR as u32);
|
||||
let cycle = M68kCycle::new(&cpu, Instant::START);
|
||||
assert_eq!(cycle.decoder.start, INIT_ADDR);
|
||||
assert_eq!(cycle.decoder.instruction, Instruction::NOP);
|
||||
(cpu, cycle, system)
|
||||
(cpu, cycle, memory)
|
||||
}
|
||||
|
||||
fn load_memory(system: &System, data: &[u16]) {
|
||||
fn load_memory<Bus: BusAccess<u32, Instant>>(bus: &mut Bus, data: &[u16]) {
|
||||
let mut addr = INIT_ADDR;
|
||||
for word in data {
|
||||
system.get_bus().write_beu16(system.clock, addr, *word).unwrap();
|
||||
bus.write_beu16(Instant::START, addr, *word).unwrap();
|
||||
addr += 2;
|
||||
}
|
||||
}
|
||||
|
||||
fn run_timing_test(case: &TimingCase) -> Result<(), Error> {
|
||||
let (mut cpu, cycle, system) = init_decode_test(case.cpu);
|
||||
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);
|
||||
|
||||
let mut bus = system.bus.borrow_mut();
|
||||
let mut adapter: BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error> = BusAdapter::new(
|
||||
&mut *bus,
|
||||
|addr| addr as u64,
|
||||
|err| err.try_into().unwrap(),
|
||||
);
|
||||
|
||||
let mut executor = cycle.begin(&mut cpu, &mut adapter);
|
||||
let mut executor = cycle.begin(&mut cpu, &mut memory);
|
||||
let mut timing = M68kInstructionTiming::new(case.cpu, 16);
|
||||
|
||||
load_memory(&system, case.data);
|
||||
executor.decode_next().unwrap();
|
||||
assert_eq!(executor.cycle.decoder.instruction, case.ins.clone());
|
||||
|
||||
@ -85,7 +75,7 @@ fn run_timing_test(case: &TimingCase) -> Result<(), Error> {
|
||||
Ok(())
|
||||
} else {
|
||||
println!("{:?}", timing);
|
||||
Err(Error::new(format!("expected {} but found {}", expected, result)))
|
||||
Err(format!("expected {} but found {}", expected, result))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ impl MouseState {
|
||||
|
||||
let events: Vec<MouseEvent> = self
|
||||
.buttons.into_iter()
|
||||
.zip(next_state.buttons.into_iter())
|
||||
.zip(next_state.buttons)
|
||||
.enumerate()
|
||||
.filter_map(|(i, (prev, next))| {
|
||||
if prev != next {
|
||||
|
@ -24,8 +24,11 @@ pub enum HostError<E> {
|
||||
Specific(E),
|
||||
}
|
||||
|
||||
/*
|
||||
impl<E> fmt::Display for HostError<E> {
|
||||
|
||||
impl<E> fmt::Display for HostError<E>
|
||||
where
|
||||
E: fmt::Display,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
HostError::TTYNotSupported => write!(f, "This frontend doesn't support PTYs"),
|
||||
@ -38,7 +41,6 @@ impl<E> fmt::Display for HostError<E> {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
pub trait Host {
|
||||
type Error: Error;
|
||||
|
@ -272,8 +272,6 @@ impl<'input> AssemblyLexer<'input> {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
}
|
||||
} else if *ch == ' ' || *ch == '\t' || *ch == '\r' {
|
||||
self.chars.next();
|
||||
|
@ -1,4 +1,4 @@
|
||||
Last run on 2024-03-14 at commit 545f339fe2714cc648bd4a01506518a13c1faf39
|
||||
Last run on 2024-03-15 at commit 59306bceff1a5964902118f33034086a349e2fd3
|
||||
|
||||
ABCD.json.gz completed: 7993 passed, 72 FAILED
|
||||
ADD.b.json.gz completed, all passed!
|
||||
@ -11,119 +11,3 @@ ADDX.l.json.gz completed: 5472 passed, 2593 FAILED
|
||||
ADDX.w.json.gz completed, all passed!
|
||||
AND.b.json.gz completed, all passed!
|
||||
AND.l.json.gz completed: 7779 passed, 286 FAILED
|
||||
AND.w.json.gz completed: 7764 passed, 301 FAILED
|
||||
ANDItoCCR.json.gz completed, all passed!
|
||||
ANDItoSR.json.gz completed, all passed!
|
||||
ASL.b.json.gz completed: 8063 passed, 2 FAILED
|
||||
ASL.l.json.gz completed, all passed!
|
||||
ASL.w.json.gz completed: 7896 passed, 169 FAILED
|
||||
ASR.b.json.gz completed: 7783 passed, 282 FAILED
|
||||
ASR.l.json.gz completed: 8029 passed, 36 FAILED
|
||||
ASR.w.json.gz completed: 7891 passed, 174 FAILED
|
||||
BCHG.json.gz completed, all passed!
|
||||
BCLR.json.gz completed, all passed!
|
||||
BSET.json.gz completed, all passed!
|
||||
BSR.json.gz completed, all passed!
|
||||
BTST.json.gz completed: 8052 passed, 13 FAILED
|
||||
Bcc.json.gz completed, all passed!
|
||||
CHK.json.gz completed: 7744 passed, 321 FAILED
|
||||
CLR.b.json.gz completed, all passed!
|
||||
CLR.l.json.gz completed: 7472 passed, 593 FAILED
|
||||
CLR.w.json.gz completed: 7465 passed, 600 FAILED
|
||||
CMP.b.json.gz completed, all passed!
|
||||
CMP.l.json.gz completed, all passed!
|
||||
CMP.w.json.gz completed, all passed!
|
||||
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
|
||||
|
@ -2,7 +2,7 @@
|
||||
const DEFAULT_HARTE_TESTS: &str = "tests/ProcessorTests/680x0/68000/v1/";
|
||||
|
||||
use std::io::prelude::*;
|
||||
use std::fmt::{Debug, UpperHex};
|
||||
use std::fmt::{Write, Debug, UpperHex};
|
||||
use std::path::PathBuf;
|
||||
use std::time::SystemTime;
|
||||
use std::fs::{self, File};
|
||||
@ -146,6 +146,7 @@ impl TestCase {
|
||||
}
|
||||
|
||||
|
||||
#[allow(clippy::uninit_vec)]
|
||||
fn init_execute_test(cputype: M68kType, state: &TestState) -> Result<(M68k, MemoryBlock<u32, Instant>), Error> {
|
||||
// Insert basic initialization
|
||||
let len = 0x100_0000;
|
||||
@ -274,13 +275,15 @@ fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> {
|
||||
Ok(()) => Ok(()),
|
||||
Err(err) => {
|
||||
if !args.quiet {
|
||||
let mut writer = String::new();
|
||||
if args.debug {
|
||||
case.dump();
|
||||
println!();
|
||||
//initial_cpu.dump_state();
|
||||
//cpu.dump_state();
|
||||
writeln!(writer).unwrap();
|
||||
initial_cpu.dump_state(&mut writer).unwrap();
|
||||
cpu.dump_state(&mut writer).unwrap();
|
||||
}
|
||||
println!("FAILED: {:?}", err);
|
||||
writeln!(writer, "FAILED: {:?}", err).unwrap();
|
||||
println!("{}", writer);
|
||||
}
|
||||
Err(err)
|
||||
},
|
||||
@ -311,11 +314,9 @@ fn test_json_file(path: PathBuf, args: &Args) -> (usize, usize, String) {
|
||||
}
|
||||
|
||||
// Only run the test if it's selected by the exceptions flag
|
||||
if case.is_extended_exception_case() && args.exceptions == Selection::ExcludeAddr {
|
||||
continue;
|
||||
} else if case.is_exception_case() && args.exceptions == Selection::Exclude {
|
||||
continue;
|
||||
} else if !case.is_exception_case() && args.exceptions == Selection::Only {
|
||||
if case.is_extended_exception_case() && args.exceptions == Selection::ExcludeAddr
|
||||
|| case.is_exception_case() && args.exceptions == Selection::Exclude
|
||||
|| !case.is_exception_case() && args.exceptions == Selection::Only {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -176,7 +176,7 @@ where
|
||||
if actual == expected {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::assertion(&format!("{:#X} != {:#X}, {}", actual, expected, message)))
|
||||
Err(Error::assertion(format!("{:#X} != {:#X}, {}", actual, expected, message)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -255,7 +255,7 @@ fn assert_state(cpu: &Z80, system: &System, io_bus: Rc<RefCell<Bus>>, expected:
|
||||
|
||||
let expected_im: InterruptMode = expected.im.into();
|
||||
if cpu.state.im != expected_im {
|
||||
return Err(Error::assertion(&format!("{:?} != {:?}, im", cpu.state.im, expected_im)));
|
||||
return Err(Error::assertion(format!("{:?} != {:?}, im", cpu.state.im, expected_im)));
|
||||
}
|
||||
assert_value(cpu.state.iff1 as u8, expected.iff1, "iff1")?;
|
||||
assert_value(cpu.state.iff2 as u8, expected.iff2, "iff2")?;
|
||||
@ -280,13 +280,13 @@ fn assert_state(cpu: &Z80, system: &System, io_bus: Rc<RefCell<Bus>>, expected:
|
||||
}
|
||||
|
||||
fn step_cpu_and_assert(cpu: &mut Z80, system: &System, io_bus: Rc<RefCell<Bus>>, case: &TestCase, args: &Args) -> Result<(), Error> {
|
||||
let clock_elapsed = cpu.step(&system)?;
|
||||
let clock_elapsed = cpu.step(system)?;
|
||||
|
||||
assert_state(&cpu, &system, io_bus, &case.final_state, args.check_extra_flags, &case.ports)?;
|
||||
assert_state(cpu, system, io_bus, &case.final_state, args.check_extra_flags, &case.ports)?;
|
||||
if args.check_timings {
|
||||
let cycles = clock_elapsed / cpu.frequency.period_duration();
|
||||
if cycles != case.cycles.len() as Address {
|
||||
return Err(Error::assertion(&format!("expected instruction to take {} cycles, but took {}", case.cycles.len(), cycles)));
|
||||
return Err(Error::assertion(format!("expected instruction to take {} cycles, but took {}", case.cycles.len(), cycles)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -305,7 +305,7 @@ fn run_test(case: &TestCase, args: &Args) -> Result<(), Error> {
|
||||
if !args.quiet {
|
||||
if args.debug {
|
||||
case.dump();
|
||||
println!("");
|
||||
println!();
|
||||
initial_cpu.dump_state(system.clock);
|
||||
cpu.dump_state(system.clock);
|
||||
}
|
||||
@ -425,7 +425,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);
|
||||
}
|
||||
@ -439,7 +439,7 @@ fn is_undocumented_instruction(name: &str) -> bool {
|
||||
|
||||
match (opcodes[0], opcodes[1]) {
|
||||
(0xCB, op) => {
|
||||
op >= 0x30 && op <= 0x37
|
||||
(0x30..=0x37).contains(&op)
|
||||
},
|
||||
(0xDD, 0xCB) |
|
||||
(0xFD, 0xCB) => {
|
||||
@ -449,9 +449,9 @@ fn is_undocumented_instruction(name: &str) -> bool {
|
||||
(0xFD, op) => {
|
||||
let upper = op & 0xF0;
|
||||
let lower = op & 0x0F;
|
||||
!(lower == 0x06 && upper >= 0x30 && upper <= 0xB0 && upper != 0x70) &&
|
||||
!(lower == 0x0E && upper >= 0x40 && upper <= 0xB0) &&
|
||||
!(op >= 0x70 && op <= 0x77 && op != 0x76) &&
|
||||
!(lower == 0x06 && (0x30..=0xB0).contains(&upper) && upper != 0x70) &&
|
||||
!(lower == 0x0E && (0x40..=0xB0).contains(&upper)) &&
|
||||
!((0x70..=0x77).contains(&op) && op != 0x76) &&
|
||||
!(op >= 0x21 && op <= 0x23 && op >= 0x34 && op <= 0x36 && op >= 0x29 && op <= 0x2B) &&
|
||||
!(lower == 0x09 && upper <= 0x30) &&
|
||||
!(op == 0xE1 || op == 0xE3 || op == 0xE5 || op == 0xE9 || op == 0xF9)
|
||||
|
31
todo.txt
31
todo.txt
@ -1,34 +1,18 @@
|
||||
|
||||
* the next step is to factor all of moa_core into the moa.rs file, with BusPort being the last big piece
|
||||
The functionality of BusPort should be integrated into memory.rs, to break up operations based on the cpu type
|
||||
and then you won't need a value to hold on to port in a special bundle type. It can be borrowed in the step function from system.bus
|
||||
|
||||
* I want to push System, and BusPort into only the step function
|
||||
* first I need to make Decoder take &mut Addressable, and still function like it does
|
||||
* next I need to make Executor only access through a &mut Addressable
|
||||
|
||||
* move the BusPort breakup code to m68k
|
||||
* implement BusAccess for BusPort
|
||||
* fix dump_state everywhere, which now requires a writer. Is there an easier way? Maybe serde? Is there a way that doesn't require std
|
||||
* can you clean it up more?
|
||||
* implement the inspect and debug traits
|
||||
* move the interrupt controller logic to the step() function only, and have a customish interrupt interface into the sim
|
||||
* move the impls for Step, Transmutable, etc into a moa.rs file or something
|
||||
* the remaining code should really use Addressable, and then we can swap it for BusAccess
|
||||
|
||||
* could you use the m68k cpu status enum for interrupts, and start handling the interrupt in the next step? but that will affect tests and behaviour if it takes two steps
|
||||
to get to the same point...
|
||||
|
||||
* the idea would be, instead of argument drilling, you create an object that is short lived, that lasts one instruction, or possibly even parts of one instruction, and
|
||||
it has some references instead of "moving" data (or if you move, you move and move out without cloning), such that you can bundle everything up, call a method on the
|
||||
bundle, with the execution context and state all part of or reference by the bundle, all instructions would be implemented on the bundle and not the state alone, and
|
||||
after the instruction, or when transitioning from one phase to the next, you'd decompose the bundle back into its parts, and return before being called again to
|
||||
repeat the process with the next instruction
|
||||
|
||||
* do the Z80? Should that be another PR?
|
||||
* fix the tests
|
||||
* fix all the clippy issues
|
||||
|
||||
* it doesn't work when using debug due to math checks, so fix them
|
||||
|
||||
|
||||
|
||||
* change all the inspection and debugging things to return a struct which can then be printed by the frontend
|
||||
|
||||
|
||||
* there are many issues with the coprocessor address space, and the VDP
|
||||
* I mapped the sn sound chip into 0xC00010, in the middle of the VDP's address space, and didn't get a runtime error!!! needs fixing
|
||||
* there should be a better way of aliasing addresses. Can you make the actual Z80 bus get mapped into 0xA00000?
|
||||
@ -57,7 +41,6 @@
|
||||
* add rust runtime checks for math to look for overflow errors
|
||||
* fix the watchers in the Bus, maybe make them manual
|
||||
* make it possible to compile without audio support (minifb frontend requires it atm)
|
||||
* does Z80 need a customized Z80BusPort like the 68k?
|
||||
* can you make it so you don't need borrow_mut() so much?
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user