mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-01 10:05:55 +00:00
1251 lines
34 KiB
Plaintext
1251 lines
34 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
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.data[4] = 0x9853abcd;
|
|
state.status |= Flag::Extend | Flag::Negative | Flag::Overflow | Flag::Carry;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.data[4], 0x98530000);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend | Flag::Zero);
|
|
XCTAssertEqual(4, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testCLRl_Dn {
|
|
_machine->set_program({
|
|
0x4284 // CLR.l D4
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.data[4] = 0x9853abcd;
|
|
state.status |= Flag::Extend | Flag::Negative | Flag::Overflow | Flag::Carry;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.data[4], 0x0);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend | Flag::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;
|
|
auto state = _machine->get_processor_state();
|
|
state.status |= Flag::Extend | Flag::Negative | Flag::Overflow | Flag::Carry;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(*_machine->ram_at(0x186a0), 0x0);
|
|
XCTAssertEqual(*_machine->ram_at(0x186a2), 0x0);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend | Flag::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;
|
|
auto state = _machine->get_processor_state();
|
|
state.status |= Flag::Extend | Flag::Negative | Flag::Overflow | Flag::Carry;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(*_machine->ram_at(0x186a0), 0x0053);
|
|
XCTAssertEqual(*_machine->ram_at(0x186a2), 0xabcd);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend | Flag::Zero);
|
|
XCTAssertEqual(20, _machine->get_cycle_count());
|
|
}
|
|
|
|
// MARK: EXG
|
|
|
|
- (void)testEXG_D1D2 {
|
|
_machine->set_program({
|
|
0xc342 // EXG D1, D2
|
|
});
|
|
|
|
auto state = _machine->get_processor_state();
|
|
state.data[1] = 0x11111111;
|
|
state.data[2] = 0x22222222;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.data[1], 0x22222222);
|
|
XCTAssertEqual(state.data[2], 0x11111111);
|
|
XCTAssertEqual(6, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testEXG_A1A2 {
|
|
_machine->set_program({
|
|
0xc34a // EXG A1, A2
|
|
});
|
|
|
|
auto state = _machine->get_processor_state();
|
|
state.address[1] = 0x11111111;
|
|
state.address[2] = 0x22222222;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[1], 0x22222222);
|
|
XCTAssertEqual(state.address[2], 0x11111111);
|
|
XCTAssertEqual(6, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testEXG_A1D1 {
|
|
_machine->set_program({
|
|
0xc389 // EXG A1, D1
|
|
});
|
|
|
|
auto state = _machine->get_processor_state();
|
|
state.data[1] = 0x11111111;
|
|
state.address[1] = 0x22222222;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.data[1], 0x22222222);
|
|
XCTAssertEqual(state.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.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.address[0], 0xc000d);
|
|
XCTAssertEqual(12, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testLEA_An {
|
|
_machine->set_program({
|
|
0x43d2, // LEA (A2), A1
|
|
});
|
|
|
|
auto state = _machine->get_processor_state();
|
|
state.address[2] = 0xc000d;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[1], 0xc000d);
|
|
XCTAssertEqual(state.address[2], 0xc000d);
|
|
XCTAssertEqual(4, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testLEA_dAn {
|
|
_machine->set_program({
|
|
0x43ea, 0xffff // LEA (-1,A2), A1
|
|
});
|
|
|
|
auto state = _machine->get_processor_state();
|
|
state.address[2] = 0xc000d;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[1], 0xc000c);
|
|
XCTAssertEqual(state.address[2], 0xc000d);
|
|
XCTAssertEqual(8, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testLEA_dAnDnw {
|
|
_machine->set_program({
|
|
0x43f2, 0x7002 // LEA (2,A2,D7.W), A1
|
|
});
|
|
|
|
auto state = _machine->get_processor_state();
|
|
state.address[2] = 0xc000d;
|
|
state.data[7] = 0x10000022;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[1], 0xc0031);
|
|
XCTAssertEqual(state.address[2], 0xc000d);
|
|
XCTAssertEqual(state.data[7], 0x10000022);
|
|
XCTAssertEqual(12, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testLEA_dAnDnl {
|
|
_machine->set_program({
|
|
0x43f2, 0x7802 // LEA (2,A2,D7.l), A1
|
|
});
|
|
|
|
auto state = _machine->get_processor_state();
|
|
state.address[2] = 0xc000d;
|
|
state.data[7] = 0x10000022;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[1], 0x100c0031);
|
|
XCTAssertEqual(state.address[2], 0xc000d);
|
|
XCTAssertEqual(state.data[7], 0x10000022);
|
|
XCTAssertEqual(12, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testLEA_dPC {
|
|
_machine->set_program({
|
|
0x43fa, 0xeff8 // LEA (-6,PC), A1
|
|
});
|
|
|
|
auto state = _machine->get_processor_state();
|
|
state.address[2] = 0xc000d;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[1], 0xFFFFFFFA);
|
|
XCTAssertEqual(8, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testLEA_dPCDn {
|
|
_machine->set_program({
|
|
0x43fb, 0x30fe // LEA (-6,PC,D3), A1
|
|
});
|
|
|
|
auto state = _machine->get_processor_state();
|
|
state.data[3] = 0x2;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[1], 0x1002);
|
|
XCTAssertEqual(state.data[3], 0x2);
|
|
XCTAssertEqual(12, _machine->get_cycle_count());
|
|
}
|
|
|
|
// MARK: LINK
|
|
|
|
- (void)testLINKA1_5 {
|
|
_machine->set_program({
|
|
0x4e51, 0x0005 // LINK a1, #5
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[1] = 0x11111111;
|
|
_machine->set_initial_stack_pointer(0x22222222);
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[1], 0x2222221e);
|
|
XCTAssertEqual(state.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
|
|
});
|
|
_machine->set_initial_stack_pointer(0x22222222);
|
|
|
|
_machine->run_for_instructions(1);
|
|
|
|
const auto state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.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
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[1] = 0x11111111;
|
|
_machine->set_initial_stack_pointer(0x22222222);
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[1], 0x2222221e);
|
|
XCTAssertEqual(state.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)
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[1] = 0x3000;
|
|
state.data[0] = 0x12345678;
|
|
state.data[1] = 0x87654321;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[1], 0x2ff8);
|
|
XCTAssertEqual(state.data[0], 0x12345678);
|
|
XCTAssertEqual(state.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)
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[1] = 0x3000;
|
|
state.data[0] = 0x12345678;
|
|
state.data[1] = 0x87654321;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[1], 0x2ff4);
|
|
XCTAssertEqual(state.data[0], 0x12345678);
|
|
XCTAssertEqual(state.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)
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
for(int c = 0; c < 8; ++c)
|
|
state.data[c] = (c+1) * 0x11111111;
|
|
for(int c = 0; c < 7; ++c)
|
|
state.address[c] = ((c < 4) ? (c + 9) : (c + 8)) * 0x11111111;
|
|
state.address[4] = 0x4000;
|
|
_machine->set_initial_stack_pointer(0xffffffff);
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.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)
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[4] = 0x4000;
|
|
state.data[4] = 0x111a1111;
|
|
state.data[0] = 0xffffffff;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
|
|
XCTAssertEqual(state.address[4], 0x3ffe);
|
|
XCTAssertEqual(state.data[0], 0xffffffff);
|
|
XCTAssertEqual(state.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
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.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->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
|
|
XCTAssertEqual(state.data[1], 0x11111111);
|
|
XCTAssertEqual(state.data[2], 0x22222222);
|
|
XCTAssertEqual(state.address[1], 0x4010);
|
|
XCTAssertEqual(state.address[2], 0x33333333);
|
|
|
|
XCTAssertEqual(44, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testMOVEMw_signExtend {
|
|
_machine->set_program({
|
|
0x4c99, 0x0002 // MOVEM.w (A1)+, D1
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[1] = 0x4000;
|
|
*_machine->ram_at(0x4000) = 0x8000;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
|
|
XCTAssertEqual(state.data[1], 0xffff8000);
|
|
XCTAssertEqual(state.address[1], 0x4002);
|
|
|
|
XCTAssertEqual(16, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testMOVEMw_fromIndirect {
|
|
_machine->set_program({
|
|
0x4c91, 0x0206 // MOVEM.w (A1), A1/D1-D2
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[1] = 0x4000;
|
|
state.data[2] = 0xffffffff;
|
|
*_machine->ram_at(0x4000) = 0x8000;
|
|
*_machine->ram_at(0x4002) = 0x2222;
|
|
*_machine->ram_at(0x4004) = 0x3333;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
|
|
XCTAssertEqual(state.data[1], 0xffff8000);
|
|
XCTAssertEqual(state.data[2], 0x00002222);
|
|
XCTAssertEqual(state.address[1], 0x3333);
|
|
|
|
XCTAssertEqual(24, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testMOVEMw_toIndirect {
|
|
_machine->set_program({
|
|
0x4891, 0x0206 // MOVEM.w A1/D1-D2, (A1)
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[1] = 0x4000;
|
|
state.data[1] = 0x11111111;
|
|
state.data[2] = 0x22222222;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
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.address[1], 0x4000);
|
|
|
|
XCTAssertEqual(20, _machine->get_cycle_count());
|
|
}
|
|
|
|
// MARK: MOVE
|
|
|
|
- (void)testMOVEb_DnDn {
|
|
_machine->set_program({
|
|
0x1401 // MOVE.b D1, D2
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.data[1] = 0x12345678;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.data[1], 0x12345678);
|
|
XCTAssertEqual(state.data[2], 0x00000078);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, 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.data[2], 0x8090fea1);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Negative);
|
|
XCTAssertEqual(12, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testMOVEs_ImmInd {
|
|
_machine->set_program({
|
|
0x34bc, 0x0000 // MOVE #$0, (A2)
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[2] = 0x3000;
|
|
*_machine->ram_at(0x3000) = 0x1234;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[2], 0x3000);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero);
|
|
XCTAssertEqual(*_machine->ram_at(0x3000), 0);
|
|
XCTAssertEqual(12, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testMOVEl_PostIncPostInc {
|
|
_machine->set_program({
|
|
0x24da // MOVE.l (A2)+, (A2)+
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[2] = 0x3000;
|
|
state.status = Flag::Negative;
|
|
*_machine->ram_at(0x3000) = 0xaaaa;
|
|
*_machine->ram_at(0x3002) = 0xbbbb;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[2], 0x3008);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::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)
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[2] = 0x3000;
|
|
state.status = Flag::Negative;
|
|
*_machine->ram_at(0x3000) = 0xaaaa;
|
|
*_machine->ram_at(0x3002) = 0xbbbb;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[2], 0x3000);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::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)
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[2] = 0x3004;
|
|
state.data[1] = 0;
|
|
state.status = Flag::Negative;
|
|
*_machine->ram_at(0x3000) = 0xaaaa;
|
|
*_machine->ram_at(0x3002) = 0xbbbb;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[2], 0x3000);
|
|
XCTAssertEqual(state.data[1], 0);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::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
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.data[1] = 0x5678;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.data[1], 0x5678);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, 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.status & Flag::ConditionCodes, 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
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[2] = 0xffffffff;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[2], 0xffffffff);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, 0);
|
|
XCTAssertEqual(4, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testMOVEAw_Dn_positive {
|
|
_machine->set_program({
|
|
0x3442 // MOVEA.w D2, A2
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[2] = 0xffffffff;
|
|
state.data[2] = 0x12345678;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[2], 0x00005678);
|
|
XCTAssertEqual(state.data[2], 0x12345678);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, 0);
|
|
XCTAssertEqual(4, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testMOVEAw_Dn_negative {
|
|
_machine->set_program({
|
|
0x3442 // MOVEA.w D2, A2
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[2] = 0xffffffff;
|
|
state.data[2] = 0x12348756;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[2], 0xffff8756);
|
|
XCTAssertEqual(state.data[2], 0x12348756);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, 0);
|
|
XCTAssertEqual(4, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testMOVEAl_Imm {
|
|
_machine->set_program({
|
|
0x247c, 0x0000, 0x0001 // MOVEA.L #$1, A2
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[2] = 0xffffffff;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[2], 1);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, 0);
|
|
XCTAssertEqual(12, _machine->get_cycle_count());
|
|
}
|
|
|
|
// MARK: MOVEP
|
|
|
|
- (void)testMOVEPw_toDn {
|
|
_machine->set_program({
|
|
0x030e, 0x0004 // MOVEP.w 4(A6), D1
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[6] = 0x3000;
|
|
*_machine->ram_at(0x3004) = 0x1200;
|
|
*_machine->ram_at(0x3006) = 0x3400;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[6], 0x3000);
|
|
XCTAssertEqual(state.data[1], 0x1234);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, 0);
|
|
XCTAssertEqual(16, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testMOVEPl_toDn {
|
|
_machine->set_program({
|
|
0x034e, 0x0002 // MOVEP.l 2(A6), D1
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[6] = 0x3000;
|
|
*_machine->ram_at(0x3002) = 0x1200;
|
|
*_machine->ram_at(0x3004) = 0x3400;
|
|
*_machine->ram_at(0x3006) = 0x5600;
|
|
*_machine->ram_at(0x3008) = 0x7800;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[6], 0x3000);
|
|
XCTAssertEqual(state.data[1], 0x12345678);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, 0);
|
|
XCTAssertEqual(24, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testMOVEPw_fromDn {
|
|
_machine->set_program({
|
|
0x038e, 0x0002 // MOVEP.w D1, 2(A6)
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[6] = 0x3000;
|
|
state.data[1] = 0x12345678;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[6], 0x3000);
|
|
XCTAssertEqual(*_machine->ram_at(0x3002), 0x5600);
|
|
XCTAssertEqual(*_machine->ram_at(0x3004), 0x7800);
|
|
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, 0);
|
|
XCTAssertEqual(16, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testMOVEPl_fromDn {
|
|
_machine->set_program({
|
|
0x03ce, 0x0002 // MOVEP.l D1, 2(A6)
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[6] = 0x3000;
|
|
state.data[1] = 0x12345678;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.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.status & Flag::ConditionCodes, 0);
|
|
XCTAssertEqual(24, _machine->get_cycle_count());
|
|
}
|
|
|
|
// MARK: MOVEQ
|
|
|
|
- (void)testMOVEQ_1 {
|
|
_machine->set_program({
|
|
0x7201 // MOVEQ #1, D1
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.data[1] = 0xffffffff;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.data[1], 0x1);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, 0);
|
|
XCTAssertEqual(4, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testMOVEQ_ff {
|
|
_machine->set_program({
|
|
0x72ff // MOVEQ #-1, D1
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.status |= Flag::Extend | Flag::Carry | Flag::Overflow;
|
|
|
|
_machine->set_processor_state(state);
|
|
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.data[1], 0xffffffff);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend | Flag::Negative);
|
|
XCTAssertEqual(4, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testMOVEQ_80 {
|
|
_machine->set_program({
|
|
0x7280 // MOVEQ #$80, D1
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.status |= Flag::Extend | Flag::Carry | Flag::Overflow;
|
|
state.data[1] = 0x12345678;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.data[1], 0xffffff80);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend | Flag::Negative);
|
|
XCTAssertEqual(4, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testMOVEQ_00 {
|
|
_machine->set_program({
|
|
0x7200 // MOVEQ #00, D1
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.status |= Flag::Extend | Flag::Carry | Flag::Overflow;
|
|
state.data[1] = 0x12345678;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.data[1], 0);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend | Flag::Zero);
|
|
XCTAssertEqual(4, _machine->get_cycle_count());
|
|
}
|
|
|
|
// MARK: MOVE from SR
|
|
|
|
- (void)testMoveFromSR {
|
|
_machine->set_program({
|
|
0x40c1 // MOVE SR, D1
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.status = 0x271f;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.data[1], 0x271f);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::ConditionCodes);
|
|
XCTAssertEqual(6, _machine->get_cycle_count());
|
|
}
|
|
|
|
// MARK: MOVE to CCR
|
|
|
|
- (void)testMoveToCCR {
|
|
_machine->set_program({
|
|
0x44fc, 0x001f // MOVE #$1f, CCR
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.status = 0; // i.e. not even supervisor.
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, 0x1f);
|
|
XCTAssertEqual(16, _machine->get_cycle_count());
|
|
}
|
|
|
|
// MARK: MOVE to SR
|
|
|
|
- (void)testMoveToSR {
|
|
_machine->set_program({
|
|
0x46fc, 0x0700 // MOVE #$700, SR
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.supervisor_stack_pointer = 0x3000;
|
|
state.user_stack_pointer = 0;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.stack_pointer(), 0);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, 0);
|
|
XCTAssertEqual(16, _machine->get_cycle_count());
|
|
}
|
|
|
|
// MARK: MOVE USP
|
|
|
|
- (void)testMoveUSP {
|
|
_machine->set_program({
|
|
0x4e69 // MOVE USP, A1
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[1] = 0x12348756;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[1], 0);
|
|
}
|
|
|
|
// MARK: PEA
|
|
|
|
- (void)testPEA_A1 {
|
|
_machine->set_program({
|
|
0x4851 // PEA (A1)
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[1] = 0x3000ffff;
|
|
_machine->set_initial_stack_pointer(0x1996);
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[1], 0x3000ffff);
|
|
XCTAssertEqual(state.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)
|
|
});
|
|
_machine->set_initial_stack_pointer(0x1012);
|
|
|
|
_machine->run_for_instructions(1);
|
|
|
|
const auto state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.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)
|
|
});
|
|
_machine->set_initial_stack_pointer(0x1012);
|
|
|
|
_machine->run_for_instructions(1);
|
|
|
|
const auto state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.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
|
|
});
|
|
_machine->set_initial_stack_pointer(0x1996);
|
|
|
|
_machine->run_for_instructions(1);
|
|
|
|
const auto state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.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)
|
|
});
|
|
_machine->set_initial_stack_pointer(0x1996);
|
|
|
|
_machine->run_for_instructions(1);
|
|
|
|
const auto state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.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
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.data[0] = 0x12345678;
|
|
state.status = Flag::Extend;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.data[0], 0x12345600);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend);
|
|
}
|
|
|
|
- (void)testSTDn {
|
|
_machine->set_program({
|
|
0x50c0 // ST D0
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.data[0] = 0x12345678;
|
|
state.status = Flag::Extend;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.data[0], 0x123456ff);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend);
|
|
}
|
|
|
|
- (void)testSLSDn {
|
|
_machine->set_program({
|
|
0x53c0 // SLS D0
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.data[0] = 0x12345678;
|
|
state.status = Flag::ConditionCodes;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.data[0], 0x123456ff);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::ConditionCodes);
|
|
}
|
|
|
|
- (void)testSGTAnXTrue {
|
|
_machine->set_program({
|
|
0x5ee8, 0x0002 // SGT 2(a0)
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[0] = 0x3000;
|
|
*_machine->ram_at(0x3002) = 0x8800;
|
|
state.status = Flag::Extend;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(*_machine->ram_at(0x3002), 0xff00);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend);
|
|
}
|
|
|
|
- (void)testSGTAnXFalse {
|
|
_machine->set_program({
|
|
0x5ee8, 0x0002 // SGT 2(a0)
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.address[0] = 0x3000;
|
|
*_machine->ram_at(0x3002) = 0x8800;
|
|
state.status = Flag::ConditionCodes;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(*_machine->ram_at(0x3002), 0x0000);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::ConditionCodes);
|
|
}
|
|
|
|
|
|
// MARK: SWAP
|
|
|
|
- (void)testSwap {
|
|
_machine->set_program({
|
|
0x4841 // SWAP D1
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.data[1] = 0x12348756;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.data[1], 0x87561234);
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Negative);
|
|
}
|
|
|
|
// MARK: TST
|
|
|
|
- (void)testTSTw_Dn {
|
|
_machine->set_program({
|
|
0x4a44 // TST.w D4
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.status |= Flag::Extend | Flag::Carry | Flag::Overflow;
|
|
state.data[4] = 0xfff1;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Negative | Flag::Extend);
|
|
XCTAssertEqual(state.data[4], 0xfff1);
|
|
XCTAssertEqual(4, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testTSTl_Dn {
|
|
_machine->set_program({
|
|
0x4a84 // TST.l D4
|
|
});
|
|
auto state = _machine->get_processor_state();
|
|
state.status |= Flag::Extend | Flag::Carry | Flag::Overflow;
|
|
state.data[4] = 0;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero | Flag::Extend);
|
|
XCTAssertEqual(state.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
|
|
});
|
|
|
|
auto state = _machine->get_processor_state();
|
|
state.address[6] = 0x3000;
|
|
*_machine->ram_at(0x3000) = 0x0000;
|
|
*_machine->ram_at(0x3002) = 0x4000;
|
|
|
|
_machine->set_processor_state(state);
|
|
_machine->run_for_instructions(1);
|
|
|
|
state = _machine->get_processor_state();
|
|
XCTAssertEqual(state.address[6], 0x4000);
|
|
XCTAssertEqual(state.supervisor_stack_pointer, 0x3004);
|
|
XCTAssertEqual(12, _machine->get_cycle_count());
|
|
}
|
|
|
|
- (void)testUNLINK_A7 {
|
|
_machine->set_program({
|
|
0x4e5f // UNLNK A7
|
|
});
|
|
_machine->set_initial_stack_pointer(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.supervisor_stack_pointer, 0x4000);
|
|
XCTAssertEqual(12, _machine->get_cycle_count());
|
|
}
|
|
|
|
@end
|