1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 08:49:37 +00:00
CLK/OSBindings/Mac/Clock SignalTests/68000ArithmeticTests.mm
Thomas Harte 640b04e59e Test only well-defined flags.
Albeit that timing is still off.
2022-06-03 10:18:46 -04:00

1695 lines
53 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 M68000ArithmeticTests : XCTestCase
@end
@implementation M68000ArithmeticTests {
std::unique_ptr<RAM68000> _machine;
}
- (RAM68000 *)machine {
return _machine.get();
}
- (void)setUp {
_machine = std::make_unique<RAM68000>();
}
- (void)tearDown {
_machine.reset();
}
@end
// MARK: - ADD
@interface M68000ADDTests : M68000ArithmeticTests
@end
@implementation M68000ADDTests
- (void)testADDb {
self.machine->set_program({
0x0602, 0xff // ADD.B #$ff, D2
});
self.machine->set_registers([=](auto &registers) {
registers.data[2] = 0x9ae;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Negative | ConditionCode::Extend);
XCTAssertEqual(state.registers.data[2], 0x9ad);
XCTAssertEqual(8, self.machine->get_cycle_count());
}
- (void)testADDb_Overflow {
self.machine->set_program({
0xd43c, 0x82 // ADD.B #$82, D2
});
self.machine->set_registers([=](auto &registers) {
registers.data[2] = 0x82;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Overflow | ConditionCode::Carry | ConditionCode::Extend);
XCTAssertEqual(state.registers.data[2], 0x04);
XCTAssertEqual(8, self.machine->get_cycle_count());
}
- (void)testADDb_XXXw {
self.machine->set_program({
0xd538, 0x3000 // ADD.B D2, ($3000).W
});
self.machine->set_registers([=](auto &registers) {
registers.data[2] = 0x82;
});
*self.machine->ram_at(0x3000) = 0x8200;
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Overflow | ConditionCode::Carry | ConditionCode::Extend);
XCTAssertEqual(state.registers.data[2], 0x82);
XCTAssertEqual(*self.machine->ram_at(0x3000), 0x0400);
XCTAssertEqual(16, self.machine->get_cycle_count());
}
- (void)testADDw_DnDn {
self.machine->set_program({
0xd442 // ADD.W D2, D2
});
self.machine->set_registers([=](auto &registers) {
registers.data[2] = 0x3e8;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[2], 0x7D0);
XCTAssertEqual(4, self.machine->get_cycle_count());
}
- (void)testADDl_DnPostInc {
self.machine->set_program({
0xd59a // ADD.L D2, (A2)+
});
self.machine->set_registers([=](auto &registers) {
registers.data[2] = 0xb2d05e00;
registers.address[2] = 0x2000;
});
*self.machine->ram_at(0x2000) = 0x7735;
*self.machine->ram_at(0x2002) = 0x9400;
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[2], 0xb2d05e00);
XCTAssertEqual(*self.machine->ram_at(0x2000), 0x2a05);
XCTAssertEqual(*self.machine->ram_at(0x2002), 0xf200);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Extend);
XCTAssertEqual(20, self.machine->get_cycle_count());
}
- (void)testADDw_PreDec {
self.machine->set_program({
0xd462 // ADD.W -(A2), D2
});
self.machine->set_registers([=](auto &registers) {
registers.data[2] = 0xFFFF0000;
registers.address[2] = 0x2002;
});
*self.machine->ram_at(0x2000) = 0;
*self.machine->ram_at(0x2002) = 0xffff;
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[2], 0xFFFF0000);
XCTAssertEqual(state.registers.address[2], 0x2000);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Zero);
XCTAssertEqual(10, self.machine->get_cycle_count());
}
/*
ADD.B A2, D2 test omitted; no such opcode exists on the 68000.
See P4-5 of the 68000PRM: An is defined for word and long only.
*/
- (void)testADDl_DnDn {
self.machine->set_program({
0xd481 // ADD.l D1, D2
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = 0xfe35aab0;
registers.data[2] = 0x012557ac;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xfe35aab0);
XCTAssertEqual(state.registers.data[2], 0xff5b025c);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative);
XCTAssertEqual(8, self.machine->get_cycle_count());
}
@end
// MARK: - ADDA
@interface M68000ADDATests : M68000ArithmeticTests
@end
@implementation M68000ADDATests
- (void)testADDAL {
self.machine->set_program({
0xd5fc, 0x1234, 0x5678 // ADDA.L #$12345678, A2
});
self.machine->set_registers([=](auto &registers) {
registers.address[2] = 0xae43ab1d;
registers.status = ConditionCode::AllConditions;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.address[2], 0xc0780195);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::AllConditions);
}
- (void)testADDAWPositive {
self.machine->set_program({
0xd4fc, 0x5678 // ADDA.W #$5678, A2
});
self.machine->set_registers([=](auto &registers) {
registers.address[2] = 0xae43ab1d;
registers.status = ConditionCode::AllConditions;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.address[2], 0xae440195);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::AllConditions);
}
- (void)testADDAWNegative {
self.machine->set_program({
0xd4fc, 0xf678 // ADDA.W #$f678, A2
});
self.machine->set_registers([=](auto &registers) {
registers.address[2] = 0xae43ab1d;
registers.status = ConditionCode::AllConditions;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.address[2], 0xae43a195);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::AllConditions);
}
- (void)testADDAWNegative_2 {
self.machine->set_program({
0xd4fc, 0xf000 // ADDA.W #$f000, A2
});
self.machine->set_registers([=](auto &registers) {
registers.status = ConditionCode::AllConditions;
registers.address[2] = 0;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.address[2], 0xfffff000);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::AllConditions);
}
- (void)testADDALPreDec {
self.machine->set_program({
0xd5e2 // ADDA.L -(A2), A2
});
self.machine->set_registers([=](auto &registers) {
registers.status = ConditionCode::AllConditions;
registers.address[2] = 0x2004;
});
*self.machine->ram_at(0x2000) = 0x7002;
*self.machine->ram_at(0x2002) = 0;
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.address[2], 0x70022000);
XCTAssertEqual(*self.machine->ram_at(0x2000), 0x7002);
XCTAssertEqual(*self.machine->ram_at(0x2002), 0x0000);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::AllConditions);
}
@end
// MARK: - ADDX
@interface M68000ADDXTests : M68000ArithmeticTests
@end
@implementation M68000ADDXTests
- (void)testADDXl_Dn {
self.machine->set_program({
0xd581 // ADDX.l D1, D2
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = 0x12345678;
registers.data[2] = 0x12345678;
registers.status |= ConditionCode::AllConditions;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x12345678);
XCTAssertEqual(state.registers.data[2], 0x2468acf1);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(8, self.machine->get_cycle_count());
}
- (void)testADDXb {
self.machine->set_program({
0xd501 // ADDX.b D1, D2
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = 0x80;
registers.data[2] = 0x8080;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x80);
XCTAssertEqual(state.registers.data[2], 0x8000);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Overflow | ConditionCode::Extend);
XCTAssertEqual(4, self.machine->get_cycle_count());
}
- (void)testADDXw {
self.machine->set_program({
0xd541 // ADDX.w D1, D2
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = 0x1ffff;
registers.data[2] = 0x18080;
registers.status |= ConditionCode::AllConditions;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x1ffff);
XCTAssertEqual(state.registers.data[2], 0x18080);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Negative | ConditionCode::Extend);
XCTAssertEqual(4, self.machine->get_cycle_count());
}
- (void)testADDXl_PreDec {
self.machine->set_program({
0xd389 // ADDX.l -(A1), -(A1)
});
self.machine->set_registers([=](auto &registers) {
registers.address[1] = 0x3000;
registers.status |= ConditionCode::AllConditions;
});
*self.machine->ram_at(0x2ff8) = 0x1000;
*self.machine->ram_at(0x2ffa) = 0x0000;
*self.machine->ram_at(0x2ffc) = 0x7000;
*self.machine->ram_at(0x2ffe) = 0x1ff1;
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.address[1], 0x2ff8);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative | ConditionCode::Overflow);
XCTAssertEqual(*self.machine->ram_at(0x2ff8), 0x8000);
XCTAssertEqual(*self.machine->ram_at(0x2ffa), 0x1ff2);
XCTAssertEqual(*self.machine->ram_at(0x2ffc), 0x7000);
XCTAssertEqual(*self.machine->ram_at(0x2ffe), 0x1ff1);
XCTAssertEqual(30, self.machine->get_cycle_count());
}
@end
// MARK: - ADDI
@interface M68000ADDITests : M68000ArithmeticTests
@end
@implementation M68000ADDITests
- (void)testADDIl {
self.machine->set_program({
0x0681, 0x1111, 0x1111 // ADDI.l #$11111111, D1
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = 0x300021b3;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x411132C4);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(16, self.machine->get_cycle_count());
}
- (void)testADDIw {
self.machine->set_program({
0x0678, 0x7aaa, 0x3000 // ADDI.W #$7aaa, ($3000).W
});
*self.machine->ram_at(0x3000) = 0xaaaa;
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(*self.machine->ram_at(0x3000), 0x2554);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Carry);
XCTAssertEqual(20, self.machine->get_cycle_count());
}
@end
// MARK: - ADDQ
@interface M68000ADDQTests : M68000ArithmeticTests
@end
@implementation M68000ADDQTests
- (void)testADDQl {
self.machine->set_program({
0x5e81 // ADDQ.l #$7, D1
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = 0xffffffff;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x6);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Carry);
XCTAssertEqual(8, self.machine->get_cycle_count());
}
- (void)testADDQw_Dn {
self.machine->set_program({
0x5641 // ADDQ.W #$3, D1
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = 0xfffffffe;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xffff0001);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Carry);
XCTAssertEqual(4, self.machine->get_cycle_count());
}
- (void)testADDQw_An {
self.machine->set_program({
0x5649 // ADDQ.W #$3, A1
});
self.machine->set_registers([=](auto &registers) {
registers.address[1] = 0xfffffffe;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.address[1], 1);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(8, self.machine->get_cycle_count());
}
- (void)testADDQw_XXXw {
self.machine->set_program({
0x5078, 0x3000 // ADDQ.W #$8, ($3000).W
});
*self.machine->ram_at(0x3000) = 0x7ffd;
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(*self.machine->ram_at(0x3000), 0x8005);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative | ConditionCode::Overflow);
XCTAssertEqual(16, self.machine->get_cycle_count());
}
@end
// MARK: - CMP
@interface M68000CMPTests : M68000ArithmeticTests
@end
@implementation M68000CMPTests
- (void)performCMPb:(uint16_t)opcode expectedFlags:(uint16_t)flags {
self.machine->set_program({
opcode
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = 0x1234567f;
registers.data[2] = 0x12345680;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x1234567f);
XCTAssertEqual(state.registers.data[2], 0x12345680);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, flags);
XCTAssertEqual(4, self.machine->get_cycle_count());
}
- (void)testCMPb_D1D2 {
[self performCMPb:0xb401 expectedFlags:ConditionCode::Overflow]; // CMP.b D1, D2
}
- (void)testCMPb_D2D1 {
[self performCMPb:0xb202 expectedFlags:ConditionCode::Overflow | ConditionCode::Negative | ConditionCode::Carry]; // CMP.b D2, D1
}
- (void)performCMPwd1:(uint32_t)d1 d2:(uint32_t)d2 expectedFlags:(uint16_t)flags {
self.machine->set_program({
0xb242 // CMP.W D2, D1
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = d1;
registers.data[2] = d2;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], d1);
XCTAssertEqual(state.registers.data[2], d2);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, flags);
XCTAssertEqual(4, self.machine->get_cycle_count());
}
- (void)testCMPw_8004v7002 {
[self performCMPwd1:0x12347002 d2:0x12348004 expectedFlags:ConditionCode::Overflow | ConditionCode::Negative | ConditionCode::Carry];
}
- (void)testCMPw_6666v5555 {
[self performCMPwd1:0x55555555 d2:0x66666666 expectedFlags:ConditionCode::Negative | ConditionCode::Carry];
}
- (void)testCMPl {
self.machine->set_program({
0xb282 // CMP.l D2, D1
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = 0x12347002;
registers.data[2] = 0x12348004;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x12347002);
XCTAssertEqual(state.registers.data[2], 0x12348004);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative | ConditionCode::Carry);
XCTAssertEqual(6, self.machine->get_cycle_count());
}
@end
// MARK: - CMPA
@interface M68000CMPATests : M68000ArithmeticTests
@end
@implementation M68000CMPATests
- (void)performCMPAld1:(uint32_t)d1 a2:(uint32_t)a2 {
self.machine->set_program({
0xb5c1 // CMPA.l D1, A2
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = d1;
registers.address[2] = a2;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], d1);
XCTAssertEqual(state.registers.address[2], a2);
XCTAssertEqual(6, self.machine->get_cycle_count());
}
- (void)testCMPAl_noFlags {
[self performCMPAld1:0x1234567f a2:0x12345680];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
}
- (void)testCMPAl_carry {
[self performCMPAld1:0xfd234577 a2:0x12345680];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry);
}
- (void)testCMPAl_carryOverflowNegative {
[self performCMPAld1:0x85678943 a2:0x22563245];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Overflow | ConditionCode::Negative);
}
- (void)performCMPAwd1:(uint32_t)d1 a2:(uint32_t)a2 {
self.machine->set_program({
0xb4c1 // CMPA.w D1, A2
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = d1;
registers.address[2] = a2;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], d1);
XCTAssertEqual(state.registers.address[2], a2);
XCTAssertEqual(6, self.machine->get_cycle_count());
}
- (void)testCMPAw_carry {
[self performCMPAwd1:0x85678943 a2:0x22563245];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry);
}
- (void)testCMPAw_zero {
[self performCMPAwd1:0x0000ffff a2:0xffffffff];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Zero);
}
@end
// MARK: CMPI
@interface M68000CMPITests : M68000ArithmeticTests
@end
@implementation M68000CMPITests
- (void)testCMPIw {
self.machine->set_program({
0x0c41, 0xffff // CMPI.W #$ffff, D1
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = 0xfff2ffff;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xfff2ffff);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Zero);
XCTAssertEqual(8, self.machine->get_cycle_count());
}
- (void)testCMPIl {
self.machine->set_program({
0x0c81, 0x8000, 0x0000 // CMPI.L #$80000000, D1
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = 0x7fffffff;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x7fffffff);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative | ConditionCode::Overflow | ConditionCode::Carry);
XCTAssertEqual(14, self.machine->get_cycle_count());
}
- (void)testCMPIb {
self.machine->set_program({
0x0c01, 0x0090 // CMPI.B #$90, D1
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = 0x8f;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x8f);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative | ConditionCode::Carry);
XCTAssertEqual(8, self.machine->get_cycle_count());
}
@end
// MARK: - CMPM
@interface M68000CMPMTests : M68000ArithmeticTests
@end
@implementation M68000CMPMTests
- (void)testCMPMl {
self.machine->set_program({
0xb389 // CMPM.L (A1)+, (A1)+
});
self.machine->set_registers([=](auto &registers) {
registers.address[1] = 0x3000;
registers.status |= ConditionCode::AllConditions;
});
*self.machine->ram_at(0x3000) = 0x7000;
*self.machine->ram_at(0x3002) = 0x1ff1;
*self.machine->ram_at(0x3004) = 0x1000;
*self.machine->ram_at(0x3006) = 0x0000;
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.address[1], 0x3008);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative | ConditionCode::Extend | ConditionCode::Carry);
XCTAssertEqual(20, self.machine->get_cycle_count());
}
- (void)testCMPMw {
self.machine->set_program({
0xb549 // CMPM.w (A1)+, (A2)+
});
self.machine->set_registers([=](auto &registers) {
registers.address[1] = 0x3000;
registers.address[2] = 0x3002;
registers.status |= ConditionCode::AllConditions;
});
*self.machine->ram_at(0x3000) = 0;
*self.machine->ram_at(0x3002) = 0;
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.address[1], 0x3002);
XCTAssertEqual(state.registers.address[2], 0x3004);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Zero | ConditionCode::Extend);
XCTAssertEqual(12, self.machine->get_cycle_count());
}
- (void)testCMPMb {
self.machine->set_program({
0xb509 // CMPM.b (A1)+, (A2)+
});
self.machine->set_registers([=](auto &registers) {
registers.address[1] = 0x3000;
registers.address[2] = 0x3001;
registers.status |= ConditionCode::AllConditions;
});
*self.machine->ram_at(0x3000) = 0x807f;
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.address[1], 0x3001);
XCTAssertEqual(state.registers.address[2], 0x3002);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative | ConditionCode::Extend | ConditionCode::Carry | ConditionCode::Overflow);
XCTAssertEqual(12, self.machine->get_cycle_count());
}
@end
// MARK: - DIVS
@interface M68000DIVSTests : M68000ArithmeticTests
@end
@implementation M68000DIVSTests
- (void)performDIVS:(uint16_t)divisor d1:(uint32_t)d1 sp:(uint32_t)sp {
self.machine->set_program({
0x83fc, divisor // DIVS #divisor, D1
}, sp);
self.machine->set_registers([=](auto &registers) {
registers.data[1] = d1;
registers.status |= ConditionCode::AllConditions;
});
self.machine->run_for_instructions(1);
}
- (void)performDIVS:(uint16_t)divisor d1:(uint32_t)d1 {
[self performDIVS:divisor d1:d1 sp:0];
}
- (void)performDIVSOverflowTestDivisor:(uint16_t)divisor {
[self performDIVS:divisor d1:0x4768f231];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x4768f231);
// N and Z are officially undefined upon DIVS overflow, and I've found no
// other relevant information.
XCTAssertEqual(
state.registers.status & (ConditionCode::Extend | ConditionCode::Overflow | ConditionCode::Carry),
ConditionCode::Extend | ConditionCode::Overflow);
XCTAssertEqual(20, self.machine->get_cycle_count());
}
- (void)testDIVSOverflow {
[self performDIVSOverflowTestDivisor:1];
}
- (void)testDIVSOverflow2 {
[self performDIVSOverflowTestDivisor:0x1234];
}
- (void)testDIVSUnderflow {
[self performDIVSOverflowTestDivisor:0xeeff];
}
- (void)testDIVS_2 {
[self performDIVS:0xeef0 d1:0x0768f231];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x026190D3);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative);
XCTAssertEqual(138, self.machine->get_cycle_count());
}
- (void)testDIVS_3 {
[self performDIVS:0xffff d1:0xffffffff];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 1);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend);
XCTAssertEqual(158, self.machine->get_cycle_count());
}
- (void)testDIVS_4 {
[self performDIVS:0x3333 d1:0xffff0000];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xfffffffb);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative);
XCTAssertEqual(158, self.machine->get_cycle_count());
}
- (void)testDIVS_5 {
[self performDIVS:0x23 d1:0x8765];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xb03de);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend);
XCTAssertEqual(138, self.machine->get_cycle_count());
}
- (void)testDIVS_6 {
[self performDIVS:0x8765 d1:0x65];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x650000);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Zero);
XCTAssertEqual(156, self.machine->get_cycle_count());
}
- (void)testDIVSExpensiveOverflow {
// DIVS.W #$ffff, D1 alt
[self performDIVS:0xffff d1:0x80000000];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x80000000);
XCTAssertEqual(
state.registers.status & (ConditionCode::Extend | ConditionCode::Overflow | ConditionCode::Carry),
ConditionCode::Extend | ConditionCode::Overflow);
XCTAssertEqual(158, self.machine->get_cycle_count());
}
- (void)testDIVS_8 {
// DIVS.W #$fffd, D1
[self performDIVS:0xfffd d1:0xfffffffd];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x1);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend);
XCTAssertEqual(158, self.machine->get_cycle_count());
}
- (void)testDIVS_9 {
// DIVS.W #$7aee, D1
[self performDIVS:0x7aee d1:0xdaaa00fe];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xc97eb240);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative);
XCTAssertEqual(148, self.machine->get_cycle_count());
}
- (void)testDIVS_10 {
// DIVS.W #$7fff, D1
[self performDIVS:0x7fff d1:0x82f9fff];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x305e105f);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend);
XCTAssertEqual(142, self.machine->get_cycle_count());
}
- (void)testDIVS_11 {
// DIVS.W #$f32, D1
[self performDIVS:0xf32 d1:0x00e1d44];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x0bfa00ed);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend);
XCTAssertEqual(144, self.machine->get_cycle_count());
}
- (void)testDIVS_12 {
// DIVS.W #$af32, D1
[self performDIVS:0xaf32 d1:0xe1d44 sp:0];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x39dcffd4);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative);
XCTAssertEqual(150, self.machine->get_cycle_count());
}
- (void)testDIVSException {
// DIVS.W #0, D1
const uint32_t initial_sp = 0x5000;
[self performDIVS:0x0 d1:0x1fffffff sp:initial_sp];
// Check register state.registers.
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x1fffffff);
XCTAssertEqual(state.registers.supervisor_stack_pointer, initial_sp - 6);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend);
// Total expected bus pattern:
//
// np | nn nn | nw nw nw np np np n np = 42 cycles
//
// Noted: Yacht shows a total of three nps for a DIVS #;
// I believe this is incorrect as it includes two in the
// '1st op (ea)' stage, but an immediate word causes
// only one elsewhere.
XCTAssertEqual(42, self.machine->get_cycle_count());
// Check stack contents; should be PC.l, PC.h and status register.
// Assumed: the program counter on the stack is that of the
// failing instrustion.
const uint16_t pc_h = *self.machine->ram_at(initial_sp-4);
const uint16_t pc_l = *self.machine->ram_at(initial_sp-2);
// const uint16_t status = *self.machine->ram_at(initial_sp);
const uint32_t initial_pc = self.machine->initial_pc();
XCTAssertEqual(pc_l, initial_pc & 0xffff);
XCTAssertEqual(pc_h, initial_pc >> 16);
// XCTAssertEqual(status, 9);
}
@end
// MARK: - DIVU
@interface M68000DIVUTests : M68000ArithmeticTests
@end
@implementation M68000DIVUTests
- (void)performDIVU:(uint16_t)divisor d1:(uint32_t)d1 {
self.machine->set_program({
0x82fc, divisor // DIVU #$eef0, D1
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = d1;
registers.status |= ConditionCode::AllConditions;
});
self.machine->run_for_instructions(1);
}
- (void)testDIVU_0001 {
[self performDIVU:1 d1:0x4768f231];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x4768f231);
// This test should produce overflow; so don't test N or Z flags.
XCTAssertEqual(
state.registers.status & (ConditionCode::Carry | ConditionCode::Overflow | ConditionCode::Extend),
ConditionCode::Extend | ConditionCode::Overflow);
XCTAssertEqual(14, self.machine->get_cycle_count());
}
- (void)testDIVU_1234 {
[self performDIVU:0x1234 d1:0x4768f231];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x4768f231);
// This test should also produce overflow; so don't test N or Z flags.
XCTAssertEqual(
state.registers.status & (ConditionCode::Carry | ConditionCode::Overflow | ConditionCode::Extend),
ConditionCode::Extend | ConditionCode::Overflow);
XCTAssertEqual(14, self.machine->get_cycle_count());
}
- (void)testDIVU_eeff {
[self performDIVU:0xeeff d1:0x4768f231];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x8bae4c7d);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend);
XCTAssertEqual(108, self.machine->get_cycle_count());
}
- (void)testDIVU_3333 {
[self performDIVU:0x3333 d1:0x1fffffff];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x1fffa000);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative);
XCTAssertEqual(136, self.machine->get_cycle_count());
}
// Omitted: divide by zero test.
@end
// MARK: - EXT
@interface M68000EXTTests : M68000ArithmeticTests
@end
@implementation M68000EXTTests
- (void)performEXTwd3:(uint32_t)d3 {
self.machine->set_program({
0x4883 // EXT.W D3
});
self.machine->set_registers([=](auto &registers) {
registers.data[3] = d3;
registers.status = 0x13;
});
self.machine->run_for_instructions(1);
XCTAssertEqual(4, self.machine->get_cycle_count());
}
- (void)testEXTw_78 {
[self performEXTwd3:0x12345678];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[3], 0x12340078);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend);
}
- (void)testEXTw_00 {
[self performEXTwd3:0x12345600];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[3], 0x12340000);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Zero);
}
- (void)testEXTw_f0 {
[self performEXTwd3:0x123456f0];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[3], 0x1234fff0);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative);
}
- (void)testEXTl {
self.machine->set_program({
0x48c3 // EXT.L D3
});
self.machine->set_registers([=](auto &registers) {
registers.data[3] = 0x1234f6f0;
registers.status = 0x13;
});
self.machine->run_for_instructions(1);
XCTAssertEqual(4, self.machine->get_cycle_count());
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[3], 0xfffff6f0);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative);
}
@end
// MARK: - MULS
@interface M68000MULSTests : M68000ArithmeticTests
@end
@implementation M68000MULSTests
- (void)performMULSd1:(uint32_t)d1 d2:(uint32_t)d2 ccr:(uint8_t)ccr {
self.machine->set_program({
0xc5c1 // MULS D1, D2
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = d1;
registers.data[2] = d2;
registers.status = ccr;
});
self.machine->run_for_instructions(1);
}
- (void)performMULSConstant:(uint16_t)constant d2:(uint32_t)d2 {
self.machine->set_program({
0xc5fc, constant // MULS #constant, D2
});
self.machine->set_registers([=](auto &registers) {
registers.data[2] = d2;
registers.status = ConditionCode::Carry | ConditionCode::Extend | ConditionCode::Overflow;
});
self.machine->run_for_instructions(1);
}
- (void)testMULS {
[self performMULSd1:0x12345678 d2:0x12345678 ccr:0];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x12345678);
XCTAssertEqual(state.registers.data[2], 0x1d34d840);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(54, self.machine->get_cycle_count());
}
- (void)testMULS_2 {
[self performMULSd1:0x82348678 d2:0x823486ff ccr:0];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x82348678);
XCTAssertEqual(state.registers.data[2], 0x3971c188);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(48, self.machine->get_cycle_count());
}
- (void)testMULSZero {
[self performMULSd1:1 d2:0 ccr:ConditionCode::Carry | ConditionCode::Overflow | ConditionCode::Extend];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 1);
XCTAssertEqual(state.registers.data[2], 0);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Zero);
XCTAssertEqual(42, self.machine->get_cycle_count());
}
- (void)testMULSFFFF {
[self performMULSConstant:0xffff d2:0xffff];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[2], 1);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend);
XCTAssertEqual(44, self.machine->get_cycle_count());
}
- (void)testMULSNegative {
[self performMULSConstant:0x1fff d2:0x8fff];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[2], 0xf2005001);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative);
XCTAssertEqual(46, self.machine->get_cycle_count());
}
@end
// MARK: - MULU
@interface M68000MULUTests : M68000ArithmeticTests
@end
@implementation M68000MULUTests
- (void)performMULUd1:(uint32_t)d1 d2:(uint32_t)d2 ccr:(uint8_t)ccr {
self.machine->set_program({
0xc4c1 // MULU D1, D2
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = d1;
registers.data[2] = d2;
registers.status |= ccr;
});
self.machine->run_for_instructions(1);
}
- (void)testMULU_Dn {
[self performMULUd1:0x12345678 d2:0x12345678 ccr:0];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[2], 0x1d34d840);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(54, self.machine->get_cycle_count());
}
- (void)testMULU_Dn_Zero {
[self performMULUd1:1 d2:0 ccr:ConditionCode::Extend | ConditionCode::Overflow | ConditionCode::Carry];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 1);
XCTAssertEqual(state.registers.data[2], 0);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Zero);
XCTAssertEqual(40, self.machine->get_cycle_count());
}
- (void)testMULU_Imm {
self.machine->set_program({
0xc4fc, 0xffff // MULU.W #$ffff, D2
});
self.machine->set_registers([=](auto &registers) {
registers.data[2] = 0xffff;
registers.status |= ConditionCode::Extend | ConditionCode::Overflow | ConditionCode::Carry;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[2], 0xfffe0001);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative);
XCTAssertEqual(74, self.machine->get_cycle_count());
}
@end
// MARK: - NEG
@interface M68000NEGTests : M68000ArithmeticTests
@end
@implementation M68000NEGTests
- (void)performNEGb:(uint32_t)value {
self.machine->set_program({
0x4400 // NEG.b D0
});
self.machine->set_registers([=](auto &registers) {
registers.data[0] = value;
});
self.machine->run_for_instructions(1);
XCTAssertEqual(4, self.machine->get_cycle_count());
}
- (void)testNEGb_78 {
[self performNEGb:0x12345678];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0x12345688);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Extend | ConditionCode::Negative);
}
- (void)testNEGb_00 {
[self performNEGb:0x12345600];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0x12345600);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Zero);
}
- (void)testNEGb_80 {
[self performNEGb:0x12345680];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0x12345680);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative | ConditionCode::Overflow | ConditionCode::Extend | ConditionCode::Carry);
}
- (void)testNEGw {
self.machine->set_program({
0x4440 // NEG.w D0
});
self.machine->set_registers([=](auto &registers) {
registers.data[0] = 0x12348000;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(4, self.machine->get_cycle_count());
XCTAssertEqual(state.registers.data[0], 0x12348000);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative | ConditionCode::Overflow | ConditionCode::Extend | ConditionCode::Carry);
}
- (void)performNEGl:(uint32_t)value {
self.machine->set_program({
0x4480 // NEG.l D0
});
self.machine->set_registers([=](auto &registers) {
registers.data[0] = value;
});
self.machine->run_for_instructions(1);
XCTAssertEqual(6, self.machine->get_cycle_count());
}
- (void)testNEGl_large {
[self performNEGl:0x12345678];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0xedcba988);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Extend | ConditionCode::Negative);
}
- (void)testNEGl_small {
[self performNEGl:0xffffffff];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0x1);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Extend);
}
- (void)testNEGl_XXXl {
self.machine->set_program({
0x44b9, 0x0000, 0x3000 // NEG.L ($3000).L
});
*self.machine->ram_at(0x3000) = 0xf001;
*self.machine->ram_at(0x3002) = 0x2311;
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(28, self.machine->get_cycle_count());
XCTAssertEqual(*self.machine->ram_at(0x3000), 0x0ffe);
XCTAssertEqual(*self.machine->ram_at(0x3002), 0xdcef);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Carry);
}
@end
// MARK: - NEGX
@interface M68000NEGXTests : M68000ArithmeticTests
@end
@implementation M68000NEGXTests
- (void)performNEGXb:(uint32_t)value {
self.machine->set_program({
0x4000 // NEGX.b D0
});
self.machine->set_registers([=](auto &registers) {
registers.data[0] = value;
registers.status |= ConditionCode::Extend;
});
self.machine->run_for_instructions(1);
XCTAssertEqual(4, self.machine->get_cycle_count());
}
- (void)testNEGXb_78 {
[self performNEGXb:0x12345678];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0x12345687);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Extend | ConditionCode::Negative);
}
- (void)testNEGXb_00 {
[self performNEGXb:0x12345600];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0x123456ff);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Extend | ConditionCode::Negative);
}
- (void)testNEGXb_80 {
[self performNEGXb:0x12345680];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0x1234567f);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Carry);
}
- (void)testNEGXw {
self.machine->set_program({
0x4040 // NEGX.w D0
});
self.machine->set_registers([=](auto &registers) {
registers.data[0] = 0x12348000;
registers.status |= ConditionCode::Extend;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(4, self.machine->get_cycle_count());
XCTAssertEqual(state.registers.data[0], 0x12347fff);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Carry);
}
- (void)performNEGXl:(uint32_t)value {
self.machine->set_program({
0x4080 // NEGX.l D0
});
self.machine->set_registers([=](auto &registers) {
registers.data[0] = value;
registers.status |= ConditionCode::Extend;
});
self.machine->run_for_instructions(1);
XCTAssertEqual(6, self.machine->get_cycle_count());
}
- (void)testNEGXl_large {
[self performNEGXl:0x12345678];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0xedcba987);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Extend | ConditionCode::Negative);
}
- (void)testNEGXl_small {
[self performNEGXl:0xffffffff];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0x0);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Extend);
}
- (void)testNEGXl_XXXl {
self.machine->set_program({
0x40b9, 0x0000, 0x3000 // NEGX.L ($3000).L
});
self.machine->set_registers([=](auto &registers) {
registers.status |= ConditionCode::Extend;
});
*self.machine->ram_at(0x3000) = 0xf001;
*self.machine->ram_at(0x3002) = 0x2311;
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(28, self.machine->get_cycle_count());
XCTAssertEqual(*self.machine->ram_at(0x3000), 0x0ffe);
XCTAssertEqual(*self.machine->ram_at(0x3002), 0xdcee);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Carry);
}
@end
// MARK: - SUB
@interface M68000SUBTests : M68000ArithmeticTests
@end
@implementation M68000SUBTests
- (void)performSUBbIMM:(uint16_t)value d2:(uint32_t)d2 {
self.machine->set_program({
0x0402, value // SUB.b #value, D2
});
self.machine->set_registers([=](auto &registers) {
registers.data[2] = d2;
});
self.machine->run_for_instructions(1);
XCTAssertEqual(8, self.machine->get_cycle_count());
}
- (void)testSUBb_IMM_ff {
[self performSUBbIMM:0xff d2:0x9ae];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[2], 0x9af);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Negative | ConditionCode::Extend);
}
- (void)testSUBb_IMM_82 {
[self performSUBbIMM:0x82 d2:0x0a];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[2], 0x88);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Negative | ConditionCode::Overflow | ConditionCode::Extend);
}
- (void)testSUBb_IMM_f0 {
[self performSUBbIMM:0xf0 d2:0x64];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[2], 0x74);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Extend);
}
- (void)testSUBb_IMM_28 {
[self performSUBbIMM:0x28 d2:0xff96];
const auto state = self.machine->get_processor_state();
XCTAssertEqual(state.registers.data[2], 0xff6e);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Overflow);
}
- (void)testSUBb_PreDec {
self.machine->set_program({
0x9427 // SUB.b -(A7), D2
}, 0x2002);
self.machine->set_registers([=](auto &registers) {
registers.data[2] = 0x9c40;
});
*self.machine->ram_at(0x2000) = 0x2710;
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(10, self.machine->get_cycle_count());
XCTAssertEqual(state.registers.data[2], 0x9c19);
XCTAssertEqual(state.registers.stack_pointer(), 0x2000);
}
// Omitted: SUB.w -(A6), D2, which is designed to trigger an address error.
- (void)testSUBw_XXXw {
self.machine->set_program({
0x9578, 0x3000 // SUB.w D2, ($3000).w
});
self.machine->set_registers([=](auto &registers) {
registers.data[2] = 0x2711;
});
*self.machine->ram_at(0x3000) = 0x759f;
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(16, self.machine->get_cycle_count());
XCTAssertEqual(state.registers.data[2], 0x2711);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(*self.machine->ram_at(0x3000), 0x4e8e);
}
- (void)testSUBl_dAn {
self.machine->set_program({
0x95ab, 0x0004 // SUB.l D2, 4(A3)
});
self.machine->set_registers([=](auto &registers) {
registers.data[2] = 0x45fd5ab4;
registers.address[3] = 0x3000;
});
*self.machine->ram_at(0x3004) = 0x327a;
*self.machine->ram_at(0x3006) = 0x4ef3;
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(24, self.machine->get_cycle_count());
XCTAssertEqual(state.registers.data[2], 0x45fd5ab4);
XCTAssertEqual(state.registers.address[3], 0x3000);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Extend | ConditionCode::Negative);
XCTAssertEqual(*self.machine->ram_at(0x3004), 0xec7c);
XCTAssertEqual(*self.machine->ram_at(0x3006), 0xf43f);
}
@end
// MARK: - SUBA
@interface M68000SUBATests : M68000ArithmeticTests
@end
@implementation M68000SUBATests
- (void)testSUBAl_Imm {
self.machine->set_program({
0x95fc, 0x1234, 0x5678 // SUBA.l #$12345678, A2
});
self.machine->set_registers([=](auto &registers) {
registers.address[2] = 0xae43ab1d;
registers.status |= ConditionCode::AllConditions;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(16, self.machine->get_cycle_count());
XCTAssertEqual(state.registers.address[2], 0x9c0f54a5);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::AllConditions);
}
- (void)testSUBAw_ImmPositive {
self.machine->set_program({
0x94fc, 0x5678 // SUBA.w #$5678, A2
});
self.machine->set_registers([=](auto &registers) {
registers.address[2] = 0xae43ab1d;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(12, self.machine->get_cycle_count());
XCTAssertEqual(state.registers.address[2], 0xae4354a5);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
}
- (void)testSUBAw_ImmNegative {
self.machine->set_program({
0x94fc, 0xf678 // SUBA.w #$5678, A2
});
self.machine->set_registers([=](auto &registers) {
registers.address[2] = 0xae43ab1d;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(12, self.machine->get_cycle_count());
XCTAssertEqual(state.registers.address[2], 0xae43b4a5);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
}
- (void)testSUBAw_PreDec {
self.machine->set_program({
0x95e2 // SUBA.l -(A2), A2
});
self.machine->set_registers([=](auto &registers) {
registers.address[2] = 0x2004;
});
*self.machine->ram_at(0x2000) = 0x7002;
*self.machine->ram_at(0x2002) = 0x0000;
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(16, self.machine->get_cycle_count());
XCTAssertEqual(state.registers.address[2], 0x8ffe2000);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
}
@end
// MARK: - SUBI
@interface M68000SUBITests : M68000ArithmeticTests
@end
@implementation M68000SUBITests
- (void)testSUBIl {
self.machine->set_program({
0x0481, 0xf111, 0x1111 // SUBI.L #$f1111111, D1
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = 0x300021b3;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(16, self.machine->get_cycle_count());
XCTAssertEqual(state.registers.data[1], 0x3eef10a2);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Extend);
}
// Test of SUBI.W #$7aaa, ($3000).W omitted; that doesn't appear to be a valid instruction?
@end
// MARK: - SUBQ
@interface M68000SUBQTests : M68000ArithmeticTests
@end
@implementation M68000SUBQTests
- (void)testSUBQl {
self.machine->set_program({
0x5f81 // SUBQ.L #$7, D1
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = 0xffffffff;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(8, self.machine->get_cycle_count());
XCTAssertEqual(state.registers.data[1], 0xfffffff8);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative);
}
- (void)testSUBQw {
self.machine->set_program({
0x5f49 // SUBQ.W #$7, A1
});
self.machine->set_registers([=](auto &registers) {
registers.address[1] = 0xffff0001;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(8, self.machine->get_cycle_count());
XCTAssertEqual(state.registers.address[1], 0xfffefffa);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
}
- (void)testSUBQb {
self.machine->set_program({
0x5f38, 0x3000 // SUBQ.b #$7, ($3000).w
});
*self.machine->ram_at(0x3000) = 0x0600;
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(16, self.machine->get_cycle_count());
XCTAssertEqual(*self.machine->ram_at(0x3000), 0xff00);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative | ConditionCode::Carry);
}
@end
// MARK: - SUBX
@interface M68000SUBXTests : M68000ArithmeticTests
@end
@implementation M68000SUBXTests
- (void)testSUBXl_Dn {
self.machine->set_program({
0x9581 // SUBX.l D1, D2
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = 0x12345678;
registers.data[2] = 0x12345678;
registers.status |= ConditionCode::AllConditions;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(8, self.machine->get_cycle_count());
XCTAssertEqual(state.registers.data[1], 0x12345678);
XCTAssertEqual(state.registers.data[2], 0xffffffff);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Carry | ConditionCode::Negative);
}
- (void)testSUBXb_Dn {
self.machine->set_program({
0x9501 // SUBX.b D1, D2
});
self.machine->set_registers([=](auto &registers) {
registers.data[1] = 0x80;
registers.data[2] = 0x01;
});
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(4, self.machine->get_cycle_count());
XCTAssertEqual(state.registers.data[1], 0x80);
XCTAssertEqual(state.registers.data[2], 0x81);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Carry | ConditionCode::Negative | ConditionCode::Overflow);
}
- (void)testSUBXl_PreDec {
self.machine->set_program({
0x9389 // SUBX.l -(A1), -(A1)
});
self.machine->set_registers([=](auto &registers) {
registers.address[1] = 0x3000;
registers.status |= ConditionCode::AllConditions;
});
*self.machine->ram_at(0x2ff8) = 0x1000;
*self.machine->ram_at(0x2ffa) = 0x0000;
*self.machine->ram_at(0x2ffc) = 0x7000;
*self.machine->ram_at(0x2ffe) = 0x1ff1;
self.machine->run_for_instructions(1);
const auto state = self.machine->get_processor_state();
XCTAssertEqual(30, self.machine->get_cycle_count());
XCTAssertEqual(state.registers.address[1], 0x2ff8);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Carry | ConditionCode::Negative );
XCTAssertEqual(*self.machine->ram_at(0x2ff8), 0x9fff);
XCTAssertEqual(*self.machine->ram_at(0x2ffa), 0xe00e);
XCTAssertEqual(*self.machine->ram_at(0x2ffc), 0x7000);
XCTAssertEqual(*self.machine->ram_at(0x2ffe), 0x1ff1);
}
@end