From 1ad7ad180733766e5319d635607a4ebed47e0206 Mon Sep 17 00:00:00 2001 From: transistor Date: Tue, 26 Oct 2021 12:17:59 -0700 Subject: [PATCH] Added Debuggable trait and added tests --- frontends/moa-console/src/bin/moa-bench.rs | 2 +- src/cpus/m68k/debugger.rs | 22 +- src/cpus/m68k/decode.rs | 22 +- src/cpus/m68k/execute.rs | 6 +- src/cpus/m68k/instructions.rs | 2 + src/cpus/m68k/tests.rs | 335 +++++++++++++++------ src/devices.rs | 11 + todo.txt | 8 +- 8 files changed, 291 insertions(+), 117 deletions(-) diff --git a/frontends/moa-console/src/bin/moa-bench.rs b/frontends/moa-console/src/bin/moa-bench.rs index 4beadf3..51faca0 100644 --- a/frontends/moa-console/src/bin/moa-bench.rs +++ b/frontends/moa-console/src/bin/moa-bench.rs @@ -32,7 +32,7 @@ fn main() { system.add_addressable_device(0x00700000, wrap_transmutable(serial)).unwrap(); - let mut cpu = M68k::new(M68kType::MC68030); + let mut cpu = M68k::new(M68kType::MC68030, 8_000_000); //cpu.enable_tracing(); //cpu.add_breakpoint(0x10781a); diff --git a/src/cpus/m68k/debugger.rs b/src/cpus/m68k/debugger.rs index a930ea2..16a7174 100644 --- a/src/cpus/m68k/debugger.rs +++ b/src/cpus/m68k/debugger.rs @@ -1,7 +1,7 @@ use crate::error::Error; use crate::system::System; -use crate::devices::{Address, Addressable}; +use crate::devices::{Address, Addressable, Debuggable}; use super::state::M68k; use super::decode::M68kDecoder; @@ -47,22 +47,22 @@ impl M68kDebugger { } } -impl M68k { - #[allow(dead_code)] - pub fn enable_tracing(&mut self) { - self.debugger.use_tracing = true; - } - - #[allow(dead_code)] - pub fn enable_debugging(&mut self) { +impl Debuggable for M68k { + fn enable_debugging(&mut self) { self.debugger.use_tracing = true; self.debugger.use_debugger = true; } - #[allow(dead_code)] - pub fn add_breakpoint(&mut self, addr: Address) { + fn add_breakpoint(&mut self, addr: Address) { self.debugger.breakpoints.push(addr as u32); } +} + +impl M68k { + #[allow(dead_code)] + pub fn enable_tracing(&mut self) { + self.debugger.use_tracing = true; + } pub fn check_breakpoints(&mut self) { for breakpoint in &self.debugger.breakpoints { diff --git a/src/cpus/m68k/decode.rs b/src/cpus/m68k/decode.rs index 993b5f9..631e401 100644 --- a/src/cpus/m68k/decode.rs +++ b/src/cpus/m68k/decode.rs @@ -88,7 +88,7 @@ impl M68kDecoder { let data = self.read_instruction_word(memory)?; match optype { 0b0000 => Ok(Instruction::ORtoCCR(data as u8)), - 0b0001 => Ok(Instruction::ANDtoCCR(data as u8)), + 0b0010 => Ok(Instruction::ANDtoCCR(data as u8)), 0b1010 => Ok(Instruction::EORtoCCR(data as u8)), _ => return Err(Error::processor(Exceptions::IllegalInstruction as u32)), } @@ -423,10 +423,12 @@ impl M68kDecoder { match size { Some(size) => { if (ins & 0b100110000) == 0b100000000 { - let mode = (ins & 0x08) == 0; - - // TODO implement SUBX - panic!("Not Implemented"); + let src = get_low_reg(ins); + let dest = get_high_reg(ins); + match (ins & 0x08) == 0 { + true => Ok(Instruction::SUBX(Target::DirectDReg(src), Target::DirectDReg(dest), size)), + false => Ok(Instruction::SUBX(Target::IndirectARegDec(src), Target::DirectDReg(dest), size)), + } } else { let target = self.decode_lower_effective_address(memory, ins, Some(size))?; if dir == 0 { @@ -506,10 +508,12 @@ impl M68kDecoder { match size { Some(size) => { if (ins & 0b100110000) == 0b100000000 { - let mode = (ins & 0x08) == 0; - - // TODO implement ADDX - panic!("Not Implemented"); + let src = get_low_reg(ins); + let dest = get_high_reg(ins); + match (ins & 0x08) == 0 { + true => Ok(Instruction::ADDX(Target::DirectDReg(src), Target::DirectDReg(dest), size)), + false => Ok(Instruction::ADDX(Target::IndirectARegDec(src), Target::DirectDReg(dest), size)), + } } else { let target = self.decode_lower_effective_address(memory, ins, Some(size))?; if dir == 0 { diff --git a/src/cpus/m68k/execute.rs b/src/cpus/m68k/execute.rs index 3bbe89c..a2239b3 100644 --- a/src/cpus/m68k/execute.rs +++ b/src/cpus/m68k/execute.rs @@ -1,7 +1,7 @@ use crate::system::System; use crate::error::{ErrorType, Error}; -use crate::devices::{ClockElapsed, Address, Steppable, Interruptable, Addressable, Transmutable}; +use crate::devices::{ClockElapsed, Address, Steppable, Interruptable, Addressable, Debuggable, Transmutable}; use super::instructions::{ Register, @@ -67,6 +67,10 @@ impl Transmutable for M68k { fn as_interruptable(&mut self) -> Option<&mut dyn Interruptable> { Some(self) } + + fn as_debuggable(&mut self) -> Option<&mut dyn Debuggable> { + Some(self) + } } diff --git a/src/cpus/m68k/instructions.rs b/src/cpus/m68k/instructions.rs index ffd2f27..5e84a1b 100644 --- a/src/cpus/m68k/instructions.rs +++ b/src/cpus/m68k/instructions.rs @@ -98,6 +98,7 @@ pub enum Target { pub enum Instruction { ABCD(Target, Target), ADD(Target, Target, Size), + ADDX(Target, Target, Size), AND(Target, Target, Size), ANDtoCCR(u8), ANDtoSR(u16), @@ -183,6 +184,7 @@ pub enum Instruction { Scc(Condition, Target), STOP(u16), SUB(Target, Target, Size), + SUBX(Target, Target, Size), SWAP(Register), TAS(Target), diff --git a/src/cpus/m68k/tests.rs b/src/cpus/m68k/tests.rs index 428d3dc..cc4c414 100644 --- a/src/cpus/m68k/tests.rs +++ b/src/cpus/m68k/tests.rs @@ -32,6 +32,14 @@ mod decode_tests { (cpu, system) } + fn load_memory(system: &System, data: &[u16]) { + let mut addr = INIT_ADDR; + for word in data { + system.get_bus().write_beu16(addr, *word).unwrap(); + addr += 2; + } + } + fn get_decode_memory(cpu: &mut M68k, system: &System) -> TransmutableBox { 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); @@ -302,30 +310,130 @@ mod decode_tests { fn instruction_nop() { let (mut cpu, system) = init_decode_test(M68kType::MC68010); - system.get_bus().write_beu16(INIT_ADDR, 0x4e71).unwrap(); + load_memory(&system, &[0x4e71]); cpu.decode_next(&system).unwrap(); + assert_eq!(cpu.decoder.instruction, Instruction::NOP); } #[test] - fn instruction_ori() { + fn instruction_ori_byte() { let (mut cpu, system) = init_decode_test(M68kType::MC68010); - system.get_bus().write_beu16(INIT_ADDR, 0x0008).unwrap(); - system.get_bus().write_beu16(INIT_ADDR + 2, 0x00FF).unwrap(); + load_memory(&system, &[0x0008, 0x00FF]); cpu.decode_next(&system).unwrap(); + assert_eq!(cpu.decoder.instruction, Instruction::OR(Target::Immediate(0xFF), Target::DirectAReg(0), Size::Byte)); } + #[test] + fn instruction_ori_to_ccr() { + let (mut cpu, system) = init_decode_test(M68kType::MC68010); + + load_memory(&system, &[0x003C, 0x00FF]); + cpu.decode_next(&system).unwrap(); + + assert_eq!(cpu.decoder.instruction, Instruction::ORtoCCR(0xFF)); + } + + #[test] + fn instruction_ori_to_sr() { + let (mut cpu, system) = init_decode_test(M68kType::MC68010); + + load_memory(&system, &[0x007C, 0x1234]); + cpu.decode_next(&system).unwrap(); + + assert_eq!(cpu.decoder.instruction, Instruction::ORtoSR(0x1234)); + } + + #[test] + fn instruction_andi_word() { + let (mut cpu, system) = init_decode_test(M68kType::MC68010); + + load_memory(&system, &[0x0263, 0x1234]); + cpu.decode_next(&system).unwrap(); + + assert_eq!(cpu.decoder.instruction, Instruction::AND(Target::Immediate(0x1234), Target::IndirectARegDec(3), Size::Word)); + } + + #[test] + fn instruction_andi_to_ccr() { + let (mut cpu, system) = init_decode_test(M68kType::MC68010); + + load_memory(&system, &[0x023C, 0x1234]); + cpu.decode_next(&system).unwrap(); + + assert_eq!(cpu.decoder.instruction, Instruction::ANDtoCCR(0x34)); + } + + #[test] + fn instruction_andi_to_sr() { + let (mut cpu, system) = init_decode_test(M68kType::MC68010); + + load_memory(&system, &[0x027C, 0xF8FF]); + cpu.decode_next(&system).unwrap(); + + assert_eq!(cpu.decoder.instruction, Instruction::ANDtoSR(0xF8FF)); + } + + #[test] + fn instruction_subi() { + let (mut cpu, system) = init_decode_test(M68kType::MC68010); + + load_memory(&system, &[0x0487, 0x1234, 0x5678]); + cpu.decode_next(&system).unwrap(); + + assert_eq!(cpu.decoder.instruction, Instruction::SUB(Target::Immediate(0x12345678), Target::DirectDReg(7), Size::Long)); + } + + #[test] + fn instruction_addi() { + let (mut cpu, system) = init_decode_test(M68kType::MC68010); + + load_memory(&system, &[0x063A, 0x1234, 0x0055]); + cpu.decode_next(&system).unwrap(); + + assert_eq!(cpu.decoder.instruction, Instruction::ADD(Target::Immediate(0x34), Target::IndirectRegOffset(BaseRegister::PC, None, 0x55), Size::Byte)); + } + + #[test] + fn instruction_eori_byte() { + let (mut cpu, system) = init_decode_test(M68kType::MC68010); + + load_memory(&system, &[0x0A23, 0x1234]); + cpu.decode_next(&system).unwrap(); + + assert_eq!(cpu.decoder.instruction, Instruction::EOR(Target::Immediate(0x34), Target::IndirectARegDec(3), Size::Byte)); + } + + #[test] + fn instruction_eori_to_ccr() { + let (mut cpu, system) = init_decode_test(M68kType::MC68010); + + load_memory(&system, &[0x0A3C, 0x1234]); + cpu.decode_next(&system).unwrap(); + + assert_eq!(cpu.decoder.instruction, Instruction::EORtoCCR(0x34)); + } + + #[test] + fn instruction_eori_to_sr() { + let (mut cpu, system) = init_decode_test(M68kType::MC68010); + + load_memory(&system, &[0x0A7C, 0xF8FF]); + cpu.decode_next(&system).unwrap(); + + assert_eq!(cpu.decoder.instruction, Instruction::EORtoSR(0xF8FF)); + } + + #[test] fn instruction_cmpi_equal() { let (mut cpu, system) = init_decode_test(M68kType::MC68010); - system.get_bus().write_beu16(INIT_ADDR, 0x7020).unwrap(); - system.get_bus().write_beu16(INIT_ADDR + 2, 0x0C00).unwrap(); - system.get_bus().write_beu16(INIT_ADDR + 4, 0x0020).unwrap(); - cpu.step(&system).unwrap(); + load_memory(&system, &[0x0C00, 0x0020]); cpu.decode_next(&system).unwrap(); + assert_eq!(cpu.decoder.instruction, Instruction::CMP(Target::Immediate(0x20), Target::DirectDReg(0), Size::Byte)); } @@ -333,11 +441,9 @@ mod decode_tests { fn instruction_cmpi_greater() { let (mut cpu, system) = init_decode_test(M68kType::MC68010); - system.get_bus().write_beu16(INIT_ADDR, 0x7020).unwrap(); - system.get_bus().write_beu16(INIT_ADDR + 2, 0x0C00).unwrap(); - system.get_bus().write_beu16(INIT_ADDR + 4, 0x0030).unwrap(); - cpu.step(&system).unwrap(); + load_memory(&system, &[0x0C00, 0x0030]); cpu.decode_next(&system).unwrap(); + assert_eq!(cpu.decoder.instruction, Instruction::CMP(Target::Immediate(0x30), Target::DirectDReg(0), Size::Byte)); } @@ -345,62 +451,59 @@ mod decode_tests { fn instruction_cmpi_less() { let (mut cpu, system) = init_decode_test(M68kType::MC68010); - system.get_bus().write_beu16(INIT_ADDR, 0x7020).unwrap(); - system.get_bus().write_beu16(INIT_ADDR + 2, 0x0C00).unwrap(); - system.get_bus().write_beu16(INIT_ADDR + 4, 0x0010).unwrap(); - cpu.step(&system).unwrap(); + load_memory(&system, &[0x0C00, 0x0010]); 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(M68kType::MC68010); + fn instruction_movel_full_extension() { + let (mut cpu, system) = init_decode_test(M68kType::MC68030); - system.get_bus().write_beu16(INIT_ADDR, 0x027C).unwrap(); - system.get_bus().write_beu16(INIT_ADDR + 2, 0xF8FF).unwrap(); + load_memory(&system, &[0x21bc, 0x0010, 0x14c4, 0x09b0, 0x0010, 0xdf40]); cpu.decode_next(&system).unwrap(); - assert_eq!(cpu.decoder.instruction, Instruction::ANDtoSR(0xF8FF)); - } - #[test] - fn instruction_muls() { - let (mut cpu, system) = init_decode_test(M68kType::MC68010); - - 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::MULW(Target::Immediate(0x276), 0, Sign::Signed)); - } - - #[test] - fn instruction_divs() { - let (mut cpu, system) = init_decode_test(M68kType::MC68010); - - system.get_bus().write_beu16(INIT_ADDR, 0x81FC).unwrap(); - system.get_bus().write_beu16(INIT_ADDR + 2, 0x0003).unwrap(); - cpu.decode_next(&system).unwrap(); - assert_eq!(cpu.decoder.instruction, Instruction::DIVW(Target::Immediate(3), 0, Sign::Signed)); + assert_eq!(cpu.decoder.instruction, Instruction::MOVE(Target::Immediate(1053892), Target::IndirectRegOffset(BaseRegister::None, Some(IndexRegister { xreg: XRegister::DReg(0), scale: 0, size: Size::Long }), 0x10df40), Size::Long)); } #[test] fn instruction_mulsl() { let (mut cpu, system) = init_decode_test(M68kType::MC68030); - system.get_bus().write_beu16(INIT_ADDR, 0x4c3c).unwrap(); - system.get_bus().write_beu16(INIT_ADDR + 2, 0x0800).unwrap(); - system.get_bus().write_beu16(INIT_ADDR + 4, 0x0000).unwrap(); - system.get_bus().write_beu16(INIT_ADDR + 6, 0x0097).unwrap(); + load_memory(&system, &[0x4c3c, 0x0800, 0x0000, 0x0097]); cpu.decode_next(&system).unwrap(); + assert_eq!(cpu.decoder.instruction, Instruction::MULL(Target::Immediate(0x97), None, 0, Sign::Signed)); } + #[test] + fn instruction_divs() { + let (mut cpu, system) = init_decode_test(M68kType::MC68010); + + load_memory(&system, &[0x81FC, 0x0003]); + cpu.decode_next(&system).unwrap(); + + assert_eq!(cpu.decoder.instruction, Instruction::DIVW(Target::Immediate(3), 0, Sign::Signed)); + } + + #[test] + fn instruction_muls() { + let (mut cpu, system) = init_decode_test(M68kType::MC68010); + + load_memory(&system, &[0xC1FC, 0x0276]); + cpu.decode_next(&system).unwrap(); + + assert_eq!(cpu.decoder.instruction, Instruction::MULW(Target::Immediate(0x276), 0, Sign::Signed)); + } + #[test] fn instruction_asli() { let (mut cpu, system) = init_decode_test(M68kType::MC68010); - system.get_bus().write_beu16(INIT_ADDR, 0xE300).unwrap(); + load_memory(&system, &[0xE300]); cpu.decode_next(&system).unwrap(); + assert_eq!(cpu.decoder.instruction, Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left)); } @@ -408,8 +511,9 @@ mod decode_tests { fn instruction_asri() { let (mut cpu, system) = init_decode_test(M68kType::MC68010); - system.get_bus().write_beu16(INIT_ADDR, 0xE200).unwrap(); + load_memory(&system, &[0xE200]); cpu.decode_next(&system).unwrap(); + assert_eq!(cpu.decoder.instruction, Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right)); } @@ -417,8 +521,9 @@ mod decode_tests { fn instruction_roli() { let (mut cpu, system) = init_decode_test(M68kType::MC68010); - system.get_bus().write_beu16(INIT_ADDR, 0xE318).unwrap(); + load_memory(&system, &[0xE318]); cpu.decode_next(&system).unwrap(); + assert_eq!(cpu.decoder.instruction, Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left)); } @@ -426,25 +531,11 @@ mod decode_tests { fn instruction_rori() { let (mut cpu, system) = init_decode_test(M68kType::MC68010); - system.get_bus().write_beu16(INIT_ADDR, 0xE218).unwrap(); + load_memory(&system, &[0xE218]); cpu.decode_next(&system).unwrap(); + assert_eq!(cpu.decoder.instruction, Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right)); } - - #[test] - fn instruction_movel_full_extension() { - let (mut cpu, system) = init_decode_test(M68kType::MC68030); - - let mut addr = INIT_ADDR; - let data = [0x21bc, 0x0010, 0x14c4, 0x09b0, 0x0010, 0xdf40]; - for word in data { - system.get_bus().write_beu16(addr, word).unwrap(); - addr += 2; - } - - cpu.decode_next(&system).unwrap(); - assert_eq!(cpu.decoder.instruction, Instruction::MOVE(Target::Immediate(1053892), Target::IndirectRegOffset(BaseRegister::None, Some(IndexRegister { xreg: XRegister::DReg(0), scale: 0, size: Size::Long }), 0x10df40), Size::Long)); - } } @@ -485,9 +576,10 @@ mod execute_tests { cpu.decoder.instruction = Instruction::NOP; - let previous = cpu.state.clone(); + let expected_state = cpu.state.clone(); + cpu.execute_current(&system).unwrap(); - assert_eq!(cpu.state, previous); + assert_eq!(cpu.state, expected_state); } @@ -497,8 +589,12 @@ mod execute_tests { cpu.decoder.instruction = Instruction::OR(Target::Immediate(0xFF), Target::DirectAReg(0), Size::Byte); + let mut expected_state = cpu.state.clone(); + expected_state.sr = 0x2708; + expected_state.a_reg[0] = 0x000000FF; + cpu.execute_current(&system).unwrap(); - assert_eq!(cpu.state.a_reg[0], 0x000000FF); + assert_eq!(cpu.state, expected_state); } #[test] @@ -509,8 +605,11 @@ mod execute_tests { cpu.state.d_reg[0] = value; cpu.decoder.instruction = Instruction::CMP(Target::Immediate(value), Target::DirectDReg(0), Size::Byte); + let mut expected_state = cpu.state.clone(); + expected_state.sr = 0x2704; + cpu.execute_current(&system).unwrap(); - assert_eq!(cpu.state.sr & 0x0F, 0x04); + assert_eq!(cpu.state, expected_state); } #[test] @@ -520,8 +619,11 @@ mod execute_tests { cpu.state.d_reg[0] = 0x20; cpu.decoder.instruction = Instruction::CMP(Target::Immediate(0x30), Target::DirectDReg(0), Size::Byte); + let mut expected_state = cpu.state.clone(); + expected_state.sr = 0x2709; + cpu.execute_current(&system).unwrap(); - assert_eq!(cpu.state.sr & 0x0F, 0x09); + assert_eq!(cpu.state, expected_state); } #[test] @@ -531,8 +633,11 @@ mod execute_tests { cpu.state.d_reg[0] = 0x20; cpu.decoder.instruction = Instruction::CMP(Target::Immediate(0x10), Target::DirectDReg(0), Size::Byte); + let mut expected_state = cpu.state.clone(); + expected_state.sr = 0x2700; + cpu.execute_current(&system).unwrap(); - assert_eq!(cpu.state.sr & 0x0F, 0x00); + assert_eq!(cpu.state, expected_state); } #[test] @@ -542,8 +647,11 @@ mod execute_tests { cpu.state.sr = 0xA7AA; cpu.decoder.instruction = Instruction::ANDtoSR(0xF8FF); + let mut expected_state = cpu.state.clone(); + expected_state.sr = 0xA0AA; + cpu.execute_current(&system).unwrap(); - assert_eq!(cpu.state.sr, 0xA0AA); + assert_eq!(cpu.state, expected_state); } #[test] @@ -553,8 +661,11 @@ mod execute_tests { cpu.state.sr = 0xA755; cpu.decoder.instruction = Instruction::ORtoSR(0x00AA); + let mut expected_state = cpu.state.clone(); + expected_state.sr = 0xA7FF; + cpu.execute_current(&system).unwrap(); - assert_eq!(cpu.state.sr, 0xA7FF); + assert_eq!(cpu.state, expected_state); } #[test] @@ -565,8 +676,11 @@ mod execute_tests { cpu.state.d_reg[0] = 0x0200; cpu.decoder.instruction = Instruction::MULW(Target::Immediate(value), 0, Sign::Signed); + let mut expected_state = cpu.state.clone(); + expected_state.d_reg[0] = 0x4ec00; + cpu.execute_current(&system).unwrap(); - assert_eq!(cpu.state.d_reg[0], 0x4ec00); + assert_eq!(cpu.state, expected_state); } #[test] @@ -577,8 +691,11 @@ mod execute_tests { cpu.state.d_reg[0] = 0x40000; cpu.decoder.instruction = Instruction::DIVW(Target::Immediate(value), 0, Sign::Unsigned); + let mut expected_state = cpu.state.clone(); + expected_state.d_reg[0] = 0x007101C3; + cpu.execute_current(&system).unwrap(); - assert_eq!(cpu.state.d_reg[0], 0x007101C3); + assert_eq!(cpu.state, expected_state); } #[test] @@ -588,9 +705,12 @@ mod execute_tests { cpu.state.d_reg[0] = 0x01; cpu.decoder.instruction = Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left); + let mut expected_state = cpu.state.clone(); + expected_state.sr = 0x2700; + expected_state.d_reg[0] = 0x00000002; + cpu.execute_current(&system).unwrap(); - assert_eq!(cpu.state.d_reg[0], 0x00000002); - assert_eq!(cpu.state.sr & 0x1F, 0x00); + assert_eq!(cpu.state, expected_state); } #[test] @@ -600,9 +720,12 @@ mod execute_tests { cpu.state.d_reg[0] = 0x81; cpu.decoder.instruction = Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right); + let mut expected_state = cpu.state.clone(); + expected_state.sr = 0x2719; + expected_state.d_reg[0] = 0x000000C0; + cpu.execute_current(&system).unwrap(); - assert_eq!(cpu.state.d_reg[0], 0x000000C0); - assert_eq!(cpu.state.sr & 0x1F, 0x19); + assert_eq!(cpu.state, expected_state); } #[test] @@ -612,9 +735,12 @@ mod execute_tests { cpu.state.d_reg[0] = 0x80; cpu.decoder.instruction = Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left); + let mut expected_state = cpu.state.clone(); + expected_state.sr = 0x2701; + expected_state.d_reg[0] = 0x00000001; + cpu.execute_current(&system).unwrap(); - assert_eq!(cpu.state.d_reg[0], 0x00000001); - assert_eq!(cpu.state.sr & 0x1F, 0x01); + assert_eq!(cpu.state, expected_state); } #[test] @@ -624,9 +750,12 @@ mod execute_tests { cpu.state.d_reg[0] = 0x01; cpu.decoder.instruction = Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right); + let mut expected_state = cpu.state.clone(); + expected_state.sr = 0x2709; + expected_state.d_reg[0] = 0x00000080; + cpu.execute_current(&system).unwrap(); - assert_eq!(cpu.state.d_reg[0], 0x00000080); - assert_eq!(cpu.state.sr & 0x1F, 0x09); + assert_eq!(cpu.state, expected_state); } #[test] @@ -637,9 +766,12 @@ mod execute_tests { cpu.state.sr = 0x2700; cpu.decoder.instruction = Instruction::ROXd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left); + let mut expected_state = cpu.state.clone(); + expected_state.sr = 0x2715; + expected_state.d_reg[0] = 0x00000000; + cpu.execute_current(&system).unwrap(); - assert_eq!(cpu.state.d_reg[0], 0x00000000); - assert_eq!(cpu.state.sr & 0x1F, 0x15); + assert_eq!(cpu.state, expected_state); } #[test] @@ -650,9 +782,12 @@ mod execute_tests { cpu.state.sr = 0x2700; cpu.decoder.instruction = Instruction::ROXd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right); + let mut expected_state = cpu.state.clone(); + expected_state.sr = 0x2715; + expected_state.d_reg[0] = 0x00000000; + cpu.execute_current(&system).unwrap(); - assert_eq!(cpu.state.d_reg[0], 0x00000000); - assert_eq!(cpu.state.sr & 0x1F, 0x15); + assert_eq!(cpu.state, expected_state); } #[test] @@ -663,9 +798,12 @@ mod execute_tests { cpu.state.sr = 0x2700; cpu.decoder.instruction = Instruction::ROXd(Target::Immediate(2), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left); + let mut expected_state = cpu.state.clone(); + expected_state.sr = 0x2700; + expected_state.d_reg[0] = 0x00000001; + cpu.execute_current(&system).unwrap(); - assert_eq!(cpu.state.d_reg[0], 0x00000001); - assert_eq!(cpu.state.sr & 0x1F, 0x00); + assert_eq!(cpu.state, expected_state); } #[test] @@ -676,9 +814,28 @@ mod execute_tests { cpu.state.sr = 0x2700; cpu.decoder.instruction = Instruction::ROXd(Target::Immediate(2), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right); + let mut expected_state = cpu.state.clone(); + expected_state.sr = 0x2708; + expected_state.d_reg[0] = 0x00000080; + cpu.execute_current(&system).unwrap(); - assert_eq!(cpu.state.d_reg[0], 0x00000080); - assert_eq!(cpu.state.sr & 0x1F, 0x08); + assert_eq!(cpu.state, expected_state); + } + + #[test] + fn instruction_neg_word() { + let (mut cpu, system) = init_test(); + + cpu.state.d_reg[0] = 0x80; + cpu.state.sr = 0x2700; + cpu.decoder.instruction = Instruction::NEG(Target::DirectDReg(0), Size::Word); + + let mut expected_state = cpu.state.clone(); + expected_state.sr = 0x2709; + expected_state.d_reg[0] = 0x0000FF80; + + cpu.execute_current(&system).unwrap(); + assert_eq!(cpu.state, expected_state); } diff --git a/src/devices.rs b/src/devices.rs index 136dc63..a4c2032 100644 --- a/src/devices.rs +++ b/src/devices.rs @@ -102,6 +102,13 @@ pub fn write_beu32(value: u32) -> [u8; 4] { ] } +/// A device that can debugged by putting it into debug mode, or setting breakpoints +pub trait Debuggable { + fn enable_debugging(&mut self); + fn add_breakpoint(&mut self, addr: Address); +} + + pub trait Transmutable { fn as_steppable(&mut self) -> Option<&mut dyn Steppable> { None @@ -114,6 +121,10 @@ pub trait Transmutable { fn as_interruptable(&mut self) -> Option<&mut dyn Interruptable> { None } + + fn as_debuggable(&mut self) -> Option<&mut dyn Debuggable> { + None + } } pub type TransmutableBox = Rc>>; diff --git a/todo.txt b/todo.txt index be424be..9636f4c 100644 --- a/todo.txt +++ b/todo.txt @@ -1,15 +1,11 @@ -* should you simulate clock ticks, and only step devices when they next request it - - +* make devices nameable, using a hashmap to store them * can you eventually make the system connections all configurable via a config file? -* make it possible to break out of the current execution, into the debugger, by using a certain keystroke + * make tests for each instruction * unimplemented: ABCD, ADDX, BFFFO, BFINS, BKPT, CHK, EXG, ILLEGAL, MOVEfromCCR, MOVEP, RTR, RTD, SBCD, SUBX -* undecoded: ADDX, SUBX -* modify execution for >=MC68020: MOVEM * >=MC68020 undecoded & unimplemented: CALLM, CAS, CAS2, CHK2, CMP2, RTM, PACK, TRAPcc, UNPK * add support for MMU