From 91825e1cb9b51d32edfbb9b622b49652871c1175 Mon Sep 17 00:00:00 2001 From: transistor Date: Mon, 11 Oct 2021 15:04:39 -0700 Subject: [PATCH] Added a bunch of unit tests --- src/cpus/m68k/debugger.rs | 7 + src/cpus/m68k/tests.rs | 529 ++++++++++++++++++++++++++++++-------- src/devices.rs | 14 +- src/error.rs | 1 - src/main.rs | 16 -- src/memory.rs | 1 + 6 files changed, 440 insertions(+), 128 deletions(-) diff --git a/src/cpus/m68k/debugger.rs b/src/cpus/m68k/debugger.rs index cb48e3a..e49afb4 100644 --- a/src/cpus/m68k/debugger.rs +++ b/src/cpus/m68k/debugger.rs @@ -4,6 +4,7 @@ use crate::system::System; use crate::memory::{Address, Addressable}; use super::state::M68k; +use super::decode::M68kDecoder; pub struct StackTracer { pub calls: Vec, @@ -47,10 +48,12 @@ impl M68kDebugger { } impl M68k { + #[allow(dead_code)] pub fn enable_tracing(&mut self) { self.debugger.use_tracing = true; } + #[allow(dead_code)] pub fn add_breakpoint(&mut self, addr: Address) { self.debugger.breakpoints.push(addr as u32); } @@ -119,6 +122,10 @@ impl M68k { println!(" {:08x}", system.get_bus().read_beu32(*addr as Address)?); } }, + "dis" | "disassemble" => { + let mut decoder = M68kDecoder::new(self.cputype, 0, 0); + decoder.dump_disassembly(system, self.state.pc, 0x1000); + }, "so" | "stepout" => { self.debugger.step_until_return = Some(self.debugger.stack_tracer.calls.len() - 1); return Ok(true); diff --git a/src/cpus/m68k/tests.rs b/src/cpus/m68k/tests.rs index f0a9420..ea7489e 100644 --- a/src/cpus/m68k/tests.rs +++ b/src/cpus/m68k/tests.rs @@ -1,67 +1,242 @@ -use crate::system::System; -use crate::devices::{Steppable, wrap_addressable}; -use crate::memory::{Address, Addressable, MemoryBlock}; - -use super::decode::Instruction; -use super::state::{M68k, M68kType}; - -const INIT_STACK: Address = 0x00002000; -const INIT_ADDR: Address = 0x00000010; - -fn init_test() -> (M68k, System) { - let mut system = System::new(); - - // Insert basic initialization - let data = vec![0; 0x00100000]; - let mem = MemoryBlock::new(data); - system.add_addressable_device(0x00000000, wrap_addressable(mem)).unwrap(); - system.get_bus().write_beu32(0, INIT_STACK as u32).unwrap(); - system.get_bus().write_beu32(4, INIT_ADDR as u32).unwrap(); - - let mut cpu = M68k::new(M68kType::MC68010); - cpu.step(&system).unwrap(); - assert_eq!(cpu.state.pc, INIT_ADDR as u32); - assert_eq!(cpu.state.msp, INIT_STACK as u32); - assert_eq!(cpu.decoder.instruction, Instruction::NOP); - (cpu, system) -} - #[cfg(test)] -mod tests { - use crate::devices::Steppable; - use crate::memory::{Address, Addressable}; +mod decode_tests { + use crate::system::System; + use crate::devices::{Steppable, AddressableDeviceBox, wrap_addressable}; + use crate::memory::{Address, Addressable, MemoryBlock}; - use super::{init_test, INIT_ADDR}; - use super::super::decode::{Instruction, Target, Size, Sign, ShiftDirection}; + use crate::cpus::m68k::{M68k, M68kType}; + use crate::cpus::m68k::decode::{Instruction, Target, Size, Sign, RegisterType, ShiftDirection}; + + const INIT_STACK: Address = 0x00002000; + const INIT_ADDR: Address = 0x00000010; + + fn init_decode_test() -> (M68k, System) { + let mut system = System::new(); + + // Insert basic initialization + let data = vec![0; 0x00100000]; + let mem = MemoryBlock::new(data); + system.add_addressable_device(0x00000000, wrap_addressable(mem)).unwrap(); + system.get_bus().write_beu32(0, INIT_STACK as u32).unwrap(); + system.get_bus().write_beu32(4, INIT_ADDR as u32).unwrap(); + + // Initialize the CPU and make sure it's in the expected state + let mut cpu = M68k::new(M68kType::MC68010); + cpu.init(&system).unwrap(); + assert_eq!(cpu.state.pc, INIT_ADDR as u32); + assert_eq!(cpu.state.msp, INIT_STACK as u32); + assert_eq!(cpu.decoder.instruction, Instruction::NOP); + (cpu, system) + } + + fn get_decode_memory(cpu: &mut M68k, system: &System) -> AddressableDeviceBox { + let (memory, relative_addr) = system.get_bus().get_device_at(INIT_ADDR, 12).unwrap(); + cpu.decoder.init((INIT_ADDR - relative_addr) as u32, INIT_ADDR as u32); + memory + } + + // + // Addressing Mode Target Tests + // + + #[test] + fn target_direct_d() { + let (mut cpu, system) = init_decode_test(); + + let size = Size::Word; + let expected = 0x1234; + + let memory = get_decode_memory(&mut cpu, &system); + let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b000, 0b001, Some(size)).unwrap(); + assert_eq!(target, Target::DirectDReg(1)); + } + + #[test] + fn target_direct_a() { + let (mut cpu, system) = init_decode_test(); + + let size = Size::Word; + let expected = 0x1234; + + let memory = get_decode_memory(&mut cpu, &system); + let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b001, 0b010, Some(size)).unwrap(); + assert_eq!(target, Target::DirectAReg(2)); + } + + #[test] + fn target_indirect_a() { + let (mut cpu, system) = init_decode_test(); + + let size = Size::Long; + let expected_addr = INIT_ADDR; + let expected = 0x12345678; + + system.get_bus().write_beu32(INIT_ADDR, expected).unwrap(); + + let memory = get_decode_memory(&mut cpu, &system); + let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b010, 0b010, Some(size)).unwrap(); + assert_eq!(target, Target::IndirectAReg(2)); + } + + #[test] + fn target_indirect_a_inc() { + let (mut cpu, system) = init_decode_test(); + + let size = Size::Long; + let expected_addr = INIT_ADDR; + let expected = 0x12345678; + + system.get_bus().write_beu32(INIT_ADDR, expected).unwrap(); + + let memory = get_decode_memory(&mut cpu, &system); + let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b011, 0b010, Some(size)).unwrap(); + assert_eq!(target, Target::IndirectARegInc(2)); + } + + #[test] + fn target_indirect_a_dec() { + let (mut cpu, system) = init_decode_test(); + + let size = Size::Long; + let expected_addr = INIT_ADDR + 4; + let expected = 0x12345678; + + system.get_bus().write_beu32(INIT_ADDR, expected).unwrap(); + + let memory = get_decode_memory(&mut cpu, &system); + let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b100, 0b010, Some(size)).unwrap(); + assert_eq!(target, Target::IndirectARegDec(2)); + } + + #[test] + fn target_indirect_a_reg_offset() { + let (mut cpu, system) = init_decode_test(); + + let size = Size::Long; + let offset = -8; + + system.get_bus().write_beu16(INIT_ADDR, (offset as i16) as u16).unwrap(); + + let memory = get_decode_memory(&mut cpu, &system); + let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b101, 0b100, Some(size)).unwrap(); + assert_eq!(target, Target::IndirectARegOffset(4, offset)); + } + + #[test] + fn target_indirect_a_reg_extension_word() { + let (mut cpu, system) = init_decode_test(); + + let size = Size::Long; + let offset = -8; + let brief_extension = 0x3800 | (((offset as i8) as u8) as u16); + + system.get_bus().write_beu16(INIT_ADDR, brief_extension).unwrap(); + system.get_bus().write_beu16(INIT_ADDR + 2, (offset as i16) as u16).unwrap(); + + let memory = get_decode_memory(&mut cpu, &system); + let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b110, 0b010, Some(size)).unwrap(); + assert_eq!(target, Target::IndirectARegXRegOffset(2, RegisterType::Data, 3, offset, size)); + } + + #[test] + fn target_indirect_immediate_word() { + let (mut cpu, system) = init_decode_test(); + + let size = Size::Word; + let expected = 0x1234; + + system.get_bus().write_beu16(INIT_ADDR, expected as u16).unwrap(); + + let memory = get_decode_memory(&mut cpu, &system); + let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b111, 0b000, Some(size)).unwrap(); + assert_eq!(target, Target::IndirectMemory(expected)); + } + + #[test] + fn target_indirect_immediate_long() { + let (mut cpu, system) = init_decode_test(); + + let size = Size::Word; + let expected = 0x12345678; + + system.get_bus().write_beu32(INIT_ADDR, expected).unwrap(); + + let memory = get_decode_memory(&mut cpu, &system); + let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b111, 0b001, Some(size)).unwrap(); + assert_eq!(target, Target::IndirectMemory(expected)); + } + + #[test] + fn target_indirect_pc_offset() { + let (mut cpu, system) = init_decode_test(); + + let size = Size::Long; + let offset = -8; + + system.get_bus().write_beu16(INIT_ADDR, (offset as i16) as u16).unwrap(); + + let memory = get_decode_memory(&mut cpu, &system); + let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b111, 0b010, Some(size)).unwrap(); + assert_eq!(target, Target::IndirectPCOffset(offset)); + } + + #[test] + fn target_indirect_pc_extension_word() { + let (mut cpu, system) = init_decode_test(); + + let size = Size::Word; + let offset = -8; + let brief_extension = 0x3000 | (((offset as i8) as u8) as u16); + + system.get_bus().write_beu16(INIT_ADDR, brief_extension).unwrap(); + system.get_bus().write_beu16(INIT_ADDR + 2, (offset as i16) as u16).unwrap(); + + let memory = get_decode_memory(&mut cpu, &system); + let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b111, 0b011, Some(size)).unwrap(); + assert_eq!(target, Target::IndirectPCXRegOffset(RegisterType::Data, 3, offset, size)); + } + + #[test] + fn target_immediate() { + let (mut cpu, system) = init_decode_test(); + + let size = Size::Word; + let expected = 0x1234; + + system.get_bus().write_beu16(INIT_ADDR, expected as u16).unwrap(); + + let memory = get_decode_memory(&mut cpu, &system); + let target = cpu.decoder.get_mode_as_target(&mut memory.borrow_mut(), 0b111, 0b100, Some(size)).unwrap(); + assert_eq!(target, Target::Immediate(expected)); + } + + // + // Instruction Decode Tests + // #[test] fn instruction_nop() { - let (mut cpu, mut system) = init_test(); + let (mut cpu, system) = init_decode_test(); system.get_bus().write_beu16(INIT_ADDR, 0x4e71).unwrap(); cpu.decode_next(&system).unwrap(); assert_eq!(cpu.decoder.instruction, Instruction::NOP); - cpu.execute_current(&system).unwrap(); - // TODO you need a way to easily check the entire state (you maybe need to make a special struct for the state) } - #[test] fn instruction_ori() { - let (mut cpu, mut system) = init_test(); + let (mut cpu, system) = init_decode_test(); system.get_bus().write_beu16(INIT_ADDR, 0x0008).unwrap(); system.get_bus().write_beu16(INIT_ADDR + 2, 0x00FF).unwrap(); cpu.decode_next(&system).unwrap(); assert_eq!(cpu.decoder.instruction, Instruction::OR(Target::Immediate(0xFF), Target::DirectAReg(0), Size::Byte)); - cpu.execute_current(&system).unwrap(); - assert_eq!(cpu.state.a_reg[0], 0x000000FF); } #[test] fn instruction_cmpi_equal() { - let (mut cpu, mut system) = init_test(); + let (mut cpu, system) = init_decode_test(); system.get_bus().write_beu16(INIT_ADDR, 0x7020).unwrap(); system.get_bus().write_beu16(INIT_ADDR + 2, 0x0C00).unwrap(); @@ -69,13 +244,11 @@ mod tests { cpu.step(&system).unwrap(); cpu.decode_next(&system).unwrap(); assert_eq!(cpu.decoder.instruction, Instruction::CMP(Target::Immediate(0x20), Target::DirectDReg(0), Size::Byte)); - cpu.execute_current(&system).unwrap(); - assert_eq!(cpu.state.sr & 0x0F, 0x04); } #[test] fn instruction_cmpi_greater() { - let (mut cpu, mut system) = init_test(); + let (mut cpu, system) = init_decode_test(); system.get_bus().write_beu16(INIT_ADDR, 0x7020).unwrap(); system.get_bus().write_beu16(INIT_ADDR + 2, 0x0C00).unwrap(); @@ -83,13 +256,11 @@ mod tests { cpu.step(&system).unwrap(); cpu.decode_next(&system).unwrap(); assert_eq!(cpu.decoder.instruction, Instruction::CMP(Target::Immediate(0x30), Target::DirectDReg(0), Size::Byte)); - cpu.execute_current(&system).unwrap(); - assert_eq!(cpu.state.sr & 0x0F, 0x009); } #[test] fn instruction_cmpi_less() { - let (mut cpu, mut system) = init_test(); + let (mut cpu, system) = init_decode_test(); system.get_bus().write_beu16(INIT_ADDR, 0x7020).unwrap(); system.get_bus().write_beu16(INIT_ADDR + 2, 0x0C00).unwrap(); @@ -97,43 +268,206 @@ mod tests { cpu.step(&system).unwrap(); cpu.decode_next(&system).unwrap(); assert_eq!(cpu.decoder.instruction, Instruction::CMP(Target::Immediate(0x10), Target::DirectDReg(0), Size::Byte)); + } + + #[test] + fn instruction_andi_sr() { + let (mut cpu, system) = init_decode_test(); + + system.get_bus().write_beu16(INIT_ADDR, 0x027C).unwrap(); + system.get_bus().write_beu16(INIT_ADDR + 2, 0xF8FF).unwrap(); + cpu.decode_next(&system).unwrap(); + assert_eq!(cpu.decoder.instruction, Instruction::ANDtoSR(0xF8FF)); + } + + #[test] + fn instruction_muls() { + let (mut cpu, system) = init_decode_test(); + + system.get_bus().write_beu16(INIT_ADDR, 0xC1FC).unwrap(); + system.get_bus().write_beu16(INIT_ADDR + 2, 0x0276).unwrap(); + cpu.decode_next(&system).unwrap(); + assert_eq!(cpu.decoder.instruction, Instruction::MUL(Target::Immediate(0x276), Target::DirectDReg(0), Size::Word, Sign::Signed)); + } + + #[test] + fn instruction_asli() { + let (mut cpu, system) = init_decode_test(); + + system.get_bus().write_beu16(INIT_ADDR, 0xE300).unwrap(); + cpu.decode_next(&system).unwrap(); + assert_eq!(cpu.decoder.instruction, Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left)); + } + + #[test] + fn instruction_asri() { + let (mut cpu, system) = init_decode_test(); + + system.get_bus().write_beu16(INIT_ADDR, 0xE200).unwrap(); + cpu.decode_next(&system).unwrap(); + assert_eq!(cpu.decoder.instruction, Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right)); + } + + #[test] + fn instruction_roli() { + let (mut cpu, system) = init_decode_test(); + + system.get_bus().write_beu16(INIT_ADDR, 0xE318).unwrap(); + cpu.decode_next(&system).unwrap(); + assert_eq!(cpu.decoder.instruction, Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left)); + } + + #[test] + fn instruction_rori() { + let (mut cpu, system) = init_decode_test(); + + system.get_bus().write_beu16(INIT_ADDR, 0xE218).unwrap(); + cpu.decode_next(&system).unwrap(); + assert_eq!(cpu.decoder.instruction, Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right)); + } +} + + +#[cfg(test)] +mod execute_tests { + use crate::system::System; + use crate::devices::{Steppable, wrap_addressable}; + use crate::memory::{Address, Addressable, MemoryBlock}; + + use crate::cpus::m68k::{M68k, M68kType}; + use crate::cpus::m68k::decode::{Instruction, Target, Size, Sign, ShiftDirection}; + + const INIT_STACK: Address = 0x00002000; + const INIT_ADDR: Address = 0x00000010; + + fn init_test() -> (M68k, System) { + let mut system = System::new(); + + // Insert basic initialization + let data = vec![0; 0x00100000]; + let mem = MemoryBlock::new(data); + system.add_addressable_device(0x00000000, wrap_addressable(mem)).unwrap(); + system.get_bus().write_beu32(0, INIT_STACK as u32).unwrap(); + system.get_bus().write_beu32(4, INIT_ADDR as u32).unwrap(); + + let mut cpu = M68k::new(M68kType::MC68010); + cpu.step(&system).unwrap(); + assert_eq!(cpu.state.pc, INIT_ADDR as u32); + assert_eq!(cpu.state.msp, INIT_STACK as u32); + assert_eq!(cpu.decoder.instruction, Instruction::NOP); + (cpu, system) + } + + + #[test] + fn instruction_nop() { + let (mut cpu, system) = init_test(); + + cpu.decoder.instruction = Instruction::NOP; + + let previous = cpu.state.clone(); + cpu.execute_current(&system).unwrap(); + assert_eq!(cpu.state, previous); + } + + + #[test] + fn instruction_ori() { + let (mut cpu, system) = init_test(); + + cpu.decoder.instruction = Instruction::OR(Target::Immediate(0xFF), Target::DirectAReg(0), Size::Byte); + + cpu.execute_current(&system).unwrap(); + assert_eq!(cpu.state.a_reg[0], 0x000000FF); + } + + #[test] + fn instruction_cmpi_equal() { + let (mut cpu, system) = init_test(); + + let value = 0x20; + cpu.state.d_reg[0] = value; + cpu.decoder.instruction = Instruction::CMP(Target::Immediate(value), Target::DirectDReg(0), Size::Byte); + + cpu.execute_current(&system).unwrap(); + assert_eq!(cpu.state.sr & 0x0F, 0x04); + } + + #[test] + fn instruction_cmpi_greater() { + let (mut cpu, system) = init_test(); + + cpu.state.d_reg[0] = 0x20; + cpu.decoder.instruction = Instruction::CMP(Target::Immediate(0x30), Target::DirectDReg(0), Size::Byte); + + cpu.execute_current(&system).unwrap(); + assert_eq!(cpu.state.sr & 0x0F, 0x09); + } + + #[test] + fn instruction_cmpi_less() { + let (mut cpu, system) = init_test(); + + cpu.state.d_reg[0] = 0x20; + cpu.decoder.instruction = Instruction::CMP(Target::Immediate(0x10), Target::DirectDReg(0), Size::Byte); + cpu.execute_current(&system).unwrap(); assert_eq!(cpu.state.sr & 0x0F, 0x00); } #[test] fn instruction_andi_sr() { - let (mut cpu, mut system) = init_test(); + let (mut cpu, system) = init_test(); - system.get_bus().write_beu16(INIT_ADDR, 0x027C).unwrap(); - system.get_bus().write_beu16(INIT_ADDR + 2, 0xF8FF).unwrap(); - cpu.decode_next(&system).unwrap(); - assert_eq!(cpu.decoder.instruction, Instruction::ANDtoSR(0xF8FF)); - //cpu.execute_current(&system).unwrap(); - //assert_eq!(cpu.state.sr & 0x0F, 0x00); + cpu.state.sr = 0x87AA; + cpu.decoder.instruction = Instruction::ANDtoSR(0xF8FF); + + cpu.execute_current(&system).unwrap(); + assert_eq!(cpu.state.sr, 0x80AA); + } + + #[test] + fn instruction_ori_sr() { + let (mut cpu, system) = init_test(); + + cpu.state.sr = 0x8755; + cpu.decoder.instruction = Instruction::ORtoSR(0x00AA); + + cpu.execute_current(&system).unwrap(); + assert_eq!(cpu.state.sr, 0x87FF); } #[test] fn instruction_muls() { - let (mut cpu, mut system) = init_test(); + let (mut cpu, system) = init_test(); - system.get_bus().write_beu16(INIT_ADDR, 0xC1FC).unwrap(); - system.get_bus().write_beu16(INIT_ADDR + 2, 0x0276).unwrap(); - cpu.decode_next(&system).unwrap(); - assert_eq!(cpu.decoder.instruction, Instruction::MUL(Target::Immediate(0x276), Target::DirectDReg(0), Size::Word, Sign::Signed)); - //cpu.execute_current(&system).unwrap(); - //assert_eq!(cpu.state.sr & 0x0F, 0x00); + let value = 0x0276; + cpu.state.d_reg[0] = 0x0200; + cpu.decoder.instruction = Instruction::MUL(Target::Immediate(value), Target::DirectDReg(0), Size::Word, Sign::Signed); + + cpu.execute_current(&system).unwrap(); + assert_eq!(cpu.state.d_reg[0], 0x4ec00); + } + + #[test] + fn instruction_divu() { + let (mut cpu, system) = init_test(); + + let value = 0x0245; + cpu.state.d_reg[0] = 0x40000; + cpu.decoder.instruction = Instruction::DIV(Target::Immediate(value), Target::DirectDReg(0), Size::Word, Sign::Unsigned); + + cpu.execute_current(&system).unwrap(); + assert_eq!(cpu.state.d_reg[0], 0x007101C3); } #[test] fn instruction_asli() { - let (mut cpu, mut system) = init_test(); - - system.get_bus().write_beu16(INIT_ADDR, 0xE300).unwrap(); - cpu.decode_next(&system).unwrap(); - assert_eq!(cpu.decoder.instruction, Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left)); + let (mut cpu, system) = init_test(); cpu.state.d_reg[0] = 0x01; + cpu.decoder.instruction = Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left); + cpu.execute_current(&system).unwrap(); assert_eq!(cpu.state.d_reg[0], 0x00000002); assert_eq!(cpu.state.sr & 0x1F, 0x00); @@ -141,13 +475,11 @@ mod tests { #[test] fn instruction_asri() { - let (mut cpu, mut system) = init_test(); - - system.get_bus().write_beu16(INIT_ADDR, 0xE200).unwrap(); - cpu.decode_next(&system).unwrap(); - assert_eq!(cpu.decoder.instruction, Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right)); + let (mut cpu, system) = init_test(); cpu.state.d_reg[0] = 0x81; + cpu.decoder.instruction = Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right); + cpu.execute_current(&system).unwrap(); assert_eq!(cpu.state.d_reg[0], 0x000000C0); assert_eq!(cpu.state.sr & 0x1F, 0x19); @@ -155,13 +487,11 @@ mod tests { #[test] fn instruction_roli() { - let (mut cpu, mut system) = init_test(); - - system.get_bus().write_beu16(INIT_ADDR, 0xE318).unwrap(); - cpu.decode_next(&system).unwrap(); - assert_eq!(cpu.decoder.instruction, Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left)); + let (mut cpu, system) = init_test(); cpu.state.d_reg[0] = 0x80; + cpu.decoder.instruction = Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left); + cpu.execute_current(&system).unwrap(); assert_eq!(cpu.state.d_reg[0], 0x00000001); assert_eq!(cpu.state.sr & 0x1F, 0x01); @@ -169,13 +499,11 @@ mod tests { #[test] fn instruction_rori() { - let (mut cpu, mut system) = init_test(); - - system.get_bus().write_beu16(INIT_ADDR, 0xE218).unwrap(); - cpu.decode_next(&system).unwrap(); - assert_eq!(cpu.decoder.instruction, Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right)); + let (mut cpu, system) = init_test(); cpu.state.d_reg[0] = 0x01; + cpu.decoder.instruction = Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right); + cpu.execute_current(&system).unwrap(); assert_eq!(cpu.state.d_reg[0], 0x00000080); assert_eq!(cpu.state.sr & 0x1F, 0x09); @@ -183,17 +511,13 @@ mod tests { - - #[test] fn target_value_direct_d() { - let (mut cpu, mut system) = init_test(); + let (mut cpu, system) = init_test(); let size = Size::Word; let expected = 0x1234; - - let target = cpu.decoder.get_mode_as_target(&system, 0b000, 0b001, Some(size)).unwrap(); - assert_eq!(target, Target::DirectDReg(1)); + let target = Target::DirectDReg(1); cpu.state.d_reg[1] = expected; let result = cpu.get_target_value(&system, target, size).unwrap(); @@ -202,13 +526,11 @@ mod tests { #[test] fn target_value_direct_a() { - let (mut cpu, mut system) = init_test(); + let (mut cpu, system) = init_test(); let size = Size::Word; let expected = 0x1234; - - let target = cpu.decoder.get_mode_as_target(&system, 0b001, 0b010, Some(size)).unwrap(); - assert_eq!(target, Target::DirectAReg(2)); + let target = Target::DirectAReg(2); cpu.state.a_reg[2] = expected; let result = cpu.get_target_value(&system, target, size).unwrap(); @@ -217,15 +539,13 @@ mod tests { #[test] fn target_value_indirect_a() { - let (mut cpu, mut system) = init_test(); + let (mut cpu, system) = init_test(); let size = Size::Long; let expected_addr = INIT_ADDR; let expected = 0x12345678; - + let target = Target::IndirectAReg(2); system.get_bus().write_beu32(INIT_ADDR, expected).unwrap(); - let target = cpu.decoder.get_mode_as_target(&system, 0b010, 0b010, Some(size)).unwrap(); - assert_eq!(target, Target::IndirectAReg(2)); cpu.state.a_reg[2] = INIT_ADDR as u32; let result = cpu.get_target_value(&system, target, size).unwrap(); @@ -234,15 +554,13 @@ mod tests { #[test] fn target_value_indirect_a_inc() { - let (mut cpu, mut system) = init_test(); + let (mut cpu, system) = init_test(); let size = Size::Long; let expected_addr = INIT_ADDR; let expected = 0x12345678; - + let target = Target::IndirectARegInc(2); system.get_bus().write_beu32(INIT_ADDR, expected).unwrap(); - let target = cpu.decoder.get_mode_as_target(&system, 0b011, 0b010, Some(size)).unwrap(); - assert_eq!(target, Target::IndirectARegInc(2)); cpu.state.a_reg[2] = INIT_ADDR as u32; let result = cpu.get_target_value(&system, target, size).unwrap(); @@ -252,15 +570,13 @@ mod tests { #[test] fn target_value_indirect_a_dec() { - let (mut cpu, mut system) = init_test(); + let (mut cpu, system) = init_test(); let size = Size::Long; let expected_addr = INIT_ADDR + 4; let expected = 0x12345678; - + let target = Target::IndirectARegDec(2); system.get_bus().write_beu32(INIT_ADDR, expected).unwrap(); - let target = cpu.decoder.get_mode_as_target(&system, 0b100, 0b010, Some(size)).unwrap(); - assert_eq!(target, Target::IndirectARegDec(2)); cpu.state.a_reg[2] = (INIT_ADDR as u32) + 4; let result = cpu.get_target_value(&system, target, size).unwrap(); @@ -271,17 +587,16 @@ mod tests { #[test] fn target_value_immediate() { - let (mut cpu, mut system) = init_test(); + let (mut cpu, system) = init_test(); let size = Size::Word; let expected = 0x1234; - system.get_bus().write_beu16(cpu.decoder.end as Address, expected as u16).unwrap(); - let target = cpu.decoder.get_mode_as_target(&system, 0b111, 0b100, Some(size)).unwrap(); - assert_eq!(target, Target::Immediate(expected)); + let target = Target::Immediate(expected); let result = cpu.get_target_value(&system, target, size).unwrap(); assert_eq!(result, expected); } } + diff --git a/src/devices.rs b/src/devices.rs index 26cbeb3..92b894f 100644 --- a/src/devices.rs +++ b/src/devices.rs @@ -9,27 +9,33 @@ use crate::memory::{Addressable}; pub type Clock = u64; - +/// A device that can change state over time. The `step()` method will be called +/// by the containing `System` when the system clock advances. If an error occurs +/// with any device, the `on_error()` method will be called to display any state +/// information that might be helpful for debugging. pub trait Steppable { fn step(&mut self, system: &System) -> Result; fn on_error(&mut self, _system: &System) { } } +/// A device that can receive an interrupt. The `interrupt_state_change()` method +/// will be called whenever an interrupt signal changes goes high or low. pub trait Interruptable { fn interrupt_state_change(&mut self, state: bool, priority: u8, number: u8) -> Result<(), Error>; } + pub trait AddressableDevice: Addressable + Steppable { } pub trait InterruptableDevice: Interruptable + Steppable { } -impl AddressableDevice for T { } -impl InterruptableDevice for T { } - pub type AddressableDeviceBox = Rc>>; pub type InterruptableDeviceBox = Rc>>; pub type AddressableDeviceRefMut<'a> = RefMut<'a, Box>; +impl AddressableDevice for T { } +impl InterruptableDevice for T { } + pub fn wrap_addressable(value: T) -> AddressableDeviceBox { Rc::new(RefCell::new(Box::new(value))) } diff --git a/src/error.rs b/src/error.rs index fcb4ac0..dec74f2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,7 +3,6 @@ pub enum ErrorType { Emulator, Processor, - Internal, } #[derive(Debug)] diff --git a/src/main.rs b/src/main.rs index 7334614..fdbcd2b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -58,21 +58,6 @@ fn main() { }, } } - - /* - // TODO I need to add a way to decode and dump the assembly for a section of code, in debugger - cpu.enable_tracing(); - cpu.state.pc = 0x0010781a; - while cpu.is_running() { - match cpu.decode_next(&system) { - Ok(()) => { }, - Err(err) => { - cpu.dump_state(&system); - panic!("{:?}", err); - }, - } - } - */ } pub fn launch_terminal_emulator(name: String) { @@ -84,7 +69,6 @@ pub fn launch_terminal_emulator(name: String) { } pub fn launch_slip_connection(name: String) { - use nix::unistd::sleep; use std::process::Command; Command::new("sudo").args(["slattach", "-s", "38400", "-p", "slip", &name]).spawn().unwrap(); diff --git a/src/memory.rs b/src/memory.rs index 9f84d14..afe3a52 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -8,6 +8,7 @@ use crate::devices::{Clock, Steppable, AddressableDeviceBox}; pub type Address = u64; +/// A device that can be addressed to read data from or write data to the device. pub trait Addressable { fn len(&self) -> usize; fn read(&mut self, addr: Address, count: usize) -> Result, Error>;