Reorganized m68k tests

This commit is contained in:
transistor 2023-03-25 21:27:02 -07:00
parent bc4f63baf3
commit 099d557a3f
10 changed files with 2702 additions and 971 deletions

View File

@ -201,7 +201,6 @@ impl M68kAssembler {
fn convert_sized_instruction(&mut self, lineno: usize, mneumonic: &str, args: &[AssemblyOperand]) -> Result<(), Error> {
let operation_size = get_size_from_mneumonic(mneumonic).ok_or_else(|| Error::new(&format!("error at line {}: expected a size specifier (b/w/l)", lineno)));
match &mneumonic[..mneumonic.len() - 1] {
"addi" => {
self.convert_common_immediate_instruction(lineno, 0x0600, args, operation_size?, Disallow::NoARegImmediateOrPC)?;
},
@ -317,18 +316,21 @@ impl M68kAssembler {
}
fn convert_common_dreg_instruction(&mut self, lineno: usize, opcode: u16, args: &[AssemblyOperand], operation_size: Size, disallow: Disallow) -> Result<(), Error> {
self.convert_common_reg_instruction(lineno, opcode, args, operation_size, disallow, Disallow::NoAReg)
parser::expect_args(lineno, args, 2)?;
let (direction, reg, operand) = convert_reg_and_other(lineno, args, Disallow::NoAReg)?;
let (effective_address, additional_words) = convert_target(lineno, operand, operation_size, disallow)?;
self.output.push(opcode | encode_size(operation_size) | direction | (reg << 9) | effective_address);
self.output.extend(additional_words);
Ok(())
}
fn convert_common_areg_instruction(&mut self, lineno: usize, opcode: u16, args: &[AssemblyOperand], operation_size: Size, disallow: Disallow) -> Result<(), Error> {
self.convert_common_reg_instruction(lineno, opcode, args, operation_size, disallow, Disallow::NoDReg)
}
fn convert_common_reg_instruction(&mut self, lineno: usize, opcode: u16, args: &[AssemblyOperand], operation_size: Size, disallow: Disallow, disallow_reg: Disallow) -> Result<(), Error> {
let size_bit = expect_a_instruction_size(lineno, operation_size)?;
parser::expect_args(lineno, args, 2)?;
let (direction, reg, operand) = convert_reg_and_other(lineno, args, disallow_reg)?;
let (effective_address, additional_words) = convert_target(lineno, operand, operation_size, disallow)?;
self.output.push(opcode | encode_size(operation_size) | direction | (reg << 9) | effective_address);
//let (_direction, reg, operand) = convert_reg_and_other(lineno, args, Disallow::NoDReg)?;
let reg = expect_address_register(lineno, &args[1])?;
let (effective_address, additional_words) = convert_target(lineno, &args[0], operation_size, disallow)?;
self.output.push(opcode | size_bit | (0b11 << 6) | (reg << 9) | effective_address);
self.output.extend(additional_words);
Ok(())
}
@ -549,7 +551,7 @@ fn expect_data_register(lineno: usize, operand: &AssemblyOperand) -> Result<u16,
fn expect_address_register(lineno: usize, operand: &AssemblyOperand) -> Result<u16, Error> {
if let AssemblyOperand::Register(name) = operand {
if name.starts_with('d') {
if name.starts_with('a') {
return expect_reg_num(lineno, name);
}
}
@ -572,6 +574,14 @@ fn expect_reg_num(lineno: usize, name: &str) -> Result<u16, Error> {
Err(Error::new(&format!("error at line {}: no such register {:?}", lineno, name)))
}
fn expect_a_instruction_size(lineno: usize, size: Size) -> Result<u16, Error> {
match size {
Size::Word => Ok(0),
Size::Long => Ok(0b1 << 8),
_ => Err(Error::new(&format!("error at line {}: address instructions can only be word or long size", lineno))),
}
}
fn get_size_from_mneumonic(s: &str) -> Option<Size> {
let size_ch = s.chars().last()?;

View File

@ -424,7 +424,7 @@ impl M68kDecoder {
}
#[inline]
fn decode_group_moveq(&mut self, memory: &mut dyn Addressable, ins: u16) -> Result<Instruction, Error> {
fn decode_group_moveq(&mut self, _memory: &mut dyn Addressable, ins: u16) -> Result<Instruction, Error> {
if (ins & 0x0100) != 0 {
return Err(Error::processor(Exceptions::IllegalInstruction as u32));
}
@ -731,7 +731,7 @@ impl M68kDecoder {
}
}
fn get_mode_as_target(&mut self, memory: &mut dyn Addressable, mode: u8, reg: u8, size: Option<Size>) -> Result<Target, Error> {
pub(super) fn get_mode_as_target(&mut self, memory: &mut dyn Addressable, mode: u8, reg: u8, size: Option<Size>) -> Result<Target, Error> {
let value = match mode {
0b000 => Target::DirectDReg(reg),
0b001 => Target::DirectAReg(reg),

View File

@ -1399,7 +1399,7 @@ impl M68k {
}
fn get_target_value(&mut self, target: Target, size: Size, used: Used) -> Result<u32, Error> {
pub(super) fn get_target_value(&mut self, target: Target, size: Size, used: Used) -> Result<u32, Error> {
match target {
Target::Immediate(value) => Ok(value),
Target::DirectDReg(reg) => Ok(get_value_sized(self.state.d_reg[reg as usize], size)),
@ -1439,7 +1439,7 @@ impl M68k {
}
}
fn set_target_value(&mut self, target: Target, value: u32, size: Size, used: Used) -> Result<(), Error> {
pub(super) fn set_target_value(&mut self, target: Target, value: u32, size: Size, used: Used) -> Result<(), Error> {
match target {
Target::DirectDReg(reg) => {
set_value_sized(&mut self.state.d_reg[reg as usize], value, size);

View File

@ -7,7 +7,6 @@ pub mod debugger;
pub mod instructions;
pub mod timing;
pub mod tests;
//pub mod testcases;
pub use self::state::{M68k, M68kType};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,195 @@
use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, wrap_transmutable};
use moa_m68k::{M68k, M68kType};
use moa_m68k::instructions::{Instruction, Target, Size, Sign, XRegister, BaseRegister, IndexRegister, Direction, ShiftDirection};
use moa_m68k::assembler::M68kAssembler;
const INIT_STACK: Address = 0x00002000;
const INIT_ADDR: Address = 0x00000010;
struct TestCase {
cpu: M68kType,
data: &'static [u16],
ins: Option<Instruction>,
}
const DECODE_TESTS: &'static [TestCase] = &[
// MC68000
TestCase { cpu: M68kType::MC68000, data: &[0x4e71], ins: Some(Instruction::NOP) },
// TODO I think this one is illegal (which is causing problems for the assembler)
//TestCase { cpu: M68kType::MC68000, data: &[0x0008, 0x00FF], ins: Some(Instruction::OR(Target::Immediate(0xFF), Target::DirectAReg(0), Size::Byte)) },
TestCase { cpu: M68kType::MC68000, data: &[0x003C, 0x00FF], ins: Some(Instruction::ORtoCCR(0xFF)) },
TestCase { cpu: M68kType::MC68000, data: &[0x007C, 0x1234], ins: Some(Instruction::ORtoSR(0x1234)) },
TestCase { cpu: M68kType::MC68000, data: &[0x0263, 0x1234], ins: Some(Instruction::AND(Target::Immediate(0x1234), Target::IndirectARegDec(3), Size::Word)) },
TestCase { cpu: M68kType::MC68000, data: &[0x0240, 0x1234], ins: Some(Instruction::AND(Target::Immediate(0x1234), Target::DirectDReg(0), Size::Word)) },
TestCase { cpu: M68kType::MC68000, data: &[0x02A3, 0x1234, 0x5678], ins: Some(Instruction::AND(Target::Immediate(0x12345678), Target::IndirectARegDec(3), Size::Long)) },
TestCase { cpu: M68kType::MC68000, data: &[0x0280, 0x1234, 0x5678], ins: Some(Instruction::AND(Target::Immediate(0x12345678), Target::DirectDReg(0), Size::Long)) },
TestCase { cpu: M68kType::MC68000, data: &[0x023C, 0x1234], ins: Some(Instruction::ANDtoCCR(0x34)) },
TestCase { cpu: M68kType::MC68000, data: &[0x027C, 0xF8FF], ins: Some(Instruction::ANDtoSR(0xF8FF)) },
TestCase { cpu: M68kType::MC68000, data: &[0x4240], ins: Some(Instruction::CLR(Target::DirectDReg(0), Size::Word)) },
TestCase { cpu: M68kType::MC68000, data: &[0x4280], ins: Some(Instruction::CLR(Target::DirectDReg(0), Size::Long)) },
TestCase { cpu: M68kType::MC68000, data: &[0x4250], ins: Some(Instruction::CLR(Target::IndirectAReg(0), Size::Word)) },
TestCase { cpu: M68kType::MC68000, data: &[0x4290], ins: Some(Instruction::CLR(Target::IndirectAReg(0), Size::Long)) },
TestCase { cpu: M68kType::MC68000, data: &[0x0487, 0x1234, 0x5678], ins: Some(Instruction::SUB(Target::Immediate(0x12345678), Target::DirectDReg(7), Size::Long)) },
TestCase { cpu: M68kType::MC68000, data: &[0x063A, 0x1234, 0x0055], ins: Some(Instruction::ADD(Target::Immediate(0x34), Target::IndirectRegOffset(BaseRegister::PC, None, 0x55), Size::Byte)) },
TestCase { cpu: M68kType::MC68000, data: &[0x0A23, 0x1234], ins: Some(Instruction::EOR(Target::Immediate(0x34), Target::IndirectARegDec(3), Size::Byte)) },
TestCase { cpu: M68kType::MC68000, data: &[0x0A3C, 0x1234], ins: Some(Instruction::EORtoCCR(0x34)) },
TestCase { cpu: M68kType::MC68000, data: &[0x0A7C, 0xF8FF], ins: Some(Instruction::EORtoSR(0xF8FF)) },
TestCase { cpu: M68kType::MC68000, data: &[0x0C00, 0x0020], ins: Some(Instruction::CMP(Target::Immediate(0x20), Target::DirectDReg(0), Size::Byte)) },
TestCase { cpu: M68kType::MC68000, data: &[0x0C00, 0x0030], ins: Some(Instruction::CMP(Target::Immediate(0x30), Target::DirectDReg(0), Size::Byte)) },
TestCase { cpu: M68kType::MC68000, data: &[0x0C00, 0x0010], ins: Some(Instruction::CMP(Target::Immediate(0x10), Target::DirectDReg(0), Size::Byte)) },
TestCase { cpu: M68kType::MC68000, data: &[0x81FC, 0x0003], ins: Some(Instruction::DIVW(Target::Immediate(3), 0, Sign::Signed)) },
TestCase { cpu: M68kType::MC68000, data: &[0xC1FC, 0x0276], ins: Some(Instruction::MULW(Target::Immediate(0x276), 0, Sign::Signed)) },
TestCase { cpu: M68kType::MC68000, data: &[0xCDC5], ins: Some(Instruction::MULW(Target::DirectDReg(5), 6, Sign::Signed)) },
TestCase { cpu: M68kType::MC68000, data: &[0x0108, 0x1234], ins: Some(Instruction::MOVEP(0, 0, 0x1234, Size::Word, Direction::FromTarget)) },
TestCase { cpu: M68kType::MC68000, data: &[0x0148, 0x1234], ins: Some(Instruction::MOVEP(0, 0, 0x1234, Size::Long, Direction::FromTarget)) },
TestCase { cpu: M68kType::MC68000, data: &[0x0188, 0x1234], ins: Some(Instruction::MOVEP(0, 0, 0x1234, Size::Word, Direction::ToTarget)) },
TestCase { cpu: M68kType::MC68000, data: &[0x01C8, 0x1234], ins: Some(Instruction::MOVEP(0, 0, 0x1234, Size::Long, Direction::ToTarget)) },
TestCase { cpu: M68kType::MC68000, data: &[0xE300], ins: Some(Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left)) },
TestCase { cpu: M68kType::MC68000, data: &[0xE200], ins: Some(Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right)) },
TestCase { cpu: M68kType::MC68000, data: &[0xE318], ins: Some(Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left)) },
TestCase { cpu: M68kType::MC68000, data: &[0xE218], ins: Some(Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right)) },
TestCase { cpu: M68kType::MC68000, data: &[0xA000], ins: Some(Instruction::UnimplementedA(0xA000)) },
TestCase { cpu: M68kType::MC68000, data: &[0xFFFF], ins: Some(Instruction::UnimplementedF(0xFFFF)) },
// MC68030
TestCase { cpu: M68kType::MC68030, data: &[0x4C3C, 0x0800, 0x0000, 0x0097], ins: Some(Instruction::MULL(Target::Immediate(0x97), None, 0, Sign::Signed)) },
TestCase { cpu: M68kType::MC68030, data: &[0x21BC, 0x0010, 0x14C4, 0x09B0, 0x0010, 0xDF40], ins: Some(Instruction::MOVE(Target::Immediate(1053892), Target::IndirectRegOffset(BaseRegister::None, Some(IndexRegister { xreg: XRegister::DReg(0), scale: 0, size: Size::Long }), 0x10df40), Size::Long)) },
// Should Fail
];
fn init_decode_test(cputype: M68kType) -> (M68k, System) {
let mut system = System::default();
// Insert basic initialization
let data = vec![0; 0x00100000];
let mem = MemoryBlock::new(data);
system.add_addressable_device(0x00000000, wrap_transmutable(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 port = if cputype <= M68kType::MC68010 {
BusPort::new(0, 24, 16, system.bus.clone())
} else {
BusPort::new(0, 24, 16, system.bus.clone())
};
let mut cpu = M68k::new(cputype, 10_000_000, port);
cpu.init().unwrap();
assert_eq!(cpu.state.pc, INIT_ADDR as u32);
assert_eq!(cpu.state.ssp, INIT_STACK as u32);
cpu.decoder.init(INIT_ADDR as u32);
assert_eq!(cpu.decoder.start, INIT_ADDR as u32);
assert_eq!(cpu.decoder.instruction, Instruction::NOP);
(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 run_decode_test(case: &TestCase) {
let (mut cpu, system) = init_decode_test(case.cpu);
load_memory(&system, case.data);
match &case.ins {
Some(ins) => {
cpu.decode_next().unwrap();
assert_eq!(cpu.decoder.instruction, ins.clone());
},
None => {
let next = cpu.decode_next();
println!("{:?}", cpu.decoder.instruction);
assert!(next.is_err());
},
}
}
#[test]
pub fn run_decode_tests() {
for case in DECODE_TESTS {
println!("Testing for {:?}", case.ins);
run_decode_test(case);
}
}
#[test]
pub fn run_assembler_tests() {
let mut tests = 0;
let mut errors = 0;
for case in DECODE_TESTS {
if case.ins.is_some() {
tests += 1;
let assembly_text = format!("{}", case.ins.as_ref().unwrap());
print!("Testing assembling of {:?} ", assembly_text);
let mut assembler = M68kAssembler::new(M68kType::MC68000);
match assembler.assemble_words(&assembly_text) {
Ok(data) => {
if data == case.data {
print!("pass");
} else {
errors += 1;
print!("FAILED");
print!("\nleft: {:?}, right: {:?}", data, case.data);
}
println!();
},
Err(err) => {
println!("FAILED\n{:?}", err);
errors += 1;
},
}
}
}
if errors > 0 {
panic!("{} errors out of {} tests", errors, tests);
}
}
/*
#[test]
pub fn run_assembler_opcode_tests() {
let mut tests = 0;
let mut errors = 0;
use super::super::testcases::{TimingCase, TIMING_TESTS};
for case in TIMING_TESTS {
tests += 1;
let assembly_text = format!("{}", case.ins);
print!("Testing assembling of {:?} from {:?}", assembly_text, case.ins);
let mut assembler = M68kAssembler::new(M68kType::MC68000);
match assembler.assemble_words(&assembly_text) {
Ok(data) => {
if data[0] == case.data[0] {
print!("pass");
} else {
errors += 1;
print!("FAILED");
print!("\nleft: {:#06x}, right: {:#06x}", data[0], case.data[0]);
}
println!();
},
Err(err) => {
println!("FAILED\n{:?}", err);
errors += 1;
},
}
}
if errors > 0 {
panic!("{} errors out of {} tests", errors, tests);
}
}
*/

View File

@ -0,0 +1,679 @@
use moa_core::{System, MemoryBlock, BusPort, Address, Addressable, Steppable, wrap_transmutable};
use moa_m68k::{M68k, M68kType};
use moa_m68k::state::M68kState;
use moa_m68k::instructions::{Instruction, Target, Size, Sign, ShiftDirection, Direction, Condition};
const INIT_STACK: Address = 0x00002000;
const INIT_ADDR: Address = 0x00000010;
const MEM_ADDR: u32 = 0x00001234;
struct TestState {
pc: u32,
ssp: u32,
usp: u32,
d0: u32,
d1: u32,
a0: u32,
a1: u32,
sr: u16,
mem: u32,
}
struct TestCase {
name: &'static str,
ins: Instruction,
data: &'static [u16],
cputype: M68kType,
init: TestState,
fini: TestState,
}
fn init_execute_test(cputype: M68kType) -> (M68k, System) {
let mut system = System::default();
// Insert basic initialization
let data = vec![0; 0x00100000];
let mem = MemoryBlock::new(data);
system.add_addressable_device(0x00000000, wrap_transmutable(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 port = if cputype <= M68kType::MC68010 {
BusPort::new(0, 24, 16, system.bus.clone())
} else {
BusPort::new(0, 24, 16, system.bus.clone())
};
let mut cpu = M68k::new(cputype, 10_000_000, port);
cpu.step(&system).unwrap();
cpu.decoder.init(cpu.state.pc);
assert_eq!(cpu.state.pc, INIT_ADDR as u32);
assert_eq!(cpu.state.ssp, INIT_STACK as u32);
assert_eq!(cpu.decoder.instruction, Instruction::NOP);
(cpu, system)
}
fn build_state(state: &TestState) -> M68kState {
let mut new_state = M68kState::default();
new_state.pc = state.pc;
new_state.ssp = state.ssp;
new_state.usp = state.usp;
new_state.d_reg[0] = state.d0;
new_state.d_reg[1] = state.d1;
new_state.a_reg[0] = state.a0;
new_state.a_reg[1] = state.a1;
new_state.sr = state.sr;
new_state
}
fn load_memory(system: &System, data: &[u16]) {
for i in 0..data.len() {
system.get_bus().write_beu16((i << 1) as Address, data[i]).unwrap();
}
}
fn run_test(case: &TestCase) {
let (mut cpu, system) = init_execute_test(case.cputype);
let init_state = build_state(&case.init);
let mut expected_state = build_state(&case.fini);
system.get_bus().write_beu32(MEM_ADDR as Address, case.init.mem).unwrap();
load_memory(&system, case.data);
cpu.state = init_state;
cpu.decode_next().unwrap();
assert_eq!(cpu.decoder.instruction, case.ins);
cpu.execute_current().unwrap();
expected_state.request = cpu.state.request.clone();
assert_eq!(cpu.state, expected_state);
let mem = system.get_bus().read_beu32(MEM_ADDR as Address).unwrap();
assert_eq!(mem, case.fini.mem);
}
#[test]
pub fn run_execute_tests() {
for case in TEST_CASES {
println!("Running test {}", case.name);
run_test(case);
}
}
#[test]
pub fn run_assembler_tests() {
use moa_m68k::assembler::M68kAssembler;
let mut tests = 0;
let mut errors = 0;
for case in TEST_CASES {
tests += 1;
let assembly_text = format!("{}", case.ins);
print!("Testing assembling of {:?} ", assembly_text);
let mut assembler = M68kAssembler::new(M68kType::MC68000);
match assembler.assemble_words(&assembly_text) {
Ok(data) => {
if data == case.data {
print!("pass");
} else {
errors += 1;
print!("FAILED");
print!("\ngot: [{}], but expected: [{}]", format_hex(&data), format_hex(case.data));
}
println!();
},
Err(err) => {
println!("FAILED\n{:?}", err);
errors += 1;
},
}
}
if errors > 0 {
panic!("{} errors out of {} tests", errors, tests);
}
}
fn format_hex(data: &[u16]) -> String {
data.iter()
.map(|word| format!("{:#06x}", word))
.collect::<Vec<String>>()
.join(", ")
}
const TEST_CASES: &'static [TestCase] = &[
TestCase {
name: "nop",
ins: Instruction::NOP,
data: &[ 0x4e71 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
},
TestCase {
name: "addi with no overflow or carry",
ins: Instruction::ADD(Target::Immediate(0x7f), Target::DirectDReg(0), Size::Byte),
data: &[ 0x0600, 0x007F ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x0000007f, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
},
TestCase {
name: "addi with no overflow but negative",
ins: Instruction::ADD(Target::Immediate(0x80), Target::DirectDReg(0), Size::Byte),
data: &[ 0x0600, 0x0080 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000001, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000081, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2708, mem: 0x00000000 },
},
TestCase {
name: "addi with overflow",
ins: Instruction::ADD(Target::Immediate(0x7f), Target::DirectDReg(0), Size::Byte),
data: &[ 0x0600, 0x007F ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000001, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000080, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x270A, mem: 0x00000000 },
},
TestCase {
name: "addi with carry",
ins: Instruction::ADD(Target::Immediate(0x80), Target::DirectDReg(0), Size::Byte),
data: &[ 0x0600, 0x0080 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000080, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2717, mem: 0x00000000 },
},
TestCase {
name: "adda immediate",
ins: Instruction::ADDA(Target::Immediate(0xF800), 0, Size::Word),
data: &[ 0xD0FC, 0xF800 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x27FF, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0xFFFFF800, a1: 0x00000000, sr: 0x27FF, mem: 0x00000000 },
},
TestCase {
name: "adda register",
ins: Instruction::ADDA(Target::DirectDReg(0), 0, Size::Word),
data: &[ 0xD0C0 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x0000F800, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x27FF, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x0000F800, d1: 0x00000000, a0: 0xFFFFF800, a1: 0x00000000, sr: 0x27FF, mem: 0x00000000 },
},
TestCase {
name: "addx",
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: 0x2700, mem: 0x00000000 },
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",
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: 0x2710, 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",
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: 0x2715, mem: 0x00000000 },
},
TestCase {
name: "andi with sr",
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: 0xA7AA, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0xA0AA, mem: 0x00000000 },
},
TestCase {
name: "asl",
ins: Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left),
data: &[ 0xE300 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000001, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000002, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
},
TestCase {
name: "asr",
ins: Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right),
data: &[ 0xE200 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000081, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x000000C0, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2719, mem: 0x00000000 },
},
TestCase {
name: "blt with jump",
ins: Instruction::Bcc(Condition::LessThan, 8),
data: &[ 0x6D08 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2709, mem: 0x00000000 },
fini: TestState { pc: 0x0000000A, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2709, mem: 0x00000000 },
},
TestCase {
name: "blt with jump",
ins: Instruction::Bcc(Condition::LessThan, 8),
data: &[ 0x6D08 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
},
TestCase {
name: "bchg not zero",
ins: Instruction::BCHG(Target::Immediate(7), Target::DirectDReg(1), Size::Long),
data: &[ 0x0841, 0x0007 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x000000FF, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
},
TestCase {
name: "bchg zero",
ins: Instruction::BCHG(Target::Immediate(7), Target::DirectDReg(1), Size::Long),
data: &[ 0x0841, 0x0007 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000080, a0: 0x00000000, a1: 0x00000000, sr: 0x2704, mem: 0x00000000 },
},
TestCase {
name: "bra 8-bit",
ins: Instruction::BRA(-32),
data: &[ 0x60E0 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0xFFFFFFE2, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
},
TestCase {
name: "cmpi equal",
ins: Instruction::CMP(Target::Immediate(0x20), Target::DirectDReg(0), Size::Byte),
data: &[ 0x0C00, 0x0020 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000020, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000020, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2704, mem: 0x00000000 },
},
TestCase {
name: "cmpi greater than",
ins: Instruction::CMP(Target::Immediate(0x30), Target::DirectDReg(0), Size::Byte),
data: &[ 0x0C00, 0x0030 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000020, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000020, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2709, mem: 0x00000000 },
},
TestCase {
name: "cmpi less than",
ins: Instruction::CMP(Target::Immediate(0x10), Target::DirectDReg(0), Size::Byte),
data: &[ 0x0C00, 0x0010 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000020, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000020, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
},
TestCase {
name: "cmpi no overflow",
ins: Instruction::CMP(Target::Immediate(0x7F), Target::DirectDReg(0), Size::Byte),
data: &[ 0x0C00, 0x007F ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2709, mem: 0x00000000 },
},
TestCase {
name: "cmpi no overflow, already negative",
ins: Instruction::CMP(Target::Immediate(0x8001), Target::DirectDReg(0), Size::Word),
data: &[ 0x0C40, 0x8001 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2701, mem: 0x00000000 },
},
TestCase {
name: "cmpi with overflow",
ins: Instruction::CMP(Target::Immediate(0x80), Target::DirectDReg(0), Size::Byte),
data: &[ 0x0C00, 0x0080 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x270B, mem: 0x00000000 },
},
TestCase {
name: "cmpi with overflow 2",
ins: Instruction::CMP(Target::Immediate(0x8001), Target::DirectDReg(0), Size::Word),
data: &[ 0x0C40, 0x8001 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000001, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000001, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x270B, mem: 0x00000000 },
},
TestCase {
name: "cmpi no carry",
ins: Instruction::CMP(Target::Immediate(0x01), Target::DirectDReg(0), Size::Byte),
data: &[ 0x0C00, 0x0001 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x000000FF, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x000000FF, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2708, mem: 0x00000000 },
},
TestCase {
name: "cmpi with carry",
ins: Instruction::CMP(Target::Immediate(0xFF), Target::DirectDReg(0), Size::Byte),
data: &[ 0x0C00, 0x00FF ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000001, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000001, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2701, mem: 0x00000000 },
},
TestCase {
name: "divu",
ins: Instruction::DIVW(Target::Immediate(0x0245), 0, Sign::Unsigned),
data: &[ 0x80FC, 0x0245 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00040000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x007101C3, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
},
TestCase {
name: "divs",
ins: Instruction::DIVW(Target::Immediate(48), 0, Sign::Signed),
data: &[ 0x81FC, 0x0030 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0xFFFFEB00, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x0000FF90, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2708, mem: 0x00000000 },
},
TestCase {
name: "eori",
ins: Instruction::EOR(Target::DirectDReg(1), Target::DirectDReg(0), Size::Long),
data: &[ 0xB380 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0xAAAA5555, d1: 0x55AA55AA, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0xFF0000FF, d1: 0x55AA55AA, a0: 0x00000000, a1: 0x00000000, sr: 0x2708, mem: 0x00000000 },
},
TestCase {
name: "exg",
ins: Instruction::EXG(Target::DirectDReg(0), Target::DirectAReg(1)),
data: &[ 0xC189 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x12345678, d1: 0x00000000, a0: 0x00000000, a1: 0x87654321, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x87654321, d1: 0x00000000, a0: 0x00000000, a1: 0x12345678, sr: 0x2700, mem: 0x00000000 },
},
TestCase {
name: "ext",
ins: Instruction::EXT(0, Size::Byte, Size::Word),
data: &[ 0x4880 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x000000CB, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x27FF, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x0000FFCB, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x27F8, mem: 0x00000000 },
},
TestCase {
name: "ext",
ins: Instruction::EXT(0, Size::Word, Size::Long),
data: &[ 0x48C0 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x000000CB, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x27FF, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x000000CB, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x27F0, mem: 0x00000000 },
},
TestCase {
name: "lsl",
ins: Instruction::LSd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left),
data: &[ 0xE308 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000001, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x271F, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000002, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
},
TestCase {
name: "lsl with bit out",
ins: Instruction::LSd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left),
data: &[ 0xE308 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000081, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000002, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2711, mem: 0x00000000 },
},
TestCase {
name: "lsr",
ins: Instruction::LSd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right),
data: &[ 0xE208 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000081, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000040, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2711, mem: 0x00000000 },
},
TestCase {
name: "muls",
ins: Instruction::MULW(Target::Immediate(0x0276), 0, Sign::Signed),
data: &[ 0xC1FC, 0x0276 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000200, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x0004ec00, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
},
TestCase {
name: "movel",
ins: Instruction::MOVE(Target::DirectDReg(0), Target::DirectDReg(1), Size::Long),
data: &[ 0x2200 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0xFEDCBA98, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0xFEDCBA98, d1: 0xFEDCBA98, a0: 0x00000000, a1: 0x00000000, sr: 0x2708, mem: 0x00000000 },
},
TestCase {
name: "movea",
ins: Instruction::MOVEA(Target::DirectDReg(0), 0, Size::Long),
data: &[ 0x2040 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0xFEDCBA98, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x27FF, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0xFEDCBA98, d1: 0x00000000, a0: 0xFEDCBA98, a1: 0x00000000, sr: 0x27FF, mem: 0x00000000 },
},
// MOVEM
TestCase {
name: "movem word to target",
ins: Instruction::MOVEM(Target::IndirectAReg(0), Size::Word, Direction::ToTarget, 0x0003),
data: &[ 0x4890, 0x0003 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0xABCD1234, d1: 0xEFEF5678, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0xABCD1234, d1: 0xEFEF5678, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0x12345678 },
},
TestCase {
name: "movem long to target",
ins: Instruction::MOVEM(Target::IndirectAReg(0), Size::Long, Direction::ToTarget, 0x0001),
data: &[ 0x48D0, 0x0001 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0xABCD1234, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0xABCD1234, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0xABCD1234 },
},
TestCase {
name: "movem long from target",
ins: Instruction::MOVEM(Target::IndirectAReg(0), Size::Long, Direction::FromTarget, 0x0001),
data: &[ 0x4CD0, 0x0001 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0xABCD1234 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0xABCD1234, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0xABCD1234 },
},
TestCase {
name: "movem word from target inc",
ins: Instruction::MOVEM(Target::IndirectARegInc(0), Size::Word, Direction::FromTarget, 0x0001),
data: &[ 0x4C98, 0x0001 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0xFFFFFFFF, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0xABCD1234 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0xFFFFABCD, d1: 0x00000000, a0: MEM_ADDR+2, a1: 0x00000000, sr: 0x27FF, mem: 0xABCD1234 },
},
TestCase {
name: "movem long to target dec",
ins: Instruction::MOVEM(Target::IndirectARegDec(0), Size::Long, Direction::ToTarget, 0x8000),
data: &[ 0x48E0, 0x8000 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0xABCD1234, d1: 0x00000000, a0: MEM_ADDR+4, a1: 0x00000000, sr: 0x27FF, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0xABCD1234, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0xABCD1234 },
},
// MOVEP
TestCase {
name: "movep word to even memory",
ins: Instruction::MOVEP(0, 0, 0, Size::Word, Direction::ToTarget),
data: &[ 0x0188, 0x0000 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x000055AA, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0xFFFFFFFF },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x000055AA, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0x55FFAAFF },
},
TestCase {
name: "movep word to odd memory",
ins: Instruction::MOVEP(0, 0, 1, Size::Word, Direction::ToTarget),
data: &[ 0x0188, 0x0001 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x000055AA, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0xFFFFFFFF },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x000055AA, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0xFF55FFAA },
},
TestCase {
name: "movep long to even memory upper",
ins: Instruction::MOVEP(0, 0, 0, Size::Long, Direction::ToTarget),
data: &[ 0x01C8, 0x0000 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0xAABBCCDD, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0xFFFFFFFF },
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 to even memory lower",
ins: Instruction::MOVEP(0, 0, 0, Size::Long, Direction::ToTarget),
data: &[ 0x01C8, 0x0000 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0xAABBCCDD, d1: 0x00000000, a0: MEM_ADDR-4, a1: 0x00000000, sr: 0x27FF, mem: 0xFFFFFFFF },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0xAABBCCDD, d1: 0x00000000, a0: MEM_ADDR-4, a1: 0x00000000, sr: 0x27FF, mem: 0xCCFFDDFF },
},
TestCase {
name: "movep word from even memory",
ins: Instruction::MOVEP(0, 0, 0, Size::Word, Direction::FromTarget),
data: &[ 0x0108, 0x0000 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0x55FFAAFF },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x000055AA, d1: 0x00000000, a0: MEM_ADDR, a1: 0x00000000, sr: 0x27FF, mem: 0x55FFAAFF },
},
TestCase {
name: "movep word from odd memory",
ins: Instruction::MOVEP(0, 0, 1, Size::Word, Direction::FromTarget),
data: &[ 0x0108, 0x0001 ],
cputype: M68kType::MC68010,
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 },
},
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 },
},
TestCase {
name: "movep long from even memory lower",
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-4, a1: 0x00000000, sr: 0x27FF, mem: 0xCCFFDDFF },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x0000CCDD, d1: 0x00000000, a0: MEM_ADDR-4, a1: 0x00000000, sr: 0x27FF, mem: 0xCCFFDDFF },
},
// NEG
TestCase {
name: "neg",
ins: Instruction::NEG(Target::DirectDReg(0), Size::Word),
data: &[ 0x4440 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000080, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x0000FF80, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2719, mem: 0x00000000 },
},
TestCase {
name: "ori",
ins: Instruction::OR(Target::Immediate(0xFF), Target::DirectAReg(0), Size::Byte),
data: &[ 0x0008, 0x00FF ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000004, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x000000FF, a1: 0x00000000, sr: 0x2708, mem: 0x00000000 },
},
TestCase {
name: "ori with sr",
ins: Instruction::ORtoSR(0x00AA),
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 },
},
TestCase {
name: "rol",
ins: Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left),
data: &[ 0xE318 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000080, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000001, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2701, mem: 0x00000000 },
},
TestCase {
name: "ror",
ins: Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right),
data: &[ 0xE218 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000001, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000080, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2709, mem: 0x00000000 },
},
TestCase {
name: "roxl",
ins: Instruction::ROXd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left),
data: &[ 0xE310 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000080, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2715, mem: 0x00000000 },
},
TestCase {
name: "roxr",
ins: Instruction::ROXd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right),
data: &[ 0xE210 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000001, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2715, mem: 0x00000000 },
},
TestCase {
name: "roxl two bits",
ins: Instruction::ROXd(Target::Immediate(2), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left),
data: &[ 0xE510 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000080, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000001, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
},
TestCase {
name: "roxr two bits",
ins: Instruction::ROXd(Target::Immediate(2), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right),
data: &[ 0xE410 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000001, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000080, d1: 0x00000000, a0: 0x00000000, a1: 0x00000000, sr: 0x2708, mem: 0x00000000 },
},
TestCase {
name: "subx",
ins: Instruction::SUBX(Target::DirectDReg(1), Target::DirectDReg(0), Size::Byte),
data: &[ 0x9101 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x000000FF, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x2700, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000080, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x2708, mem: 0x00000000 },
},
TestCase {
name: "subx with extend",
ins: Instruction::SUBX(Target::DirectDReg(1), Target::DirectDReg(0), Size::Byte),
data: &[ 0x9101 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x000000FF, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x2710, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x0000007F, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x2702, mem: 0x00000000 },
},
TestCase {
name: "subx with extend and carry",
ins: Instruction::SUBX(Target::DirectDReg(1), Target::DirectDReg(0), Size::Byte),
data: &[ 0x9101 ],
cputype: M68kType::MC68010,
init: TestState { pc: 0x00000000, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000000, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x2710, mem: 0x00000000 },
fini: TestState { pc: 0x00000002, ssp: 0x00000000, usp: 0x00000000, d0: 0x00000080, d1: 0x0000007F, a0: 0x00000000, a1: 0x00000000, sr: 0x2719, mem: 0x00000000 },
},
];

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,104 @@
use moa_core::{System, Error, MemoryBlock, BusPort, Address, Addressable, wrap_transmutable};
use moa_m68k::{M68k, M68kType};
use moa_m68k::instructions::{Instruction, Target, Size};
use moa_m68k::timing::M68kInstructionTiming;
const INIT_STACK: Address = 0x00002000;
const INIT_ADDR: Address = 0x00000010;
struct TimingCase {
cpu: M68kType,
data: &'static [u16],
timing: (u16, u16, u16),
ins: Instruction,
}
const TIMING_TESTS: &'static [TimingCase] = &[
TimingCase { cpu: M68kType::MC68000, data: &[0xD090], timing: ( 14, 14, 6), ins: Instruction::ADD(Target::IndirectAReg(0), Target::DirectDReg(0), Size::Long) },
];
fn init_decode_test(cputype: M68kType) -> (M68k, System) {
let mut system = System::default();
// Insert basic initialization
let data = vec![0; 0x00100000];
let mem = MemoryBlock::new(data);
system.add_addressable_device(0x00000000, wrap_transmutable(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 port = if cputype <= M68kType::MC68010 {
BusPort::new(0, 24, 16, system.bus.clone())
} else {
BusPort::new(0, 24, 16, system.bus.clone())
};
let mut cpu = M68k::new(cputype, 10_000_000, port);
cpu.init().unwrap();
assert_eq!(cpu.state.pc, INIT_ADDR as u32);
assert_eq!(cpu.state.ssp, INIT_STACK as u32);
cpu.decoder.init(INIT_ADDR as u32);
assert_eq!(cpu.decoder.start, INIT_ADDR as u32);
assert_eq!(cpu.decoder.instruction, Instruction::NOP);
(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 run_timing_test(case: &TimingCase) -> Result<(), Error> {
let (mut cpu, system) = init_decode_test(case.cpu);
let mut timing = M68kInstructionTiming::new(case.cpu, 16);
load_memory(&system, case.data);
cpu.decode_next().unwrap();
assert_eq!(cpu.decoder.instruction, case.ins.clone());
timing.add_instruction(&cpu.decoder.instruction);
let result = timing.calculate_clocks(false, 1);
let expected = match case.cpu {
M68kType::MC68000 => case.timing.0,
M68kType::MC68010 => case.timing.1,
_ => case.timing.2,
};
//assert_eq!(expected, result);
if expected == result {
Ok(())
} else {
println!("{:?}", timing);
Err(Error::new(&format!("expected {} but found {}", expected, result)))
}
}
#[test]
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 },
//}
if let Err(_) = run_timing_test(case) {
errors += 1;
}
}
if errors > 0 {
panic!("{} errors", errors);
}
}

View File

@ -137,7 +137,7 @@ impl TestCase {
fn init_execute_test(cputype: M68kType, state: &TestState) -> Result<(M68k, System), Error> {
let mut system = System::new();
let mut system = System::default();
// Insert basic initialization
let data = vec![0; 0x01000000];