Fixed tests and clippy warnings
This commit is contained in:
parent
c20d7afe6e
commit
d0037c8125
|
@ -521,7 +521,6 @@ dependencies = [
|
|||
"emulator-hal-memory",
|
||||
"femtos",
|
||||
"flate2",
|
||||
"moa-core",
|
||||
"moa-m68k",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
|
|
|
@ -171,7 +171,7 @@ pub trait Debuggable {
|
|||
fn remove_breakpoint(&mut self, addr: Address);
|
||||
|
||||
fn print_current_step(&mut self, system: &System) -> Result<(), Error>;
|
||||
fn print_disassembly(&mut self, addr: Address, count: usize);
|
||||
fn print_disassembly(&mut self, system: &System, addr: Address, count: usize);
|
||||
fn run_command(&mut self, system: &System, args: &[&str]) -> Result<bool, Error>;
|
||||
}
|
||||
|
||||
|
|
|
@ -92,13 +92,14 @@ impl M68kDecoder {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn dump_disassembly<Bus>(&mut self, bus: &mut Bus, memory: &mut M68kBusPort, start: u32, length: u32)
|
||||
pub fn dump_disassembly<Bus>(&mut self, bus: &mut Bus, start: u32, length: u32)
|
||||
where
|
||||
Bus: BusAccess<M68kAddress, Instant>,
|
||||
{
|
||||
let mut memory = M68kBusPort::default();
|
||||
let mut next = start;
|
||||
while next < (start + length) {
|
||||
match self.decode_at(bus, memory, self.is_supervisor, next) {
|
||||
match self.decode_at(bus, &mut memory, self.is_supervisor, next) {
|
||||
Ok(()) => {
|
||||
self.dump_decoded(memory.current_clock, bus);
|
||||
next = self.end;
|
||||
|
|
|
@ -142,7 +142,7 @@ impl M68kBusPort {
|
|||
Self {
|
||||
request: Default::default(),
|
||||
data_bytewidth: info.data_width as usize / 8,
|
||||
address_mask: 1_u32.wrapping_shl(info.address_width as u32).wrapping_sub(1),
|
||||
address_mask: 1_u32.checked_shl(info.address_width as u32).unwrap_or(0).wrapping_sub(1),
|
||||
cycle_start_clock: clock,
|
||||
current_clock: clock,
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ impl Steppable for M68k {
|
|||
let mut adapter: bus::BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error> = bus::BusAdapter::new(
|
||||
&mut *bus,
|
||||
|addr| addr as u64,
|
||||
|err| err.try_into().unwrap(),
|
||||
|err| err,
|
||||
);
|
||||
|
||||
let mut executor = cycle.begin(self, &mut adapter);
|
||||
|
@ -24,7 +24,7 @@ impl Steppable for M68k {
|
|||
executor.step()?;
|
||||
|
||||
let interrupt = system.get_interrupt_controller().check();
|
||||
if let (priority, Some(ack)) = executor.check_pending_interrupts(interrupt)? {
|
||||
if let (priority, Some(_)) = executor.check_pending_interrupts(interrupt)? {
|
||||
log::debug!("interrupt: {:?} @ {} ns", priority, system.clock.as_duration().as_nanos());
|
||||
system.get_interrupt_controller().acknowledge(priority as u8)?;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ impl Steppable for M68k {
|
|||
|
||||
fn on_error(&mut self, _system: &System) {
|
||||
let mut output = String::with_capacity(256);
|
||||
self.dump_state(&mut output);
|
||||
let _ = self.dump_state(&mut output);
|
||||
println!("{}", output);
|
||||
}
|
||||
}
|
||||
|
@ -60,8 +60,8 @@ impl<BusError> From<Error> for M68kError<BusError> {
|
|||
fn from(err: Error) -> Self {
|
||||
match err {
|
||||
Error::Processor(ex) => M68kError::Interrupt(ex as u8),
|
||||
Error::Breakpoint(msg) => M68kError::Breakpoint,
|
||||
Error::Other(msg) | Error::Assertion(msg) | Error::Emulator(_, msg) => M68kError::Other(format!("{}", msg)),
|
||||
Error::Breakpoint(_) => M68kError::Breakpoint,
|
||||
Error::Other(msg) | Error::Assertion(msg) | Error::Emulator(_, msg) => M68kError::Other(msg.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -100,9 +100,17 @@ impl Debuggable for M68k {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn print_disassembly(&mut self, addr: Address, count: usize) {
|
||||
fn print_disassembly(&mut self, system: &System, 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);
|
||||
|
||||
let mut bus = system.bus.borrow_mut();
|
||||
let mut adapter: bus::BusAdapter<u32, u64, Instant, &mut dyn Addressable, Error> = bus::BusAdapter::new(
|
||||
&mut *bus,
|
||||
|addr| addr as u64,
|
||||
|err| err,
|
||||
);
|
||||
|
||||
decoder.dump_disassembly(&mut adapter, addr as u32, count as u32);
|
||||
}
|
||||
|
||||
fn run_command(&mut self, system: &System, args: &[&str]) -> Result<bool, Error> {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/(
|
||||
|
||||
#[cfg(test)]
|
||||
mod decode_unit_tests {
|
||||
use femtos::Instant;
|
||||
|
@ -12,7 +12,10 @@ mod decode_unit_tests {
|
|||
|
||||
const INIT_ADDR: u32 = 0x00000000;
|
||||
|
||||
fn init_decode_test<'a>(cputype: M68kType) -> InstructionDecoding<'a, MemoryBlock<u32, Instant>> {
|
||||
fn run_decode_test<F>(cputype: M68kType, mut test_func: F)
|
||||
where
|
||||
F: FnMut(&mut InstructionDecoding<'_, MemoryBlock<u32, Instant>>),
|
||||
{
|
||||
let mut memory = MemoryBlock::from(vec![0; 0x0000100]);
|
||||
let mut decoder = M68kDecoder::new(cputype, true, 0);
|
||||
let mut decoding = InstructionDecoding {
|
||||
|
@ -20,7 +23,8 @@ mod decode_unit_tests {
|
|||
memory: &mut M68kBusPort::default(),
|
||||
decoder: &mut decoder,
|
||||
};
|
||||
decoding
|
||||
|
||||
test_func(&mut decoding);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -29,224 +33,224 @@ mod decode_unit_tests {
|
|||
|
||||
#[test]
|
||||
fn target_direct_d() {
|
||||
let mut decoder = init_decode_test(M68kType::MC68010);
|
||||
run_decode_test(M68kType::MC68010, |decoder| {
|
||||
let size = Size::Word;
|
||||
|
||||
let size = Size::Word;
|
||||
|
||||
let target = decoder.get_mode_as_target(0b000, 0b001, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::DirectDReg(1));
|
||||
let target = decoder.get_mode_as_target(0b000, 0b001, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::DirectDReg(1));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_direct_a() {
|
||||
let mut decoder = init_decode_test(M68kType::MC68010);
|
||||
run_decode_test(M68kType::MC68010, |decoder| {
|
||||
let size = Size::Word;
|
||||
|
||||
let size = Size::Word;
|
||||
|
||||
let target = decoder.get_mode_as_target(0b001, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::DirectAReg(2));
|
||||
let target = decoder.get_mode_as_target(0b001, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::DirectAReg(2));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_a() {
|
||||
let mut decoder = init_decode_test(M68kType::MC68010);
|
||||
run_decode_test(M68kType::MC68010, |decoder| {
|
||||
let size = Size::Long;
|
||||
let expected = 0x12345678;
|
||||
|
||||
let size = Size::Long;
|
||||
let expected = 0x12345678;
|
||||
decoder.bus.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));
|
||||
let target = decoder.get_mode_as_target(0b010, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectAReg(2));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_a_inc() {
|
||||
let mut decoder = init_decode_test(M68kType::MC68010);
|
||||
run_decode_test(M68kType::MC68010, |decoder| {
|
||||
let size = Size::Long;
|
||||
let expected = 0x12345678;
|
||||
|
||||
let size = Size::Long;
|
||||
let expected = 0x12345678;
|
||||
decoder.bus.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));
|
||||
let target = decoder.get_mode_as_target(0b011, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectARegInc(2));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_a_dec() {
|
||||
let mut decoder = init_decode_test(M68kType::MC68010);
|
||||
run_decode_test(M68kType::MC68010, |decoder| {
|
||||
let size = Size::Long;
|
||||
let expected = 0x12345678;
|
||||
|
||||
let size = Size::Long;
|
||||
let expected = 0x12345678;
|
||||
decoder.bus.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));
|
||||
let target = decoder.get_mode_as_target(0b100, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectARegDec(2));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_a_reg_offset() {
|
||||
let mut decoder = init_decode_test(M68kType::MC68010);
|
||||
run_decode_test(M68kType::MC68010, |decoder| {
|
||||
let size = Size::Long;
|
||||
let offset = -8;
|
||||
|
||||
let size = Size::Long;
|
||||
let offset = -8;
|
||||
decoder.bus.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));
|
||||
let target = decoder.get_mode_as_target(0b101, 0b100, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(4), None, offset));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_a_reg_brief_extension_word() {
|
||||
let mut decoder = init_decode_test(M68kType::MC68010);
|
||||
run_decode_test(M68kType::MC68010, |decoder| {
|
||||
let size = Size::Long;
|
||||
let offset = -8;
|
||||
let brief_extension = 0x3800 | (((offset as i8) as u8) as u16);
|
||||
|
||||
let size = Size::Long;
|
||||
let offset = -8;
|
||||
let brief_extension = 0x3800 | (((offset as i8) as u8) as u16);
|
||||
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();
|
||||
|
||||
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));
|
||||
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));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_a_reg_full_extension_word() {
|
||||
let mut decoder = init_decode_test(M68kType::MC68020);
|
||||
run_decode_test(M68kType::MC68020, |decoder| {
|
||||
let size = Size::Word;
|
||||
let offset = -1843235 as i32;
|
||||
let brief_extension = 0xF330;
|
||||
|
||||
let size = Size::Word;
|
||||
let offset = -1843235 as i32;
|
||||
let brief_extension = 0xF330;
|
||||
decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
|
||||
decoder.bus.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));
|
||||
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));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_a_reg_full_extension_word_no_base() {
|
||||
let mut decoder = init_decode_test(M68kType::MC68020);
|
||||
run_decode_test(M68kType::MC68020, |decoder| {
|
||||
let size = Size::Word;
|
||||
let offset = -1843235 as i32;
|
||||
let brief_extension = 0xF3B0;
|
||||
|
||||
let size = Size::Word;
|
||||
let offset = -1843235 as i32;
|
||||
let brief_extension = 0xF3B0;
|
||||
decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
|
||||
decoder.bus.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));
|
||||
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));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_a_reg_full_extension_word_no_index() {
|
||||
let mut decoder = init_decode_test(M68kType::MC68020);
|
||||
run_decode_test(M68kType::MC68020, |decoder| {
|
||||
let size = Size::Word;
|
||||
let offset = -1843235 as i32;
|
||||
let brief_extension = 0xF370;
|
||||
|
||||
let size = Size::Word;
|
||||
let offset = -1843235 as i32;
|
||||
let brief_extension = 0xF370;
|
||||
decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
|
||||
decoder.bus.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));
|
||||
let target = decoder.get_mode_as_target(0b110, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::AReg(2), None, offset));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_pc_offset() {
|
||||
let mut decoder = init_decode_test(M68kType::MC68010);
|
||||
run_decode_test(M68kType::MC68010, |decoder| {
|
||||
let size = Size::Long;
|
||||
let offset = -8;
|
||||
|
||||
let size = Size::Long;
|
||||
let offset = -8;
|
||||
decoder.bus.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));
|
||||
let target = decoder.get_mode_as_target(0b111, 0b010, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectRegOffset(BaseRegister::PC, None, offset));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_pc_brief_extension_word() {
|
||||
let mut decoder = init_decode_test(M68kType::MC68010);
|
||||
run_decode_test(M68kType::MC68010, |decoder| {
|
||||
let size = Size::Word;
|
||||
let offset = -8;
|
||||
let brief_extension = 0x3000 | (((offset as i8) as u8) as u16);
|
||||
|
||||
let size = Size::Word;
|
||||
let offset = -8;
|
||||
let brief_extension = 0x3000 | (((offset as i8) as u8) as u16);
|
||||
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();
|
||||
|
||||
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));
|
||||
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));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_pc_full_extension_word() {
|
||||
let mut decoder = init_decode_test(M68kType::MC68020);
|
||||
run_decode_test(M68kType::MC68020, |decoder| {
|
||||
let size = Size::Word;
|
||||
let offset = -1843235 as i32;
|
||||
let brief_extension = 0xF330;
|
||||
|
||||
let size = Size::Word;
|
||||
let offset = -1843235 as i32;
|
||||
let brief_extension = 0xF330;
|
||||
decoder.bus.write_beu16(Instant::START, INIT_ADDR, brief_extension).unwrap();
|
||||
decoder.bus.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));
|
||||
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));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn target_indirect_immediate_word() {
|
||||
let mut decoder = init_decode_test(M68kType::MC68010);
|
||||
run_decode_test(M68kType::MC68010, |decoder| {
|
||||
let size = Size::Word;
|
||||
let expected = 0x1234;
|
||||
|
||||
let size = Size::Word;
|
||||
let expected = 0x1234;
|
||||
decoder.bus.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));
|
||||
let target = decoder.get_mode_as_target(0b111, 0b000, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectMemory(expected, Size::Word));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_indirect_immediate_long() {
|
||||
let mut decoder = init_decode_test(M68kType::MC68010);
|
||||
run_decode_test(M68kType::MC68010, |decoder| {
|
||||
let size = Size::Word;
|
||||
let expected = 0x12345678;
|
||||
|
||||
let size = Size::Word;
|
||||
let expected = 0x12345678;
|
||||
decoder.bus.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));
|
||||
let target = decoder.get_mode_as_target(0b111, 0b001, Some(size)).unwrap();
|
||||
assert_eq!(target, Target::IndirectMemory(expected, Size::Long));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn target_immediate() {
|
||||
let mut decoder = init_decode_test(M68kType::MC68010);
|
||||
run_decode_test(M68kType::MC68010, |decoder| {
|
||||
let size = Size::Word;
|
||||
let expected = 0x1234;
|
||||
|
||||
let size = Size::Word;
|
||||
let expected = 0x1234;
|
||||
decoder.bus.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));
|
||||
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 emulator_hal::bus::BusAccess;
|
||||
use emulator_hal::step::Step;
|
||||
use emulator_hal_memory::MemoryBlock;
|
||||
|
||||
|
@ -265,13 +269,14 @@ mod execute_unit_tests {
|
|||
// Insert basic initialization
|
||||
let len = 0x10_0000;
|
||||
let mut data = Vec::with_capacity(len);
|
||||
unsafe { data.set_len(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(Instant::START, &mut memory).unwrap();
|
||||
let mut cycle = M68kCycle::new(&mut cpu, Instant::START);
|
||||
let cycle = M68kCycle::new(&mut cpu, Instant::START);
|
||||
|
||||
let mut executor = cycle.begin(&mut cpu, &mut memory);
|
||||
executor.cycle.decoder.init(true, executor.state.pc);
|
||||
|
|
|
@ -17,6 +17,7 @@ struct TestCase {
|
|||
ins: Option<Instruction>,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
const DECODE_TESTS: &'static [TestCase] = &[
|
||||
// MC68000
|
||||
TestCase { cpu: M68kType::MC68000, data: &[0x4e71], ins: Some(Instruction::NOP) },
|
||||
|
@ -66,21 +67,16 @@ const DECODE_TESTS: &'static [TestCase] = &[
|
|||
|
||||
fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, MemoryBlock<u32, Instant>) {
|
||||
// Insert basic initialization
|
||||
let len = 0x10_0000;
|
||||
let len = 0x2000;
|
||||
let mut data = Vec::with_capacity(len);
|
||||
unsafe { data.set_len(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));
|
||||
//cpu.reset_cpu().unwrap();
|
||||
//assert_eq!(cpu.state.pc, INIT_ADDR);
|
||||
//assert_eq!(cpu.state.ssp, INIT_STACK);
|
||||
|
||||
let cpu = M68k::from_type(cputype, Frequency::from_mhz(10));
|
||||
let cycle = M68kCycle::new(&cpu, Instant::START);
|
||||
//assert_eq!(cycle.decoder.start, INIT_ADDR);
|
||||
//assert_eq!(cycle.decoder.instruction, Instruction::NOP);
|
||||
(cpu, cycle, memory)
|
||||
}
|
||||
|
||||
|
@ -100,12 +96,16 @@ fn run_decode_test(case: &TestCase) {
|
|||
Some(ins) => {
|
||||
let mut executor = cycle.begin(&mut cpu, &mut memory);
|
||||
executor.reset_cpu().unwrap();
|
||||
assert_eq!(executor.state.pc, INIT_ADDR);
|
||||
assert_eq!(executor.state.ssp, INIT_STACK);
|
||||
executor.decode_next().unwrap();
|
||||
assert_eq!(executor.cycle.decoder.instruction, ins.clone());
|
||||
},
|
||||
None => {
|
||||
let mut executor = cycle.begin(&mut cpu, &mut memory);
|
||||
executor.reset_cpu().unwrap();
|
||||
assert_eq!(executor.state.pc, INIT_ADDR);
|
||||
assert_eq!(executor.state.ssp, INIT_STACK);
|
||||
let next = executor.decode_next();
|
||||
println!("{:?}", executor.cycle.decoder.instruction);
|
||||
assert!(next.is_err());
|
||||
|
@ -122,6 +122,7 @@ pub fn run_decode_tests() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
pub fn run_assembler_tests() {
|
||||
let mut tests = 0;
|
||||
let mut errors = 0;
|
||||
|
|
|
@ -44,6 +44,7 @@ where
|
|||
// Insert basic initialization
|
||||
let len = 0x10_0000;
|
||||
let mut data = Vec::with_capacity(len);
|
||||
unsafe { data.set_len(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();
|
||||
|
@ -75,11 +76,9 @@ fn build_state(state: &TestState) -> M68kState {
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
for i in 0..data.len() {
|
||||
bus.write_beu16(Instant::START, (i << 1) as u32, data[i]).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn run_test(case: &TestCase) {
|
||||
|
@ -111,6 +110,7 @@ pub fn run_execute_tests() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
pub fn run_assembler_tests() {
|
||||
use moa_m68k::assembler::M68kAssembler;
|
||||
|
||||
|
@ -152,6 +152,7 @@ fn format_hex(data: &[u16]) -> String {
|
|||
.join(", ")
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
const TEST_CASES: &'static [TestCase] = &[
|
||||
TestCase {
|
||||
name: "nop",
|
||||
|
@ -218,7 +219,7 @@ const TEST_CASES: &'static [TestCase] = &[
|
|||
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x000000FE, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x270A, mem: 0x00000000 },
|
||||
},
|
||||
TestCase {
|
||||
name: "addx with extend",
|
||||
name: "addx with extend; zero flag not set",
|
||||
ins: Instruction::ADDX(Target::DirectDReg(1), Target::DirectDReg(0), Size::Byte),
|
||||
data: &[ 0xD101 ],
|
||||
cputype: M68kType::MC68010,
|
||||
|
@ -226,11 +227,27 @@ const TEST_CASES: &'static [TestCase] = &[
|
|||
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x000000FF, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x270A, mem: 0x00000000 },
|
||||
},
|
||||
TestCase {
|
||||
name: "addx with extend and carry",
|
||||
name: "addx with extend; zero flag set",
|
||||
ins: Instruction::ADDX(Target::DirectDReg(1), Target::DirectDReg(0), Size::Byte),
|
||||
data: &[ 0xD101 ],
|
||||
cputype: M68kType::MC68010,
|
||||
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x0000007F, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x2714, mem: 0x00000000 },
|
||||
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x000000FF, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x270A, mem: 0x00000000 },
|
||||
},
|
||||
TestCase {
|
||||
name: "addx with extend and carry; zero flag not set",
|
||||
ins: Instruction::ADDX(Target::DirectDReg(1), Target::DirectDReg(0), Size::Byte),
|
||||
data: &[ 0xD101 ],
|
||||
cputype: M68kType::MC68010,
|
||||
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000080, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x2710, mem: 0x00000000 },
|
||||
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x2711, mem: 0x00000000 },
|
||||
},
|
||||
TestCase {
|
||||
name: "addx with extend and carry; zero flag set",
|
||||
ins: Instruction::ADDX(Target::DirectDReg(1), Target::DirectDReg(0), Size::Byte),
|
||||
data: &[ 0xD101 ],
|
||||
cputype: M68kType::MC68010,
|
||||
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000080, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x2714, mem: 0x00000000 },
|
||||
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x2715, mem: 0x00000000 },
|
||||
},
|
||||
TestCase {
|
||||
|
@ -239,7 +256,15 @@ const TEST_CASES: &'static [TestCase] = &[
|
|||
data: &[ 0x027C, 0xF8FF ],
|
||||
cputype: M68kType::MC68010,
|
||||
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0xA7AA, mem: 0x00000000 },
|
||||
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0xA0AA, mem: 0x00000000 },
|
||||
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0xA00A, mem: 0x00000000 },
|
||||
},
|
||||
TestCase {
|
||||
name: "andi with sr 2",
|
||||
ins: Instruction::ANDtoSR(0xF8FF),
|
||||
data: &[ 0x027C, 0xF8FF ],
|
||||
cputype: M68kType::MC68010,
|
||||
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0xA7FA, mem: 0x00000000 },
|
||||
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0xA01A, mem: 0x00000000 },
|
||||
},
|
||||
TestCase {
|
||||
name: "asl",
|
||||
|
@ -560,13 +585,14 @@ const TEST_CASES: &'static [TestCase] = &[
|
|||
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0xFF55FFAA },
|
||||
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x000055AA, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0xFF55FFAA },
|
||||
},
|
||||
// TODO not sure if these cases are correct
|
||||
TestCase {
|
||||
name: "movep long from even memory upper",
|
||||
ins: Instruction::MOVEP(0, 0, 0, Size::Long, Direction::FromTarget),
|
||||
data: &[ 0x0148, 0x0000 ],
|
||||
cputype: M68kType::MC68010,
|
||||
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0xAAFFBBFF },
|
||||
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0xAABB0000, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0xAAFFBBFF },
|
||||
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0xAABBCCDD, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0xAAFFBBFF },
|
||||
},
|
||||
TestCase {
|
||||
name: "movep long from even memory lower",
|
||||
|
@ -603,7 +629,7 @@ const TEST_CASES: &'static [TestCase] = &[
|
|||
data: &[ 0x007C, 0x00AA ],
|
||||
cputype: M68kType::MC68010,
|
||||
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0xA755, mem: 0x00000000 },
|
||||
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0xA7FF, mem: 0x00000000 },
|
||||
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0xA71F, mem: 0x00000000 },
|
||||
},
|
||||
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, MemoryBlock<u32, Ins
|
|||
// Insert basic initialization
|
||||
let len = 0x10_0000;
|
||||
let mut data = Vec::with_capacity(len);
|
||||
unsafe { data.set_len(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();
|
||||
|
@ -24,10 +25,6 @@ fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, MemoryBlock<u32, Ins
|
|||
// Initialize the CPU and make sure it's in the expected state
|
||||
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, memory)
|
||||
}
|
||||
|
||||
|
@ -46,6 +43,10 @@ fn run_timing_test(case: &TimingCase) -> Result<(), String> {
|
|||
let mut executor = cycle.begin(&mut cpu, &mut memory);
|
||||
let mut timing = M68kInstructionTiming::new(case.cpu, 16);
|
||||
|
||||
executor.reset_cpu().unwrap();
|
||||
assert_eq!(executor.state.pc, INIT_ADDR);
|
||||
assert_eq!(executor.state.ssp, INIT_STACK);
|
||||
|
||||
executor.decode_next().unwrap();
|
||||
assert_eq!(executor.cycle.decoder.instruction, case.ins.clone());
|
||||
|
||||
|
@ -67,15 +68,15 @@ fn run_timing_test(case: &TimingCase) -> Result<(), String> {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
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 },
|
||||
//}
|
||||
print!("Testing for {:?}...", case.ins);
|
||||
match run_timing_test(case) {
|
||||
Ok(()) => println!("ok"),
|
||||
Err(err) => { println!("{:?}", err); errors += 1 },
|
||||
}
|
||||
|
||||
if let Err(_) = run_timing_test(case) {
|
||||
errors += 1;
|
||||
|
@ -94,6 +95,7 @@ pub struct TimingCase {
|
|||
pub ins: Instruction,
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub const TIMING_TESTS: &'static [TimingCase] = &[
|
||||
TimingCase { cpu: M68kType::MC68000, data: &[0xA000], timing: ( 4, 4, 4), ins: Instruction::UnimplementedA(0xA000) },
|
||||
TimingCase { cpu: M68kType::MC68000, data: &[0xF000], timing: ( 4, 4, 4), ins: Instruction::UnimplementedF(0xF000) },
|
||||
|
|
|
@ -28,19 +28,14 @@ fn init_decode_test(cputype: M68kType) -> (M68k, M68kCycle, MemoryBlock<u32, Ins
|
|||
// Insert basic initialization
|
||||
let len = 0x10_0000;
|
||||
let mut data = Vec::with_capacity(len);
|
||||
unsafe { data.set_len(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));
|
||||
//cpu.reset_cpu().unwrap();
|
||||
assert_eq!(cpu.state.pc, INIT_ADDR);
|
||||
assert_eq!(cpu.state.ssp, INIT_STACK);
|
||||
|
||||
let cycle = M68kCycle::new(&cpu, Instant::START);
|
||||
assert_eq!(cycle.decoder.start, INIT_ADDR);
|
||||
assert_eq!(cycle.decoder.instruction, Instruction::NOP);
|
||||
(cpu, cycle, memory)
|
||||
}
|
||||
|
||||
|
@ -59,6 +54,10 @@ fn run_timing_test(case: &TimingCase) -> Result<(), String> {
|
|||
let mut executor = cycle.begin(&mut cpu, &mut memory);
|
||||
let mut timing = M68kInstructionTiming::new(case.cpu, 16);
|
||||
|
||||
executor.reset_cpu().unwrap();
|
||||
assert_eq!(executor.state.pc, INIT_ADDR);
|
||||
assert_eq!(executor.state.ssp, INIT_STACK);
|
||||
|
||||
executor.decode_next().unwrap();
|
||||
assert_eq!(executor.cycle.decoder.instruction, case.ins.clone());
|
||||
|
||||
|
@ -83,12 +82,11 @@ fn run_timing_test(case: &TimingCase) -> Result<(), String> {
|
|||
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 },
|
||||
//}
|
||||
print!("Testing for {:?}...", case.ins);
|
||||
match run_timing_test(case) {
|
||||
Ok(()) => println!("ok"),
|
||||
Err(err) => { println!("{:?}", err); errors += 1 },
|
||||
}
|
||||
|
||||
if let Err(_) = run_timing_test(case) {
|
||||
errors += 1;
|
||||
|
|
|
@ -30,7 +30,7 @@ impl Debuggable for Z80 {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn print_disassembly(&mut self, addr: Address, count: usize) {
|
||||
fn print_disassembly(&mut self, _system: &System, addr: Address, count: usize) {
|
||||
let mut decoder = Z80Decoder::default();
|
||||
decoder.dump_disassembly(&mut self.port, addr as u16, count as u16);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
use core::fmt::Write;
|
||||
use femtos::Instant;
|
||||
|
||||
use moa_core::{Address, Addressable};
|
||||
|
@ -6,11 +7,9 @@ use moa_core::{Address, Addressable};
|
|||
use crate::state::Z80Error;
|
||||
use crate::instructions::{Direction, Condition, Register, RegisterPair, IndexRegister, IndexRegisterHalf, SpecialRegister, InterruptMode, Target, LoadTarget, UndocumentedCopy, Instruction};
|
||||
|
||||
use emulator_hal::bus::{BusAccess};
|
||||
|
||||
struct Z80Bus;
|
||||
|
||||
type Z80Address = (bool, u16);
|
||||
//use emulator_hal::bus::BusAccess;
|
||||
//
|
||||
//type Z80Address = (bool, u16);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Z80Decoder {
|
||||
|
@ -554,10 +553,10 @@ impl Z80Decoder {
|
|||
}
|
||||
|
||||
pub fn format_instruction_bytes(&mut self, memory: &mut dyn Addressable) -> String {
|
||||
let ins_data: String =
|
||||
(0..self.end.saturating_sub(self.start)).map(|offset|
|
||||
format!("{:02x} ", memory.read_u8(self.clock, (self.start + offset) as Address).unwrap())
|
||||
).collect();
|
||||
let mut ins_data = String::new();
|
||||
for offset in 0..self.end.saturating_sub(self.start) {
|
||||
write!(ins_data, "{:02x} ", memory.read_u8(self.clock, (self.start + offset) as Address).unwrap()).unwrap()
|
||||
}
|
||||
ins_data
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,6 @@ use crate::state::{Z80, Z80Error, Status, Flags};
|
|||
use crate::timing::Z80InstructionCycles;
|
||||
|
||||
|
||||
const DEV_NAME: &str = "z80-cpu";
|
||||
|
||||
const FLAGS_NUMERIC: u8 = 0xC0;
|
||||
const FLAGS_ARITHMETIC: u8 = 0x17;
|
||||
const FLAGS_CARRY_HALF_CARRY: u8 = 0x11;
|
||||
|
@ -70,8 +68,8 @@ impl From<Error> for Z80Error {
|
|||
fn from(err: Error) -> Self {
|
||||
match err {
|
||||
Error::Processor(ex) => Z80Error::BusError(format!("processor error {}", ex)),
|
||||
Error::Breakpoint(msg) => Z80Error::Breakpoint,
|
||||
Error::Other(msg) | Error::Assertion(msg) | Error::Emulator(_, msg) => Z80Error::BusError(format!("{}", msg)),
|
||||
Error::Breakpoint(_) => Z80Error::Breakpoint,
|
||||
Error::Other(msg) | Error::Assertion(msg) | Error::Emulator(_, msg) => Z80Error::BusError(msg.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
use femtos::{Instant, Frequency};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
use cpal::{Stream, SampleRate, SampleFormat, StreamConfig, StreamInstant, OutputCallbackInfo, traits::{DeviceTrait, HostTrait, StreamTrait}};
|
||||
use cpal::{Stream, SampleRate, SampleFormat, StreamConfig, OutputCallbackInfo, traits::{DeviceTrait, HostTrait, StreamTrait}};
|
||||
|
||||
use crate::audio::{AudioOutput, SAMPLE_RATE};
|
||||
|
||||
|
@ -22,7 +22,7 @@ impl CpalAudioOutput {
|
|||
.with_sample_rate(SampleRate(SAMPLE_RATE as u32))
|
||||
.into();
|
||||
|
||||
let data_callback = move |data: &mut [f32], info: &OutputCallbackInfo| {
|
||||
let data_callback = move |data: &mut [f32], _info: &OutputCallbackInfo| {
|
||||
let mut index = 0;
|
||||
while index < data.len() {
|
||||
if let Some((clock, mut frame)) = output.receive() {
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::thread;
|
|||
use std::time::Duration;
|
||||
use femtos::Frequency;
|
||||
|
||||
use moa_core::{System, MemoryBlock, BusPort, Device};
|
||||
use moa_core::{System, MemoryBlock, Device};
|
||||
|
||||
use moa_m68k::{M68k, M68kType};
|
||||
use moa_peripherals_generic::AtaDevice;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
use clap::{Arg, ArgAction};
|
||||
use clap::Arg;
|
||||
|
||||
use moa_console::ConsoleFrontend;
|
||||
use moa_systems_computie::{build_computie, ComputieOptions};
|
||||
|
@ -18,9 +18,9 @@ fn main() {
|
|||
options.rom = filename.to_string();
|
||||
}
|
||||
|
||||
let mut frontend = ConsoleFrontend::default();
|
||||
let frontend = ConsoleFrontend;
|
||||
|
||||
let system = build_computie(&mut frontend, options).unwrap();
|
||||
let system = build_computie(&frontend, options).unwrap();
|
||||
frontend.start(matches, system);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ fn main() {
|
|||
.help("ROM file to load (must be flat binary)"))
|
||||
.get_matches();
|
||||
|
||||
let mut frontend = ConsoleFrontend::default();
|
||||
let mut frontend = ConsoleFrontend;
|
||||
|
||||
let mut options = SegaGenesisOptions::default();
|
||||
if let Some(filename) = matches.get_one::<String>("ROM") {
|
||||
|
|
|
@ -14,7 +14,7 @@ impl Host for ConsoleFrontend {
|
|||
|
||||
fn add_pty(&self) -> Result<Box<dyn Tty>, HostError<Self::Error>> {
|
||||
use moa_common::tty::SimplePty;
|
||||
Ok(Box::new(SimplePty::open().map_err(|err| HostError::TTYNotSupported)?)) //.map_err(|err| Error::new(format!("console: error opening pty: {:?}", err)))?))
|
||||
Ok(Box::new(SimplePty::open().map_err(|_| HostError::TTYNotSupported)?)) //.map_err(|err| Error::new(format!("console: error opening pty: {:?}", err)))?))
|
||||
}
|
||||
|
||||
fn add_video_source(&mut self, _receiver: FrameReceiver) -> Result<(), HostError<Self::Error>> {
|
||||
|
|
|
@ -154,7 +154,7 @@ impl Debugger {
|
|||
};
|
||||
|
||||
if let Some(device) = system.get_next_debuggable_device() {
|
||||
device.borrow_mut().as_debuggable().unwrap().print_disassembly(addr, count);
|
||||
device.borrow_mut().as_debuggable().unwrap().print_disassembly(system, addr, count);
|
||||
}
|
||||
},
|
||||
"c" | "continue" => {
|
||||
|
|
|
@ -725,13 +725,18 @@ pub struct Ym2612 {
|
|||
channels: Vec<Channel>,
|
||||
dac: Dac,
|
||||
|
||||
// TODO the timer hasn't been implemented yet
|
||||
#[allow(dead_code)]
|
||||
timer_a_enable: bool,
|
||||
timer_a: u16,
|
||||
#[allow(dead_code)]
|
||||
timer_a_current: u16,
|
||||
timer_a_overflow: bool,
|
||||
|
||||
#[allow(dead_code)]
|
||||
timer_b_enable: bool,
|
||||
timer_b: u8,
|
||||
#[allow(dead_code)]
|
||||
timer_b_current: u8,
|
||||
timer_b_overflow: bool,
|
||||
|
||||
|
@ -856,8 +861,8 @@ impl Ym2612 {
|
|||
0x28 => {
|
||||
let num = (data as usize) & 0x07;
|
||||
let ch = match num {
|
||||
0 | 1 | 2 => num,
|
||||
4 | 5 | 6 => num - 1,
|
||||
0..=2 => num,
|
||||
4..=6 => num - 1,
|
||||
_ => {
|
||||
log::warn!("{}: attempted key on/off to invalid channel {}", DEV_NAME, num);
|
||||
return;
|
||||
|
@ -1025,7 +1030,7 @@ impl Addressable for Ym2612 {
|
|||
|
||||
fn read(&mut self, _clock: Instant, addr: Address, data: &mut [u8]) -> Result<(), Error> {
|
||||
match addr {
|
||||
0 | 1 | 2 | 3 => {
|
||||
0..=3 => {
|
||||
// Read the status byte (busy/overflow)
|
||||
data[0] = ((self.timer_a_overflow as u8) << 1) | (self.timer_b_overflow as u8);
|
||||
}
|
||||
|
|
|
@ -818,7 +818,7 @@ impl Addressable for Ym7101 {
|
|||
0x00 | 0x02 => self.state.memory.read_data_port(addr, data)?,
|
||||
|
||||
// Read from Control Port
|
||||
0x04 | 0x05 | 0x06 | 0x07 => {
|
||||
0x04..=0x07 => {
|
||||
log::debug!("{}: read status byte {:x}", DEV_NAME, self.state.status);
|
||||
for item in data {
|
||||
*item = if (addr % 2) == 0 {
|
||||
|
|
|
@ -7,11 +7,8 @@ edition = "2021"
|
|||
femtos = "0.1"
|
||||
emulator-hal = { path = "../../emulator/libraries/emulator-hal/emulator-hal" }
|
||||
emulator-hal-memory = { path = "../../emulator/libraries/emulator-hal/emulator-hal-memory" }
|
||||
moa-m68k = { path = "../../emulator/cpus/m68k" }
|
||||
|
||||
moa-core = { path = "../../emulator/core" }
|
||||
moa-m68k = { path = "../../emulator/cpus/m68k", features = ["moa"] }
|
||||
|
||||
#thiserror = "1.0"
|
||||
serde = "1.0"
|
||||
serde_json = "1.0"
|
||||
serde_derive = "1.0"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Last run on 2024-03-15 at commit 59306bceff1a5964902118f33034086a349e2fd3
|
||||
Last run on 2024-03-16 at commit c20d7afe6e8005ab272602953154280f0e1aa944
|
||||
|
||||
ABCD.json.gz completed: 7993 passed, 72 FAILED
|
||||
ADD.b.json.gz completed, all passed!
|
||||
|
@ -11,3 +11,119 @@ 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: 8051 passed, 14 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: 966036, failed: 34024, total 97%
|
||||
completed in 0m 7s
|
||||
|
|
|
@ -449,10 +449,8 @@ fn is_undocumented_instruction(name: &str) -> bool {
|
|||
(0xFD, op) => {
|
||||
let upper = op & 0xF0;
|
||||
let lower = op & 0x0F;
|
||||
!(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 == 0x0E && (0x40..=0xB0).contains(&upper) || (0x70..=0x77).contains(&op) && op != 0x76 || op != 0x76 && (0x70..=0x77).contains(&op) || lower == 0x06 && (0x30..=0xB0).contains(&upper) && upper != 0x70) &&
|
||||
!((0x21..=0x23).contains(&op) || (0x34..=0x36).contains(&op) || (0x29..=0x2B).contains(&op)) &&
|
||||
!(lower == 0x09 && upper <= 0x30) &&
|
||||
!(op == 0xE1 || op == 0xE3 || op == 0xE5 || op == 0xE9 || op == 0xF9)
|
||||
},
|
||||
|
|
2
todo.txt
2
todo.txt
|
@ -1,5 +1,5 @@
|
|||
|
||||
* 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
|
||||
* fix dump_state everywhere, which now requires a writer. Is there an easier way? 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
|
||||
|
|
Loading…
Reference in New Issue