1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-30 04:50:08 +00:00
CLK/OSBindings/Mac/Clock SignalTests/68000MoveTests.mm
2022-05-26 07:52:14 -04:00

1207 lines
35 KiB
Plaintext

//
// 68000ArithmeticTests.m
// Clock SignalTests
//
// Created by Thomas Harte on 28/06/2019.
//
// Largely ported from the tests of the Portable 68k Emulator.
//
#import <XCTest/XCTest.h>
#include "TestRunner68000.hpp"
@interface M68000MoveTests : XCTestCase
@end
@implementation M68000MoveTests {
std::unique_ptr<RAM68000> _machine;
}
- (void)setUp {
_machine = std::make_unique<RAM68000>();
}
- (void)tearDown {
_machine.reset();
}
// MARK: CLR
- (void)testCLRw {
_machine->set_program({
0x4244 // CLR.w D4
});
_machine->set_registers([=](auto &registers) {
registers.data[4] = 0x9853abcd;
registers.status |= ConditionCode::Extend | ConditionCode::Negative | ConditionCode::Overflow | ConditionCode::Carry;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[4], 0x98530000);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Zero);
XCTAssertEqual(4, _machine->get_cycle_count());
}
- (void)testCLRl_Dn {
_machine->set_program({
0x4284 // CLR.l D4
});
_machine->set_registers([=](auto &registers) {
registers.data[4] = 0x9853abcd;
registers.status |= ConditionCode::Extend | ConditionCode::Negative | ConditionCode::Overflow | ConditionCode::Carry;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[4], 0x0);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Zero);
XCTAssertEqual(6, _machine->get_cycle_count());
}
- (void)testCLRl_XXXl {
_machine->set_program({
0x42b9, 0x0001, 0x86a0 // CLR.l ($186a0).l
});
*_machine->ram_at(0x186a0) = 0x9853;
*_machine->ram_at(0x186a2) = 0xabcd;
_machine->set_registers([=](auto &registers) {
registers.status |= ConditionCode::Extend | ConditionCode::Negative | ConditionCode::Overflow | ConditionCode::Carry;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(*_machine->ram_at(0x186a0), 0x0);
XCTAssertEqual(*_machine->ram_at(0x186a2), 0x0);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Zero);
XCTAssertEqual(28, _machine->get_cycle_count());
}
- (void)testCLRb_XXXl {
_machine->set_program({
0x4239, 0x0001, 0x86a0 // CLR.b ($186a0).l
});
*_machine->ram_at(0x186a0) = 0x9853;
*_machine->ram_at(0x186a2) = 0xabcd;
_machine->set_registers([=](auto &registers) {
registers.status |= ConditionCode::Extend | ConditionCode::Negative | ConditionCode::Overflow | ConditionCode::Carry;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(*_machine->ram_at(0x186a0), 0x0053);
XCTAssertEqual(*_machine->ram_at(0x186a2), 0xabcd);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Zero);
XCTAssertEqual(20, _machine->get_cycle_count());
}
// MARK: EXG
- (void)testEXG_D1D2 {
_machine->set_program({
0xc342 // EXG D1, D2
});
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0x11111111;
registers.data[2] = 0x22222222;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x22222222);
XCTAssertEqual(state.registers.data[2], 0x11111111);
XCTAssertEqual(6, _machine->get_cycle_count());
}
- (void)testEXG_A1A2 {
_machine->set_program({
0xc34a // EXG A1, A2
});
_machine->set_registers([=](auto &registers) {
registers.address[1] = 0x11111111;
registers.address[2] = 0x22222222;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[1], 0x22222222);
XCTAssertEqual(state.registers.address[2], 0x11111111);
XCTAssertEqual(6, _machine->get_cycle_count());
}
- (void)testEXG_A1D1 {
_machine->set_program({
0xc389 // EXG A1, D1
});
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0x11111111;
registers.address[1] = 0x22222222;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x22222222);
XCTAssertEqual(state.registers.address[1], 0x11111111);
XCTAssertEqual(6, _machine->get_cycle_count());
}
// MARK: LEA
- (void)testLEA_w {
_machine->set_program({
0x41f8, 0x000c // LEA ($12).w, A0
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[0], 0xc);
XCTAssertEqual(8, _machine->get_cycle_count());
}
- (void)testLEA_l {
_machine->set_program({
0x41f9, 0x000c, 0x000d // LEA ($c000d).w, A0
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[0], 0xc000d);
XCTAssertEqual(12, _machine->get_cycle_count());
}
- (void)testLEA_An {
_machine->set_program({
0x43d2, // LEA (A2), A1
});
_machine->set_registers([=](auto &registers) {
registers.address[2] = 0xc000d;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[1], 0xc000d);
XCTAssertEqual(state.registers.address[2], 0xc000d);
XCTAssertEqual(4, _machine->get_cycle_count());
}
- (void)testLEA_dAn {
_machine->set_program({
0x43ea, 0xffff // LEA (-1,A2), A1
});
_machine->set_registers([=](auto &registers) {
registers.address[2] = 0xc000d;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[1], 0xc000c);
XCTAssertEqual(state.registers.address[2], 0xc000d);
XCTAssertEqual(8, _machine->get_cycle_count());
}
- (void)testLEA_dAnDnw {
_machine->set_program({
0x43f2, 0x7002 // LEA (2,A2,D7.W), A1
});
_machine->set_registers([=](auto &registers) {
registers.address[2] = 0xc000d;
registers.data[7] = 0x10000022;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[1], 0xc0031);
XCTAssertEqual(state.registers.address[2], 0xc000d);
XCTAssertEqual(state.registers.data[7], 0x10000022);
XCTAssertEqual(12, _machine->get_cycle_count());
}
- (void)testLEA_dAnDnl {
_machine->set_program({
0x43f2, 0x7802 // LEA (2,A2,D7.l), A1
});
_machine->set_registers([=](auto &registers) {
registers.address[2] = 0xc000d;
registers.data[7] = 0x10000022;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[1], 0x100c0031);
XCTAssertEqual(state.registers.address[2], 0xc000d);
XCTAssertEqual(state.registers.data[7], 0x10000022);
XCTAssertEqual(12, _machine->get_cycle_count());
}
- (void)testLEA_dPC {
_machine->set_program({
0x43fa, 0xeff8 // LEA (-6,PC), A1
});
_machine->set_registers([=](auto &registers) {
registers.address[2] = 0xc000d;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[1], 0xFFFFFFFA);
XCTAssertEqual(8, _machine->get_cycle_count());
}
- (void)testLEA_dPCDn {
_machine->set_program({
0x43fb, 0x30fe // LEA (-6,PC,D3), A1
});
_machine->set_registers([=](auto &registers) {
registers.data[3] = 0x2;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[1], 0x1002);
XCTAssertEqual(state.registers.data[3], 0x2);
XCTAssertEqual(12, _machine->get_cycle_count());
}
// MARK: LINK
- (void)testLINKA1_5 {
_machine->set_program({
0x4e51, 0x0005 // LINK a1, #5
}, 0x22222222);
_machine->set_registers([=](auto &registers) {
registers.address[1] = 0x11111111;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[1], 0x2222221e);
XCTAssertEqual(state.registers.supervisor_stack_pointer, 0x22222223);
XCTAssertEqual(*_machine->ram_at(0x2222221e), 0x1111);
XCTAssertEqual(*_machine->ram_at(0x22222220), 0x1111);
XCTAssertEqual(16, _machine->get_cycle_count());
}
- (void)testLINKA7_5 {
_machine->set_program({
0x4e57, 0x0005 // LINK a7, #5
}, 0x22222222);
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.supervisor_stack_pointer, 0x22222223);
XCTAssertEqual(*_machine->ram_at(0x2222221e), 0x2222);
XCTAssertEqual(*_machine->ram_at(0x22222220), 0x221e);
XCTAssertEqual(16, _machine->get_cycle_count());
}
- (void)testLINKA1_8000 {
_machine->set_program({
0x4e51, 0x8000 // LINK a1, #$8000
}, 0x22222222);
_machine->set_registers([=](auto &registers) {
registers.address[1] = 0x11111111;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[1], 0x2222221e);
XCTAssertEqual(state.registers.supervisor_stack_pointer, 0x2221a21e);
XCTAssertEqual(*_machine->ram_at(0x2222221e), 0x1111);
XCTAssertEqual(*_machine->ram_at(0x22222220), 0x1111);
XCTAssertEqual(16, _machine->get_cycle_count());
}
// MARK: MOVEM
- (void)testMOVEMl_fromD0D1 {
_machine->set_program({
0x48e1, 0xc000 // MOVEM.L D0-D1, -(A1)
});
_machine->set_registers([=](auto &registers) {
registers.address[1] = 0x3000;
registers.data[0] = 0x12345678;
registers.data[1] = 0x87654321;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[1], 0x2ff8);
XCTAssertEqual(state.registers.data[0], 0x12345678);
XCTAssertEqual(state.registers.data[1], 0x87654321);
XCTAssertEqual(*_machine->ram_at(0x2ff8), 0x1234);
XCTAssertEqual(*_machine->ram_at(0x2ffa), 0x5678);
XCTAssertEqual(*_machine->ram_at(0x2ffc), 0x8765);
XCTAssertEqual(*_machine->ram_at(0x2ffe), 0x4321);
XCTAssertEqual(24, _machine->get_cycle_count());
}
- (void)testMOVEMl_fromD0D1A1 {
_machine->set_program({
0x48e1, 0xc040 // MOVEM.L D0-D1/A1, -(A1)
});
_machine->set_registers([=](auto &registers) {
registers.address[1] = 0x3000;
registers.data[0] = 0x12345678;
registers.data[1] = 0x87654321;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[1], 0x2ff4);
XCTAssertEqual(state.registers.data[0], 0x12345678);
XCTAssertEqual(state.registers.data[1], 0x87654321);
XCTAssertEqual(*_machine->ram_at(0x2ff4), 0x1234);
XCTAssertEqual(*_machine->ram_at(0x2ff6), 0x5678);
XCTAssertEqual(*_machine->ram_at(0x2ff8), 0x8765);
XCTAssertEqual(*_machine->ram_at(0x2ffa), 0x4321);
XCTAssertEqual(*_machine->ram_at(0x2ffc), 0x0000);
XCTAssertEqual(*_machine->ram_at(0x2ffe), 0x3000);
XCTAssertEqual(32, _machine->get_cycle_count());
}
- (void)testMOVEMl_fromEverything {
_machine->set_program({
0x48e4, 0xffff // MOVEM.L D0-D7/A0-A7, -(A4)
}, 0xffffffff);
_machine->set_registers([=](auto &registers) {
for(int c = 0; c < 8; ++c)
registers.data[c] = (c+1) * 0x11111111;
for(int c = 0; c < 7; ++c)
registers.address[c] = ((c < 4) ? (c + 9) : (c + 8)) * 0x11111111;
registers.address[4] = 0x4000;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[4], 0x3fc0);
const uint32_t expected_values[] = {
0xffffffff, 0xeeeeeeee, 0xdddddddd, 0x00004000,
0xcccccccc, 0xbbbbbbbb, 0xaaaaaaaa, 0x99999999,
0x88888888, 0x77777777, 0x66666666, 0x55555555,
0x44444444, 0x33333333, 0x22222222, 0x11111111,
};
const uint32_t *expected_value = expected_values;
for(uint32_t address = 0x3ffc; address <= 0x3fc0; address += 4) {
XCTAssertEqual(*_machine->ram_at(address), (*expected_value >> 16));
XCTAssertEqual(*_machine->ram_at(address + 2), (*expected_value & 0xffff));
++expected_value;
}
XCTAssertEqual(136, _machine->get_cycle_count());
}
- (void)testMOVEMw_fromD4 {
_machine->set_program({
0x48a4, 0x0800 // MOVEM.W D4, -(A4)
});
_machine->set_registers([=](auto &registers) {
registers.address[4] = 0x4000;
registers.data[4] = 0x111a1111;
registers.data[0] = 0xffffffff;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[4], 0x3ffe);
XCTAssertEqual(state.registers.data[0], 0xffffffff);
XCTAssertEqual(state.registers.data[4], 0x111a1111);
XCTAssertEqual(*_machine->ram_at(0x3ffe), 0x1111);
XCTAssertEqual(*_machine->ram_at(0x3ffc), 0x0000);
XCTAssertEqual(12, _machine->get_cycle_count());
}
// TODO: port MOVEM.W D4/D0, -(A4), which tests bus error response.
- (void)testMOVEMl_toD1D2A1A2 {
_machine->set_program({
0x4cd9, 0x0606 // MOVEM.l (A1)+, D1-D2/A1-A2
});
_machine->set_registers([=](auto &registers) {
registers.address[1] = 0x4000;
});
*_machine->ram_at(0x4000) = 0x1111;
*_machine->ram_at(0x4002) = 0x1111;
*_machine->ram_at(0x4004) = 0x2222;
*_machine->ram_at(0x4006) = 0x2222;
*_machine->ram_at(0x400c) = 0x3333;
*_machine->ram_at(0x400e) = 0x3333;
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x11111111);
XCTAssertEqual(state.registers.data[2], 0x22222222);
XCTAssertEqual(state.registers.address[1], 0x4010);
XCTAssertEqual(state.registers.address[2], 0x33333333);
XCTAssertEqual(44, _machine->get_cycle_count());
}
- (void)testMOVEMw_signExtend {
_machine->set_program({
0x4c99, 0x0002 // MOVEM.w (A1)+, D1
});
_machine->set_registers([=](auto &registers) {
registers.address[1] = 0x4000;
});
*_machine->ram_at(0x4000) = 0x8000;
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xffff8000);
XCTAssertEqual(state.registers.address[1], 0x4002);
XCTAssertEqual(16, _machine->get_cycle_count());
}
- (void)testMOVEMw_fromIndirect {
_machine->set_program({
0x4c91, 0x0206 // MOVEM.w (A1), A1/D1-D2
});
_machine->set_registers([=](auto &registers) {
registers.address[1] = 0x4000;
registers.data[2] = 0xffffffff;
});
*_machine->ram_at(0x4000) = 0x8000;
*_machine->ram_at(0x4002) = 0x2222;
*_machine->ram_at(0x4004) = 0x3333;
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xffff8000);
XCTAssertEqual(state.registers.data[2], 0x00002222);
XCTAssertEqual(state.registers.address[1], 0x3333);
XCTAssertEqual(24, _machine->get_cycle_count());
}
- (void)testMOVEMw_toIndirect {
_machine->set_program({
0x4891, 0x0206 // MOVEM.w A1/D1-D2, (A1)
});
_machine->set_registers([=](auto &registers) {
registers.address[1] = 0x4000;
registers.data[1] = 0x11111111;
registers.data[2] = 0x22222222;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(*_machine->ram_at(0x4000), 0x1111);
XCTAssertEqual(*_machine->ram_at(0x4002), 0x2222);
XCTAssertEqual(*_machine->ram_at(0x4004), 0x4000);
XCTAssertEqual(state.registers.address[1], 0x4000);
XCTAssertEqual(20, _machine->get_cycle_count());
}
// MARK: MOVE
- (void)testMOVEb_DnDn {
_machine->set_program({
0x1401 // MOVE.b D1, D2
});
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0x12345678;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x12345678);
XCTAssertEqual(state.registers.data[2], 0x00000078);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(4, _machine->get_cycle_count());
}
- (void)testMOVEl_ImmDn {
_machine->set_program({
0x243c, 0x8090, 0xfea1 // MOVE.l #$8090fea1, D2
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[2], 0x8090fea1);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative);
XCTAssertEqual(12, _machine->get_cycle_count());
}
- (void)testMOVEs_ImmInd {
_machine->set_program({
0x34bc, 0x0000 // MOVE #$0, (A2)
});
_machine->set_registers([=](auto &registers) {
registers.address[2] = 0x3000;
});
*_machine->ram_at(0x3000) = 0x1234;
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[2], 0x3000);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Zero);
XCTAssertEqual(*_machine->ram_at(0x3000), 0);
XCTAssertEqual(12, _machine->get_cycle_count());
}
- (void)testMOVEl_PostIncPostInc {
_machine->set_program({
0x24da // MOVE.l (A2)+, (A2)+
});
_machine->set_registers([=](auto &registers) {
registers.address[2] = 0x3000;
registers.status = ConditionCode::Negative;
});
*_machine->ram_at(0x3000) = 0xaaaa;
*_machine->ram_at(0x3002) = 0xbbbb;
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[2], 0x3008);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative);
XCTAssertEqual(*_machine->ram_at(0x3000), 0xaaaa);
XCTAssertEqual(*_machine->ram_at(0x3002), 0xbbbb);
XCTAssertEqual(*_machine->ram_at(0x3004), 0xaaaa);
XCTAssertEqual(*_machine->ram_at(0x3006), 0xbbbb);
XCTAssertEqual(20, _machine->get_cycle_count());
}
- (void)testMOVEl_PostIncPreDec {
_machine->set_program({
0x251a // MOVE.l (A2)+, -(A2)
});
_machine->set_registers([=](auto &registers) {
registers.address[2] = 0x3000;
registers.status = ConditionCode::Negative;
});
*_machine->ram_at(0x3000) = 0xaaaa;
*_machine->ram_at(0x3002) = 0xbbbb;
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[2], 0x3000);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative);
XCTAssertEqual(*_machine->ram_at(0x3000), 0xaaaa);
XCTAssertEqual(*_machine->ram_at(0x3002), 0xbbbb);
XCTAssertEqual(*_machine->ram_at(0x3004), 0);
XCTAssertEqual(*_machine->ram_at(0x3006), 0);
XCTAssertEqual(20, _machine->get_cycle_count());
}
- (void)testMOVEl_PreDecD16An {
_machine->set_program({
0x25a2, 0x1004 // MOVE.L -(A2), 4(A2,D1)
});
_machine->set_registers([=](auto &registers) {
registers.address[2] = 0x3004;
registers.data[1] = 0;
registers.status = ConditionCode::Negative;
});
*_machine->ram_at(0x3000) = 0xaaaa;
*_machine->ram_at(0x3002) = 0xbbbb;
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[2], 0x3000);
XCTAssertEqual(state.registers.data[1], 0);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative);
XCTAssertEqual(*_machine->ram_at(0x3000), 0xaaaa);
XCTAssertEqual(*_machine->ram_at(0x3002), 0xbbbb);
XCTAssertEqual(*_machine->ram_at(0x3004), 0xaaaa);
XCTAssertEqual(*_machine->ram_at(0x3006), 0xbbbb);
XCTAssertEqual(28, _machine->get_cycle_count());
}
- (void)testMOVEl_DnXXXl {
_machine->set_program({
0x33c1, 0x0000, 0x3000 // MOVE.W D1, ($3000).L
});
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0x5678;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x5678);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(*_machine->ram_at(0x3000), 0x5678);
XCTAssertEqual(*_machine->ram_at(0x3002), 0);
XCTAssertEqual(16, _machine->get_cycle_count());
}
- (void)testMOVEl_XXXlXXXl {
_machine->set_program({
0x23f9, 0x0000, 0x3000, 0x0000, 0x3004 // MOVE.L ($3000).L, ($3004).L
});
*_machine->ram_at(0x3002) = 0xeeee;
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0); /* !! 8 !! */
XCTAssertEqual(*_machine->ram_at(0x3002), 0xeeee);
XCTAssertEqual(*_machine->ram_at(0x3006), 0xeeee);
XCTAssertEqual(36, _machine->get_cycle_count());
}
// MARK: MOVEA
- (void)testMOVEAl_An {
_machine->set_program({
0x244a // MOVEA.l A2, A2
});
_machine->set_registers([=](auto &registers) {
registers.address[2] = 0xffffffff;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[2], 0xffffffff);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(4, _machine->get_cycle_count());
}
- (void)testMOVEAw_Dn_positive {
_machine->set_program({
0x3442 // MOVEA.w D2, A2
});
_machine->set_registers([=](auto &registers) {
registers.address[2] = 0xffffffff;
registers.data[2] = 0x12345678;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[2], 0x00005678);
XCTAssertEqual(state.registers.data[2], 0x12345678);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(4, _machine->get_cycle_count());
}
- (void)testMOVEAw_Dn_negative {
_machine->set_program({
0x3442 // MOVEA.w D2, A2
});
_machine->set_registers([=](auto &registers) {
registers.address[2] = 0xffffffff;
registers.data[2] = 0x12348756;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[2], 0xffff8756);
XCTAssertEqual(state.registers.data[2], 0x12348756);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(4, _machine->get_cycle_count());
}
- (void)testMOVEAl_Imm {
_machine->set_program({
0x247c, 0x0000, 0x0001 // MOVEA.L #$1, A2
});
_machine->set_registers([=](auto &registers) {
registers.address[2] = 0xffffffff;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[2], 1);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(12, _machine->get_cycle_count());
}
// MARK: MOVEP
- (void)testMOVEPw_toDn {
_machine->set_program({
0x030e, 0x0004 // MOVEP.w 4(A6), D1
});
_machine->set_registers([=](auto &registers) {
registers.address[6] = 0x3000;
});
*_machine->ram_at(0x3004) = 0x1200;
*_machine->ram_at(0x3006) = 0x3400;
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[6], 0x3000);
XCTAssertEqual(state.registers.data[1], 0x1234);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(16, _machine->get_cycle_count());
}
- (void)testMOVEPl_toDn {
_machine->set_program({
0x034e, 0x0002 // MOVEP.l 2(A6), D1
});
_machine->set_registers([=](auto &registers) {
registers.address[6] = 0x3000;
});
*_machine->ram_at(0x3002) = 0x1200;
*_machine->ram_at(0x3004) = 0x3400;
*_machine->ram_at(0x3006) = 0x5600;
*_machine->ram_at(0x3008) = 0x7800;
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[6], 0x3000);
XCTAssertEqual(state.registers.data[1], 0x12345678);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(24, _machine->get_cycle_count());
}
- (void)testMOVEPw_fromDn {
_machine->set_program({
0x038e, 0x0002 // MOVEP.w D1, 2(A6)
});
_machine->set_registers([=](auto &registers) {
registers.address[6] = 0x3000;
registers.data[1] = 0x12345678;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[6], 0x3000);
XCTAssertEqual(*_machine->ram_at(0x3002), 0x5600);
XCTAssertEqual(*_machine->ram_at(0x3004), 0x7800);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(16, _machine->get_cycle_count());
}
- (void)testMOVEPl_fromDn {
_machine->set_program({
0x03ce, 0x0002 // MOVEP.l D1, 2(A6)
});
_machine->set_registers([=](auto &registers) {
registers.address[6] = 0x3000;
registers.data[1] = 0x12345678;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[6], 0x3000);
XCTAssertEqual(*_machine->ram_at(0x3002), 0x1200);
XCTAssertEqual(*_machine->ram_at(0x3004), 0x3400);
XCTAssertEqual(*_machine->ram_at(0x3006), 0x5600);
XCTAssertEqual(*_machine->ram_at(0x3008), 0x7800);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(24, _machine->get_cycle_count());
}
// MARK: MOVEQ
- (void)testMOVEQ_1 {
_machine->set_program({
0x7201 // MOVEQ #1, D1
});
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xffffffff;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x1);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(4, _machine->get_cycle_count());
}
- (void)testMOVEQ_ff {
_machine->set_program({
0x72ff // MOVEQ #-1, D1
});
_machine->set_registers([=](auto &registers) {
registers.status |= ConditionCode::Extend | ConditionCode::Carry | ConditionCode::Overflow;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xffffffff);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative);
XCTAssertEqual(4, _machine->get_cycle_count());
}
- (void)testMOVEQ_80 {
_machine->set_program({
0x7280 // MOVEQ #$80, D1
});
_machine->set_registers([=](auto &registers) {
registers.status |= ConditionCode::Extend | ConditionCode::Carry | ConditionCode::Overflow;
registers.data[1] = 0x12345678;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xffffff80);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative);
XCTAssertEqual(4, _machine->get_cycle_count());
}
- (void)testMOVEQ_00 {
_machine->set_program({
0x7200 // MOVEQ #00, D1
});
_machine->set_registers([=](auto &registers) {
registers.status |= ConditionCode::Extend | ConditionCode::Carry | ConditionCode::Overflow;
registers.data[1] = 0x12345678;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Zero);
XCTAssertEqual(4, _machine->get_cycle_count());
}
// MARK: MOVE from SR
- (void)testMoveFromSR {
_machine->set_program({
0x40c1 // MOVE SR, D1
});
_machine->set_registers([=](auto &registers) {
registers.status = 0x271f;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x271f);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::AllConditions);
XCTAssertEqual(6, _machine->get_cycle_count());
}
// MARK: MOVE to CCR
- (void)testMoveToCCR {
_machine->set_program({
0x44fc, 0x001f // MOVE #$1f, CCR
});
_machine->set_registers([=](auto &registers) {
registers.status = 0; // i.e. not supervisor.
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0x1f);
XCTAssertEqual(16, _machine->get_cycle_count());
}
// MARK: MOVE to SR
- (void)testMoveToSR {
_machine->set_program({
0x46fc, 0x0700 // MOVE #$700, SR
});
_machine->set_registers([=](auto &registers) {
registers.supervisor_stack_pointer = 0x3000;
registers.user_stack_pointer = 0;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.stack_pointer(), 0);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(16, _machine->get_cycle_count());
}
// MARK: MOVE USP
- (void)testMoveUSP {
_machine->set_program({
0x4e69 // MOVE USP, A1
});
_machine->set_registers([=](auto &registers) {
registers.address[1] = 0x12348756;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[1], 0);
}
// MARK: PEA
- (void)testPEA_A1 {
_machine->set_program({
0x4851 // PEA (A1)
}, 0x1996);
_machine->set_registers([=](auto &registers) {
registers.address[1] = 0x3000ffff;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[1], 0x3000ffff);
XCTAssertEqual(state.registers.stack_pointer(), 0x1992);
XCTAssertEqual(*_machine->ram_at(0x1992), 0x3000);
XCTAssertEqual(*_machine->ram_at(0x1994), 0xffff);
XCTAssertEqual(12, _machine->get_cycle_count());
}
- (void)testPEA_A7 {
_machine->set_program({
0x4857 // PEA (A7)
}, 0x1012);
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.stack_pointer(), 0x100e);
XCTAssertEqual(*_machine->ram_at(0x1010), 0x1012);
XCTAssertEqual(*_machine->ram_at(0x1008), 0x0000);
XCTAssertEqual(12, _machine->get_cycle_count());
}
- (void)testPEA_4A7 {
_machine->set_program({
0x486f, 0x0004 // PEA 4(A7)
}, 0x1012);
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.stack_pointer(), 0x100e);
XCTAssertEqual(*_machine->ram_at(0x1010), 0x1016);
XCTAssertEqual(*_machine->ram_at(0x1008), 0x0000);
XCTAssertEqual(16, _machine->get_cycle_count());
}
- (void)testPEA_XXXw {
_machine->set_program({
0x4878, 0x3000 // PEA ($3000).w
}, 0x1996);
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.stack_pointer(), 0x1992);
XCTAssertEqual(*_machine->ram_at(0x1992), 0x0000);
XCTAssertEqual(*_machine->ram_at(0x1994), 0x3000);
XCTAssertEqual(16, _machine->get_cycle_count());
}
- (void)testPEA_XXXl {
_machine->set_program({
0x4879, 0x1234, 0x5678 // PEA ($12345678)
}, 0x1996);
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.stack_pointer(), 0x1992);
XCTAssertEqual(*_machine->ram_at(0x1992), 0x1234);
XCTAssertEqual(*_machine->ram_at(0x1994), 0x5678);
XCTAssertEqual(20, _machine->get_cycle_count());
}
// MARK: Scc
- (void)testSFDn {
_machine->set_program({
0x51c0 // SF D0
});
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0x12345678;
registers.status = ConditionCode::Extend;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0x12345600);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend);
}
- (void)testSTDn {
_machine->set_program({
0x50c0 // ST D0
});
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0x12345678;
registers.status = ConditionCode::Extend;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0x123456ff);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend);
}
- (void)testSLSDn {
_machine->set_program({
0x53c0 // SLS D0
});
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0x12345678;
registers.status = ConditionCode::AllConditions;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0x123456ff);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::AllConditions);
}
- (void)testSGTAnXTrue {
_machine->set_program({
0x5ee8, 0x0002 // SGT 2(a0)
});
_machine->set_registers([=](auto &registers) {
registers.address[0] = 0x3000;
registers.status = ConditionCode::Extend;
});
*_machine->ram_at(0x3002) = 0x8800;
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(*_machine->ram_at(0x3002), 0xff00);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend);
}
- (void)testSGTAnXFalse {
_machine->set_program({
0x5ee8, 0x0002 // SGT 2(a0)
});
_machine->set_registers([=](auto &registers) {
registers.address[0] = 0x3000;
registers.status = ConditionCode::AllConditions;
});
*_machine->ram_at(0x3002) = 0x8800;
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(*_machine->ram_at(0x3002), 0x0000);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::AllConditions);
}
// MARK: SWAP
- (void)testSwap {
_machine->set_program({
0x4841 // SWAP D1
});
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0x12348756;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x87561234);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative);
}
// MARK: TST
- (void)testTSTw_Dn {
_machine->set_program({
0x4a44 // TST.w D4
});
_machine->set_registers([=](auto &registers) {
registers.status |= ConditionCode::Extend | ConditionCode::Carry | ConditionCode::Overflow;
registers.data[4] = 0xfff1;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative | ConditionCode::Extend);
XCTAssertEqual(state.registers.data[4], 0xfff1);
XCTAssertEqual(4, _machine->get_cycle_count());
}
- (void)testTSTl_Dn {
_machine->set_program({
0x4a84 // TST.l D4
});
_machine->set_registers([=](auto &registers) {
registers.status |= ConditionCode::Extend | ConditionCode::Carry | ConditionCode::Overflow;
registers.data[4] = 0;
});
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Zero | ConditionCode::Extend);
XCTAssertEqual(state.registers.data[4], 0);
XCTAssertEqual(4, _machine->get_cycle_count());
}
// Omitted: test that tst.w A0 doesn't decode.
// MARK: UNLINK
- (void)testUNLINK_A6 {
_machine->set_program({
0x4e5e // UNLNK A6
});
_machine->set_registers([=](auto &registers) {
registers.address[6] = 0x3000;
});
*_machine->ram_at(0x3000) = 0x0000;
*_machine->ram_at(0x3002) = 0x4000;
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[6], 0x4000);
XCTAssertEqual(state.registers.supervisor_stack_pointer, 0x3004);
XCTAssertEqual(12, _machine->get_cycle_count());
}
- (void)testUNLINK_A7 {
_machine->set_program({
0x4e5f // UNLNK A7
}, 0x3000);
*_machine->ram_at(0x3000) = 0x0000;
*_machine->ram_at(0x3002) = 0x4000;
_machine->run_for_instructions(1);
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.supervisor_stack_pointer, 0x4000);
XCTAssertEqual(12, _machine->get_cycle_count());
}
@end