2021-10-02 02:27:05 +00:00
|
|
|
|
2021-10-09 06:11:52 +00:00
|
|
|
use crate::system::System;
|
|
|
|
use crate::devices::{Steppable, wrap_addressable};
|
2021-10-07 16:41:01 +00:00
|
|
|
use crate::memory::{Address, Addressable, MemoryBlock};
|
2021-10-02 02:27:05 +00:00
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
use super::decode::Instruction;
|
2021-10-10 21:26:54 +00:00
|
|
|
use super::state::{M68k, M68kType};
|
2021-10-02 02:27:05 +00:00
|
|
|
|
|
|
|
const INIT_STACK: Address = 0x00002000;
|
|
|
|
const INIT_ADDR: Address = 0x00000010;
|
|
|
|
|
2021-10-10 21:26:54 +00:00
|
|
|
fn init_test() -> (M68k, System) {
|
2021-10-06 23:14:56 +00:00
|
|
|
let mut system = System::new();
|
2021-10-02 02:27:05 +00:00
|
|
|
|
|
|
|
// Insert basic initialization
|
2021-10-06 23:14:56 +00:00
|
|
|
let data = vec![0; 0x00100000];
|
2021-10-02 02:27:05 +00:00
|
|
|
let mem = MemoryBlock::new(data);
|
2021-10-07 16:41:01 +00:00
|
|
|
system.add_addressable_device(0x00000000, wrap_addressable(mem)).unwrap();
|
|
|
|
system.get_bus().write_beu32(0, INIT_STACK as u32).unwrap();
|
|
|
|
system.get_bus().write_beu32(4, INIT_ADDR as u32).unwrap();
|
2021-10-02 02:27:05 +00:00
|
|
|
|
2021-10-10 21:26:54 +00:00
|
|
|
let mut cpu = M68k::new(M68kType::MC68010);
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.step(&system).unwrap();
|
2021-10-02 15:47:20 +00:00
|
|
|
assert_eq!(cpu.state.pc, INIT_ADDR as u32);
|
|
|
|
assert_eq!(cpu.state.msp, INIT_STACK as u32);
|
|
|
|
assert_eq!(cpu.decoder.instruction, Instruction::NOP);
|
2021-10-06 23:14:56 +00:00
|
|
|
(cpu, system)
|
2021-10-02 02:27:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::{init_test, INIT_ADDR};
|
2021-10-06 23:14:56 +00:00
|
|
|
use crate::memory::{Address, Addressable};
|
|
|
|
use super::super::decode::{Instruction, Target, Size, Sign, ShiftDirection};
|
2021-10-02 02:27:05 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn instruction_nop() {
|
2021-10-06 23:14:56 +00:00
|
|
|
let (mut cpu, mut system) = init_test();
|
2021-10-02 02:27:05 +00:00
|
|
|
|
2021-10-07 16:41:01 +00:00
|
|
|
system.get_bus().write_beu16(INIT_ADDR, 0x4e71).unwrap();
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.decode_next(&system).unwrap();
|
2021-10-02 15:47:20 +00:00
|
|
|
assert_eq!(cpu.decoder.instruction, Instruction::NOP);
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.execute_current(&system).unwrap();
|
2021-10-02 02:27:05 +00:00
|
|
|
// TODO you need a way to easily check the entire state (you maybe need to make a special struct for the state)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn instruction_ori() {
|
2021-10-06 23:14:56 +00:00
|
|
|
let (mut cpu, mut system) = init_test();
|
2021-10-02 02:27:05 +00:00
|
|
|
|
2021-10-07 16:41:01 +00:00
|
|
|
system.get_bus().write_beu16(INIT_ADDR, 0x0008).unwrap();
|
|
|
|
system.get_bus().write_beu16(INIT_ADDR + 2, 0x00FF).unwrap();
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.decode_next(&system).unwrap();
|
2021-10-02 15:47:20 +00:00
|
|
|
assert_eq!(cpu.decoder.instruction, Instruction::OR(Target::Immediate(0xFF), Target::DirectAReg(0), Size::Byte));
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.execute_current(&system).unwrap();
|
2021-10-02 15:47:20 +00:00
|
|
|
assert_eq!(cpu.state.a_reg[0], 0x000000FF);
|
2021-10-02 02:27:05 +00:00
|
|
|
}
|
2021-10-02 22:35:08 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn instruction_cmpi_equal() {
|
2021-10-06 23:14:56 +00:00
|
|
|
let (mut cpu, mut system) = init_test();
|
2021-10-02 22:35:08 +00:00
|
|
|
|
2021-10-07 16:41:01 +00:00
|
|
|
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();
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.step(&system).unwrap();
|
|
|
|
cpu.decode_next(&system).unwrap();
|
2021-10-02 22:35:08 +00:00
|
|
|
assert_eq!(cpu.decoder.instruction, Instruction::CMP(Target::Immediate(0x20), Target::DirectDReg(0), Size::Byte));
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.execute_current(&system).unwrap();
|
2021-10-02 22:35:08 +00:00
|
|
|
assert_eq!(cpu.state.sr & 0x0F, 0x04);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn instruction_cmpi_greater() {
|
2021-10-06 23:14:56 +00:00
|
|
|
let (mut cpu, mut system) = init_test();
|
2021-10-02 22:35:08 +00:00
|
|
|
|
2021-10-07 16:41:01 +00:00
|
|
|
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();
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.step(&system).unwrap();
|
|
|
|
cpu.decode_next(&system).unwrap();
|
2021-10-02 22:35:08 +00:00
|
|
|
assert_eq!(cpu.decoder.instruction, Instruction::CMP(Target::Immediate(0x30), Target::DirectDReg(0), Size::Byte));
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.execute_current(&system).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(cpu.state.sr & 0x0F, 0x009);
|
2021-10-02 22:35:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn instruction_cmpi_less() {
|
2021-10-06 23:14:56 +00:00
|
|
|
let (mut cpu, mut system) = init_test();
|
2021-10-02 22:35:08 +00:00
|
|
|
|
2021-10-07 16:41:01 +00:00
|
|
|
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();
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.step(&system).unwrap();
|
|
|
|
cpu.decode_next(&system).unwrap();
|
2021-10-02 22:35:08 +00:00
|
|
|
assert_eq!(cpu.decoder.instruction, Instruction::CMP(Target::Immediate(0x10), Target::DirectDReg(0), Size::Byte));
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.execute_current(&system).unwrap();
|
2021-10-02 22:35:08 +00:00
|
|
|
assert_eq!(cpu.state.sr & 0x0F, 0x00);
|
|
|
|
}
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
|
|
|
|
#[test]
|
2021-10-03 16:55:20 +00:00
|
|
|
fn instruction_andi_sr() {
|
2021-10-06 23:14:56 +00:00
|
|
|
let (mut cpu, mut system) = init_test();
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
|
2021-10-07 16:41:01 +00:00
|
|
|
system.get_bus().write_beu16(INIT_ADDR, 0x027C).unwrap();
|
|
|
|
system.get_bus().write_beu16(INIT_ADDR + 2, 0xF8FF).unwrap();
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.decode_next(&system).unwrap();
|
2021-10-03 16:55:20 +00:00
|
|
|
assert_eq!(cpu.decoder.instruction, Instruction::ANDtoSR(0xF8FF));
|
2021-10-06 23:14:56 +00:00
|
|
|
//cpu.execute_current(&system).unwrap();
|
2021-10-03 16:55:20 +00:00
|
|
|
//assert_eq!(cpu.state.sr & 0x0F, 0x00);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn instruction_muls() {
|
2021-10-06 23:14:56 +00:00
|
|
|
let (mut cpu, mut system) = init_test();
|
2021-10-03 16:55:20 +00:00
|
|
|
|
2021-10-07 16:41:01 +00:00
|
|
|
system.get_bus().write_beu16(INIT_ADDR, 0xC1FC).unwrap();
|
|
|
|
system.get_bus().write_beu16(INIT_ADDR + 2, 0x0276).unwrap();
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.decode_next(&system).unwrap();
|
2021-10-03 16:55:20 +00:00
|
|
|
assert_eq!(cpu.decoder.instruction, Instruction::MUL(Target::Immediate(0x276), Target::DirectDReg(0), Size::Word, Sign::Signed));
|
2021-10-06 23:14:56 +00:00
|
|
|
//cpu.execute_current(&system).unwrap();
|
Added MUL, DIV, NEG, DBcc, and Scc instructions, and fixed issue with ADD/SUB flags
With ADDA, SUBA, and ADDQ/SUBQ when the target is an address register, the condition
flags should not be changed, but the code was changing them, which caused problems.
I've fixed it by making the ADD/SUB executions check for an address target and
will not update flags in that case. This should only occur when the actual instruction
was an ADDA or ADDQ with an address register target
2021-10-03 04:59:28 +00:00
|
|
|
//assert_eq!(cpu.state.sr & 0x0F, 0x00);
|
|
|
|
}
|
2021-10-05 23:22:21 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn instruction_asli() {
|
2021-10-06 23:14:56 +00:00
|
|
|
let (mut cpu, mut system) = init_test();
|
2021-10-05 23:22:21 +00:00
|
|
|
|
2021-10-07 16:41:01 +00:00
|
|
|
system.get_bus().write_beu16(INIT_ADDR, 0xE300).unwrap();
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.decode_next(&system).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(cpu.decoder.instruction, Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left));
|
|
|
|
|
|
|
|
cpu.state.d_reg[0] = 0x01;
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.execute_current(&system).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(cpu.state.d_reg[0], 0x00000002);
|
|
|
|
assert_eq!(cpu.state.sr & 0x1F, 0x00);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn instruction_asri() {
|
2021-10-06 23:14:56 +00:00
|
|
|
let (mut cpu, mut system) = init_test();
|
2021-10-05 23:22:21 +00:00
|
|
|
|
2021-10-07 16:41:01 +00:00
|
|
|
system.get_bus().write_beu16(INIT_ADDR, 0xE200).unwrap();
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.decode_next(&system).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(cpu.decoder.instruction, Instruction::ASd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right));
|
|
|
|
|
|
|
|
cpu.state.d_reg[0] = 0x81;
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.execute_current(&system).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(cpu.state.d_reg[0], 0x000000C0);
|
|
|
|
assert_eq!(cpu.state.sr & 0x1F, 0x19);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn instruction_roli() {
|
2021-10-06 23:14:56 +00:00
|
|
|
let (mut cpu, mut system) = init_test();
|
2021-10-05 23:22:21 +00:00
|
|
|
|
2021-10-07 16:41:01 +00:00
|
|
|
system.get_bus().write_beu16(INIT_ADDR, 0xE318).unwrap();
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.decode_next(&system).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(cpu.decoder.instruction, Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Left));
|
|
|
|
|
|
|
|
cpu.state.d_reg[0] = 0x80;
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.execute_current(&system).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(cpu.state.d_reg[0], 0x00000001);
|
|
|
|
assert_eq!(cpu.state.sr & 0x1F, 0x01);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn instruction_rori() {
|
2021-10-06 23:14:56 +00:00
|
|
|
let (mut cpu, mut system) = init_test();
|
2021-10-05 23:22:21 +00:00
|
|
|
|
2021-10-07 16:41:01 +00:00
|
|
|
system.get_bus().write_beu16(INIT_ADDR, 0xE218).unwrap();
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.decode_next(&system).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(cpu.decoder.instruction, Instruction::ROd(Target::Immediate(1), Target::DirectDReg(0), Size::Byte, ShiftDirection::Right));
|
|
|
|
|
|
|
|
cpu.state.d_reg[0] = 0x01;
|
2021-10-06 23:14:56 +00:00
|
|
|
cpu.execute_current(&system).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(cpu.state.d_reg[0], 0x00000080);
|
|
|
|
assert_eq!(cpu.state.sr & 0x1F, 0x09);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn target_value_direct_d() {
|
2021-10-06 23:14:56 +00:00
|
|
|
let (mut cpu, mut system) = init_test();
|
2021-10-05 23:22:21 +00:00
|
|
|
|
|
|
|
let size = Size::Word;
|
|
|
|
let expected = 0x1234;
|
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
let target = cpu.decoder.get_mode_as_target(&system, 0b000, 0b001, Some(size)).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(target, Target::DirectDReg(1));
|
|
|
|
|
|
|
|
cpu.state.d_reg[1] = expected;
|
2021-10-06 23:14:56 +00:00
|
|
|
let result = cpu.get_target_value(&system, target, size).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(result, expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn target_value_direct_a() {
|
2021-10-06 23:14:56 +00:00
|
|
|
let (mut cpu, mut system) = init_test();
|
2021-10-05 23:22:21 +00:00
|
|
|
|
|
|
|
let size = Size::Word;
|
|
|
|
let expected = 0x1234;
|
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
let target = cpu.decoder.get_mode_as_target(&system, 0b001, 0b010, Some(size)).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(target, Target::DirectAReg(2));
|
|
|
|
|
|
|
|
cpu.state.a_reg[2] = expected;
|
2021-10-06 23:14:56 +00:00
|
|
|
let result = cpu.get_target_value(&system, target, size).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(result, expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn target_value_indirect_a() {
|
2021-10-06 23:14:56 +00:00
|
|
|
let (mut cpu, mut system) = init_test();
|
2021-10-05 23:22:21 +00:00
|
|
|
|
|
|
|
let size = Size::Long;
|
|
|
|
let expected_addr = INIT_ADDR;
|
|
|
|
let expected = 0x12345678;
|
|
|
|
|
2021-10-07 16:41:01 +00:00
|
|
|
system.get_bus().write_beu32(INIT_ADDR, expected).unwrap();
|
2021-10-06 23:14:56 +00:00
|
|
|
let target = cpu.decoder.get_mode_as_target(&system, 0b010, 0b010, Some(size)).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(target, Target::IndirectAReg(2));
|
|
|
|
|
|
|
|
cpu.state.a_reg[2] = INIT_ADDR as u32;
|
2021-10-06 23:14:56 +00:00
|
|
|
let result = cpu.get_target_value(&system, target, size).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(result, expected);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn target_value_indirect_a_inc() {
|
2021-10-06 23:14:56 +00:00
|
|
|
let (mut cpu, mut system) = init_test();
|
2021-10-05 23:22:21 +00:00
|
|
|
|
|
|
|
let size = Size::Long;
|
|
|
|
let expected_addr = INIT_ADDR;
|
|
|
|
let expected = 0x12345678;
|
|
|
|
|
2021-10-07 16:41:01 +00:00
|
|
|
system.get_bus().write_beu32(INIT_ADDR, expected).unwrap();
|
2021-10-06 23:14:56 +00:00
|
|
|
let target = cpu.decoder.get_mode_as_target(&system, 0b011, 0b010, Some(size)).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(target, Target::IndirectARegInc(2));
|
|
|
|
|
|
|
|
cpu.state.a_reg[2] = INIT_ADDR as u32;
|
2021-10-06 23:14:56 +00:00
|
|
|
let result = cpu.get_target_value(&system, target, size).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(result, expected);
|
|
|
|
assert_eq!(cpu.state.a_reg[2], (INIT_ADDR as u32) + 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn target_value_indirect_a_dec() {
|
2021-10-06 23:14:56 +00:00
|
|
|
let (mut cpu, mut system) = init_test();
|
2021-10-05 23:22:21 +00:00
|
|
|
|
|
|
|
let size = Size::Long;
|
|
|
|
let expected_addr = INIT_ADDR + 4;
|
|
|
|
let expected = 0x12345678;
|
|
|
|
|
2021-10-07 16:41:01 +00:00
|
|
|
system.get_bus().write_beu32(INIT_ADDR, expected).unwrap();
|
2021-10-06 23:14:56 +00:00
|
|
|
let target = cpu.decoder.get_mode_as_target(&system, 0b100, 0b010, Some(size)).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(target, Target::IndirectARegDec(2));
|
|
|
|
|
|
|
|
cpu.state.a_reg[2] = (INIT_ADDR as u32) + 4;
|
2021-10-06 23:14:56 +00:00
|
|
|
let result = cpu.get_target_value(&system, target, size).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(result, expected);
|
|
|
|
assert_eq!(cpu.state.a_reg[2], INIT_ADDR as u32);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn target_value_immediate() {
|
2021-10-06 23:14:56 +00:00
|
|
|
let (mut cpu, mut system) = init_test();
|
2021-10-05 23:22:21 +00:00
|
|
|
|
|
|
|
let size = Size::Word;
|
|
|
|
let expected = 0x1234;
|
|
|
|
|
2021-10-07 16:41:01 +00:00
|
|
|
system.get_bus().write_beu16(cpu.decoder.end as Address, expected as u16).unwrap();
|
2021-10-06 23:14:56 +00:00
|
|
|
let target = cpu.decoder.get_mode_as_target(&system, 0b111, 0b100, Some(size)).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(target, Target::Immediate(expected));
|
|
|
|
|
2021-10-06 23:14:56 +00:00
|
|
|
let result = cpu.get_target_value(&system, target, size).unwrap();
|
2021-10-05 23:22:21 +00:00
|
|
|
assert_eq!(result, expected);
|
|
|
|
}
|
2021-10-02 02:27:05 +00:00
|
|
|
}
|
|
|
|
|