mirror of
https://github.com/transistorfet/moa.git
synced 2024-11-25 15:33:08 +00:00
Added Debuggable trait and added tests
This commit is contained in:
parent
c980c2f56d
commit
1ad7ad1807
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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<RefCell<Box<dyn Transmutable>>>;
|
||||
|
8
todo.txt
8
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
|
||||
|
Loading…
Reference in New Issue
Block a user