diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index db8a2ac51..8b15cbfd2 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -295,6 +295,7 @@ 4B8FE21D1DA19D5F0090D3CE /* QuickLoadCompositeOptions.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4B8FE2171DA19D5F0090D3CE /* QuickLoadCompositeOptions.xib */; }; 4B8FE2221DA19FB20090D3CE /* MachinePanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8FE2211DA19FB20090D3CE /* MachinePanel.swift */; }; 4B8FE2271DA1DE2D0090D3CE /* NSBundle+DataResource.m in Sources */ = {isa = PBXBuildFile; fileRef = 4B8FE2261DA1DE2D0090D3CE /* NSBundle+DataResource.m */; }; + 4B90467422C6FADD000E2074 /* 68000BitwiseTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B90467322C6FADD000E2074 /* 68000BitwiseTests.mm */; }; 4B924E991E74D22700B76AF1 /* AtariStaticAnalyserTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */; }; 4B9252CE1E74D28200B76AF1 /* Atari ROMs in Resources */ = {isa = PBXBuildFile; fileRef = 4B9252CD1E74D28200B76AF1 /* Atari ROMs */; }; 4B92EACA1B7C112B00246143 /* 6502TimingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B92EAC91B7C112B00246143 /* 6502TimingTests.swift */; }; @@ -1044,6 +1045,8 @@ 4B8FE2211DA19FB20090D3CE /* MachinePanel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MachinePanel.swift; sourceTree = ""; }; 4B8FE2251DA1DE2D0090D3CE /* NSBundle+DataResource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+DataResource.h"; sourceTree = ""; }; 4B8FE2261DA1DE2D0090D3CE /* NSBundle+DataResource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+DataResource.m"; sourceTree = ""; }; + 4B90467222C6FA31000E2074 /* TestRunner68000.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = TestRunner68000.hpp; sourceTree = ""; }; + 4B90467322C6FADD000E2074 /* 68000BitwiseTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = 68000BitwiseTests.mm; sourceTree = ""; }; 4B92294222B04A3D00A1458F /* MouseMachine.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MouseMachine.hpp; sourceTree = ""; }; 4B92294422B04ACB00A1458F /* Mouse.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Mouse.hpp; sourceTree = ""; }; 4B92294A22B064FD00A1458F /* QuadratureMouse.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = QuadratureMouse.hpp; sourceTree = ""; }; @@ -2920,6 +2923,8 @@ isa = PBXGroup; children = ( 4B85322922778E4200F26553 /* Comparative68000.hpp */, + 4B90467222C6FA31000E2074 /* TestRunner68000.hpp */, + 4B90467322C6FADD000E2074 /* 68000BitwiseTests.mm */, 4BD388872239E198002D14B5 /* 68000Tests.mm */, 4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */, 4BB2A9AE1E13367E001A5C23 /* CRCTests.mm */, @@ -4170,6 +4175,7 @@ 4B98A05F1FFAD62400ADF63B /* CSROMFetcher.mm in Sources */, 4BC9E1EE1D23449A003FCEE4 /* 6502InterruptTests.swift in Sources */, 4BEF6AAA1D35CE9E00E73575 /* DigitalPhaseLockedLoopBridge.mm in Sources */, + 4B90467422C6FADD000E2074 /* 68000BitwiseTests.mm in Sources */, 4B924E991E74D22700B76AF1 /* AtariStaticAnalyserTests.mm in Sources */, 4B7BC7F61F58F7D200D1B1B4 /* 6502Base.cpp in Sources */, 4B7BC7F51F58F27800D1B1B4 /* 6502AllRAM.cpp in Sources */, diff --git a/OSBindings/Mac/Clock SignalTests/68000BitwiseTests.mm b/OSBindings/Mac/Clock SignalTests/68000BitwiseTests.mm new file mode 100644 index 000000000..3631032b9 --- /dev/null +++ b/OSBindings/Mac/Clock SignalTests/68000BitwiseTests.mm @@ -0,0 +1,819 @@ +// +// 68000Bitwise.m +// Clock SignalTests +// +// Created by Thomas Harte on 28/06/2019. +// +// Largely ported from the tests of the Portable 68k Emulator. +// + +#import + +#include "TestRunner68000.hpp" + +@interface M68000BitwiseTests : XCTestCase +@end + +@implementation M68000BitwiseTests { + std::unique_ptr _machine; +} + +- (void)setUp { + _machine.reset(new RAM68000()); +} + +- (void)tearDown { + _machine.reset(); +} + +// MARK: BCHG + +- (void)performBCHGD0D1:(uint32_t)d1 { + _machine->set_program({ + 0x0340 // BCHG D1, D0 + }); + auto state = _machine->get_processor_state(); + state.data[0] = 0x12345678; + state.data[1] = d1; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(state.data[1], d1); +} + +- (void)testBCHG_D0D1_0 { + [self performBCHGD0D1:0]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[0], 0x12345679); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); + XCTAssertEqual(_machine->get_cycle_count(), 6); +} + +- (void)testBCHG_D0D1_10 { + [self performBCHGD0D1:10]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[0], 0x12345278); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0); + XCTAssertEqual(_machine->get_cycle_count(), 6); +} + +- (void)testBCHG_D0D1_48 { + [self performBCHGD0D1:48]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[0], 0x12355678); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); + XCTAssertEqual(_machine->get_cycle_count(), 8); +} + +- (void)performBCHGD1Ind:(uint32_t)d1 { + _machine->set_program({ + 0x0350 // BCHG D1, (A0) + }); + auto state = _machine->get_processor_state(); + state.address[0] = 0x3000; + state.data[1] = d1; + *_machine->ram_at(0x3000) = 0x7800; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(state.data[1], d1); + XCTAssertEqual(state.address[0], 0x3000); + XCTAssertEqual(_machine->get_cycle_count(), 12); +} + +- (void)testBCHG_D1Ind_48 { + [self performBCHGD1Ind:48]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); + XCTAssertEqual(*_machine->ram_at(0x3000), 0x7900); +} + +- (void)testBCHG_D1Ind_7 { + [self performBCHGD1Ind:7]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); + XCTAssertEqual(*_machine->ram_at(0x3000), 0xf800); +} + +- (void)performBCHGImm:(uint16_t)immediate { + _machine->set_program({ + 0x0840, immediate // BCHG #, D0 + }); + auto state = _machine->get_processor_state(); + state.data[0] = 0x12345678; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); +} + +- (void)testBCHG_Imm_31 { + [self performBCHGImm:31]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[0], 0x92345678); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); + XCTAssertEqual(_machine->get_cycle_count(), 12); +} + +- (void)testBCHG_Imm_4 { + [self performBCHGImm:4]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[0], 0x12345668); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0); + XCTAssertEqual(_machine->get_cycle_count(), 10); +} + +- (void)testBCHG_ImmWWWx { + _machine->set_program({ + 0x0878, 0x0006, 0x3000 // BCHG #6, ($3000).W + }); + *_machine->ram_at(0x3000) = 0x7800; + + _machine->run_for_instructions(1); + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0); + XCTAssertEqual(_machine->get_cycle_count(), 20); + XCTAssertEqual(*_machine->ram_at(0x3000), 0x3800); +} + +// MARK: BCLR + +- (void)performBCLRD0D1:(uint32_t)d1 { + _machine->set_program({ + 0x0380 // BCLR D1, D0 + }); + auto state = _machine->get_processor_state(); + state.data[0] = 0x12345678; + state.data[1] = d1; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(state.data[1], d1); +} + +- (void)testBCLR_D0D1_0 { + [self performBCLRD0D1:0]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[0], 0x12345678); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); + XCTAssertEqual(_machine->get_cycle_count(), 8); +} + +- (void)testBCLR_D0D1_10 { + [self performBCLRD0D1:10]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[0], 0x12345278); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0); + XCTAssertEqual(_machine->get_cycle_count(), 8); +} + +- (void)testBCLR_D0D1_50 { + [self performBCLRD0D1:50]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[0], 0x12305678); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0); + XCTAssertEqual(_machine->get_cycle_count(), 10); +} + +- (void)performBCLRD1Ind:(uint32_t)d1 { + _machine->set_program({ + 0x0390 // BCLR D1, (A0) + }); + auto state = _machine->get_processor_state(); + state.address[0] = 0x3000; + state.data[1] = d1; + *_machine->ram_at(0x3000) = 0x7800; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(state.data[1], d1); + XCTAssertEqual(state.address[0], 0x3000); + XCTAssertEqual(_machine->get_cycle_count(), 12); +} + +- (void)testBCLR_D1Ind_50 { + [self performBCLRD1Ind:50]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); + XCTAssertEqual(*_machine->ram_at(0x3000), 0x7800); +} + +- (void)testBCLR_D1Ind_3 { + [self performBCLRD1Ind:3]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0); + XCTAssertEqual(*_machine->ram_at(0x3000), 0x7000); +} + +- (void)performBCLRImm:(uint16_t)immediate { + _machine->set_program({ + 0x0880, immediate // BCLR #, D0 + }); + auto state = _machine->get_processor_state(); + state.data[0] = 0x12345678; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0); +} + +- (void)testBCLR_Imm_28 { + [self performBCLRImm:28]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[0], 0x02345678); + XCTAssertEqual(_machine->get_cycle_count(), 14); +} + +- (void)testBCLR_Imm_4 { + [self performBCLRImm:4]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[0], 0x12345668); + XCTAssertEqual(_machine->get_cycle_count(), 12); +} + +- (void)testBCLR_ImmWWWx { + _machine->set_program({ + 0x08b8, 0x0006, 0x3000 // BCLR #6, ($3000).W + }); + *_machine->ram_at(0x3000) = 0x7800; + + _machine->run_for_instructions(1); + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0); + XCTAssertEqual(_machine->get_cycle_count(), 20); + XCTAssertEqual(*_machine->ram_at(0x3000), 0x3800); +} + +// MARK: BSET + +- (void)performBSETD0D1:(uint32_t)d1 { + _machine->set_program({ + 0x03c0 // BSET D1, D0 + }); + auto state = _machine->get_processor_state(); + state.data[0] = 0x12345678; + state.data[1] = d1; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(state.data[1], d1); +} + +- (void)testBSET_D0D1_0 { + [self performBSETD0D1:0]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[0], 0x12345679); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); + XCTAssertEqual(_machine->get_cycle_count(), 6); +} + +- (void)testBSET_D0D1_10 { + [self performBSETD0D1:10]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[0], 0x12345678); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0); + XCTAssertEqual(_machine->get_cycle_count(), 6); +} + +- (void)testBSET_D0D1_49 { + [self performBSETD0D1:49]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[0], 0x12365678); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); + XCTAssertEqual(_machine->get_cycle_count(), 8); +} + +- (void)performBSETD1Ind:(uint32_t)d1 { + _machine->set_program({ + 0x03d0 // BSET D1, (A0) + }); + auto state = _machine->get_processor_state(); + state.address[0] = 0x3000; + state.data[1] = d1; + *_machine->ram_at(0x3000) = 0x7800; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(state.data[1], d1); + XCTAssertEqual(state.address[0], 0x3000); + XCTAssertEqual(_machine->get_cycle_count(), 12); +} + +- (void)testBSET_D1Ind_50 { + [self performBSETD1Ind:50]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); + XCTAssertEqual(*_machine->ram_at(0x3000), 0x7c00); +} + +- (void)testBSET_D1Ind_3 { + [self performBSETD1Ind:3]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0); + XCTAssertEqual(*_machine->ram_at(0x3000), 0x7800); +} + +- (void)performBSETImm:(uint16_t)immediate { + _machine->set_program({ + 0x08c0, immediate // BSET #, D0 + }); + auto state = _machine->get_processor_state(); + state.data[0] = 0x12345678; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); +} + +- (void)testBSET_Imm_28 { + [self performBSETImm:28]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[0], 0x12345678); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0); + XCTAssertEqual(_machine->get_cycle_count(), 12); +} + +- (void)testBSET_Imm_2 { + [self performBSETImm:2]; + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.data[0], 0x1234567c); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); + XCTAssertEqual(_machine->get_cycle_count(), 10); +} + +- (void)testBSET_ImmWWWx { + _machine->set_program({ + 0x08f8, 0x0006, 0x3000 // BSET #6, ($3000).W + }); + *_machine->ram_at(0x3000) = 0x7800; + + _machine->run_for_instructions(1); + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0); + XCTAssertEqual(_machine->get_cycle_count(), 20); + XCTAssertEqual(*_machine->ram_at(0x3000), 0x7800); +} + +// MARK: - +// MARK: ANDI + +- (void)testANDIb { + _machine->set_program({ + 0x0201, 0x0012 // ANDI.B #$12, D1 + }); + + 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], 0x12345610); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0); + XCTAssertEqual(8, _machine->get_cycle_count()); +} + +- (void)testANDIl { + _machine->set_program({ + 0x02b8, 0xffff, 0x0000, 0x3000 // ANDI.L #$ffff0000, ($3000).W + }); + + *_machine->ram_at(0x3000) = 0x0000; + *_machine->ram_at(0x3002) = 0xffff; + + _machine->run_for_instructions(1); + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(*_machine->ram_at(0x3000), 0x0000); + XCTAssertEqual(*_machine->ram_at(0x3002), 0x0000); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); + XCTAssertEqual(32, _machine->get_cycle_count()); +} + +// MARK: ANDI CCR + +- (void)testANDICCR { + _machine->set_program({ + 0x023c, 0x001b // ANDI.b #$1b, CCR + }); + auto state = _machine->get_processor_state(); + state.status |= 0xc; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0xc & 0x1b); + XCTAssertEqual(20, _machine->get_cycle_count()); +} + +// MARK: ANDI SR + +- (void)testANDISR_supervisor { + _machine->set_program({ + 0x027c, 0x0700 // ANDI.W #$700, SR + }); + _machine->set_initial_stack_pointer(300); + + _machine->run_for_instructions(1); + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.program_counter, 0x1004 + 4); + XCTAssertEqual(20, _machine->get_cycle_count()); +} + +- (void)testANDISR_user { + _machine->set_program({ + 0x46fc, 0x0000, // MOVE 0, SR + 0x027c, 0x0700 // ANDI.W #$700, SR + }); + + _machine->run_for_instructions(2); + + const auto state = _machine->get_processor_state(); + XCTAssertNotEqual(state.program_counter, 0x1008 + 4); +// XCTAssertEqual(34, _machine->get_cycle_count()); +} + +// MARK: EOR + +- (void)testEORw { + _machine->set_program({ + 0xb744 // EOR.w D3, D4 + }); + + auto state = _machine->get_processor_state(); + state.status |= Flag::Extend | Flag::Carry | Flag::Overflow; + state.data[3] = 0x54ff0056; + state.data[4] = 0x9853abcd; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(state.data[3], 0x54ff0056); + XCTAssertEqual(state.data[4], 0x9853ab9b); + XCTAssertEqual(4, _machine->get_cycle_count()); +} + +- (void)testEORl { + _machine->set_program({ + 0xb792 // EOR.l D3, (A2) + }); + + auto state = _machine->get_processor_state(); + state.address[2] = 0x3000; + state.data[3] = 0x54ff0056; + *_machine->ram_at(0x3000) = 0x0f0f; + *_machine->ram_at(0x3002) = 0x0f11; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(state.data[3], 0x54ff0056); + XCTAssertEqual(state.address[2], 0x3000); + XCTAssertEqual(*_machine->ram_at(0x3000), 0x5bf0); + XCTAssertEqual(*_machine->ram_at(0x3002), 0x0f47); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0); + XCTAssertEqual(20, _machine->get_cycle_count()); +} + +// MARK: EORI + +- (void)testEORIb { + _machine->set_program({ + 0x0a01, 0x0012 // EORI.B #$12, D1 + }); + + 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], 0x1234566a); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0); + XCTAssertEqual(8, _machine->get_cycle_count()); +} + +- (void)testEORIl { + _machine->set_program({ + 0x0ab8, 0xffff, 0x0000, 0x3000 // EORI.L #$ffff0000, ($3000).W + }); + + *_machine->ram_at(0x3000) = 0x0000; + *_machine->ram_at(0x3002) = 0xffff; + + _machine->run_for_instructions(1); + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(*_machine->ram_at(0x3000), 0xffff); + XCTAssertEqual(*_machine->ram_at(0x3002), 0xffff); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Negative); + XCTAssertEqual(32, _machine->get_cycle_count()); +} + +// MARK: EORI to CCR + +- (void)testEORICCR { + _machine->set_program({ + 0x0a3c, 0x001b // EORI.b #$1b, CCR + }); + + auto state = _machine->get_processor_state(); + state.status |= 0xc; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0xc ^ 0x1b); + XCTAssertEqual(20, _machine->get_cycle_count()); +} + +// MARK: EORI to SR + +- (void)testEORISR_supervisor { + _machine->set_program({ + 0x0a7c, 0x0700 // EORI.W #$700, SR + }); + _machine->set_initial_stack_pointer(300); + + _machine->run_for_instructions(1); + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.program_counter, 0x1004 + 4); + XCTAssertEqual(20, _machine->get_cycle_count()); +} + +- (void)testEORISR_user { + _machine->set_program({ + 0x46fc, 0x0000, // MOVE 0, SR + 0x0a7c, 0x0700 // EORI.W #$700, SR + }); + + _machine->run_for_instructions(2); + + const auto state = _machine->get_processor_state(); + XCTAssertNotEqual(state.program_counter, 0x1008 + 4); +// XCTAssertEqual(34, _machine->get_cycle_count()); +} + +// MARK: NOT + +- (void)testNOTb { + _machine->set_program({ + 0x4600 // NOT.B D0 + }); + auto state = _machine->get_processor_state(); + state.data[0] = 0x12345678; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(state.data[0], 0x12345687); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Negative); + XCTAssertEqual(4, _machine->get_cycle_count()); +} + +- (void)testNOTw { + _machine->set_program({ + 0x4640 // NOT.w D0 + }); + auto state = _machine->get_processor_state(); + state.data[0] = 0x12340000; + state.status |= Flag::ConditionCodes; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(state.data[0], 0x1234ffff); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Negative | Flag::Extend); + XCTAssertEqual(4, _machine->get_cycle_count()); +} + +- (void)testNOTl_Dn { + _machine->set_program({ + 0x4680 // NOT.l D0 + }); + auto state = _machine->get_processor_state(); + state.data[0] = 0xffffff00; + state.status |= Flag::ConditionCodes; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(state.data[0], 0x000000ff); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend); + XCTAssertEqual(6, _machine->get_cycle_count()); +} + +- (void)testNOTl_XXXl { + _machine->set_program({ + 0x46b9, 0x0000, 0x3000 // NOT.L ($3000).L + }); + *_machine->ram_at(0x3000) = 0xf001; + *_machine->ram_at(0x3002) = 0x2311; + auto state = _machine->get_processor_state(); + state.status |= Flag::Extend; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(*_machine->ram_at(0x3000), 0x0ffe); + XCTAssertEqual(*_machine->ram_at(0x3002), 0xdcee); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend); + XCTAssertEqual(28, _machine->get_cycle_count()); +} + +// MARK: OR + +- (void)testORb { + _machine->set_program({ + 0x8604 // OR.b D4, D3 + }); + auto state = _machine->get_processor_state(); + state.data[3] = 0x54ff0056; + state.data[4] = 0x9853abcd; + 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[3], 0x54ff00df); + XCTAssertEqual(state.data[4], 0x9853abcd); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend | Flag::Negative); + XCTAssertEqual(4, _machine->get_cycle_count()); +} + +- (void)testORl_toDn { + _machine->set_program({ + 0x86ac, 0xfffa // OR.l -6(A4), D3 + }); + auto state = _machine->get_processor_state(); + state.data[3] = 0x54fff856; + state.address[4] = 0x3006; + *_machine->ram_at(0x3000) = 0x1253; + *_machine->ram_at(0x3002) = 0xfb34; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(state.data[3], 0x56fffb76); + XCTAssertEqual(state.address[4], 0x3006); + XCTAssertEqual(*_machine->ram_at(0x3000), 0x1253); + XCTAssertEqual(*_machine->ram_at(0x3002), 0xfb34); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0); + XCTAssertEqual(18, _machine->get_cycle_count()); +} + +- (void)testORl_fromDn { + _machine->set_program({ + 0x87ac, 0xfffa // OR.l D3, -6(A4) + }); + auto state = _machine->get_processor_state(); + state.data[3] = 0x54fff856; + state.address[4] = 0x3006; + *_machine->ram_at(0x3000) = 0x1253; + *_machine->ram_at(0x3002) = 0xfb34; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(state.data[3], 0x54fff856); + XCTAssertEqual(state.address[4], 0x3006); + XCTAssertEqual(*_machine->ram_at(0x3000), 0x56ff); + XCTAssertEqual(*_machine->ram_at(0x3002), 0xfb76); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0); + XCTAssertEqual(24, _machine->get_cycle_count()); +} + +// MARK: ORI + +- (void)testORIb { + _machine->set_program({ + 0x0001, 0x0012 // ORI.B #$12, D1 + }); + + 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], 0x1234567a); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0); + XCTAssertEqual(8, _machine->get_cycle_count()); +} + +- (void)testORIl { + _machine->set_program({ + 0x00b8, 0xffff, 0x0000, 0x3000 // ORI.L #$ffff0000, ($3000).W + }); + + *_machine->ram_at(0x3000) = 0x0000; + *_machine->ram_at(0x3002) = 0xffff; + + _machine->run_for_instructions(1); + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(*_machine->ram_at(0x3000), 0xffff); + XCTAssertEqual(*_machine->ram_at(0x3002), 0xffff); + XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Negative); + XCTAssertEqual(32, _machine->get_cycle_count()); +} + +// MARK: ORI to CCR + +- (void)testORICCR { + _machine->set_program({ + 0x003c, 0x001b // ORI.b #$1b, CCR + }); + + auto state = _machine->get_processor_state(); + state.status |= 0xc; + + _machine->set_processor_state(state); + _machine->run_for_instructions(1); + + state = _machine->get_processor_state(); + XCTAssertEqual(state.status & Flag::ConditionCodes, 0xc | 0x1b); + XCTAssertEqual(20, _machine->get_cycle_count()); +} + +// MARK: ORI to SR + +- (void)testORISR_supervisor { + _machine->set_program({ + 0x007c, 0x0700 // ORI.W #$700, SR + }); + _machine->set_initial_stack_pointer(300); + + _machine->run_for_instructions(1); + + const auto state = _machine->get_processor_state(); + XCTAssertEqual(state.program_counter, 0x1004 + 4); + XCTAssertEqual(20, _machine->get_cycle_count()); +} + +- (void)testORISR_user { + _machine->set_program({ + 0x46fc, 0x0000, // MOVE 0, SR + 0x007c, 0x0700 // ORI.W #$700, SR + }); + + _machine->run_for_instructions(2); + + const auto state = _machine->get_processor_state(); + XCTAssertNotEqual(state.program_counter, 0x1008 + 4); +// XCTAssertEqual(34, _machine->get_cycle_count()); +} + +@end diff --git a/OSBindings/Mac/Clock SignalTests/68000Tests.mm b/OSBindings/Mac/Clock SignalTests/68000Tests.mm index 498696b9a..6747db6ea 100644 --- a/OSBindings/Mac/Clock SignalTests/68000Tests.mm +++ b/OSBindings/Mac/Clock SignalTests/68000Tests.mm @@ -8,136 +8,9 @@ #import -#include #include -#define LOG_TRACE -#include "../../../Processors/68000/68000.hpp" - -using Flag = CPU::MC68000::Flag; - -/*! - Provides a 68000 with 64kb of RAM in its low address space; - /RESET will put the supervisor stack pointer at 0xFFFF and - begin execution at 0x0400. -*/ -class RAM68000: public CPU::MC68000::BusHandler { - public: - RAM68000() : m68000_(*this) { - // Setup the /RESET vector. - ram_[0] = 0; - ram_[1] = 0x206; // Supervisor stack pointer. - ram_[2] = 0; - ram_[3] = 0x1000; // Initial PC. - - // Ensure the condition codes start unset. - auto state = get_processor_state(); - state.status &= ~Flag::ConditionCodes; - set_processor_state(state); - } - - void set_program(const std::vector &program) { - memcpy(&ram_[0x1000 >> 1], program.data(), program.size() * sizeof(uint16_t)); - - // Add a NOP suffix, to avoid corrupting flags should the attempt to - // run for a certain number of instructions overrun. - ram_[(0x1000 >> 1) + program.size()] = 0x4e71; - } - - void set_initial_stack_pointer(uint32_t sp) { - ram_[0] = sp >> 16; - ram_[1] = sp & 0xffff; - } - - void will_perform(uint32_t address, uint16_t opcode) { - --instructions_remaining_; - } - - void run_for_instructions(int count) { - instructions_remaining_ = count + (has_run_ ? 0 : 1); - finish_reset_if_needed(); - - while(instructions_remaining_) { - run_for(HalfCycles(2)); - } - } - - void run_for(HalfCycles cycles) { - finish_reset_if_needed(); - m68000_.run_for(cycles); - } - - void finish_reset_if_needed() { - // If the 68000 hasn't run yet, build in the necessary - // cycles to finish the reset program, and set the stored state. - if(!has_run_) { - has_run_ = true; - m68000_.run_for(HalfCycles(76)); - duration_ -= HalfCycles(76); - } - } - - uint16_t *ram_at(uint32_t address) { - return &ram_[(address >> 1) % ram_.size()]; - } - - HalfCycles perform_bus_operation(const CPU::MC68000::Microcycle &cycle, int is_supervisor) { - const uint32_t word_address = cycle.word_address(); - if(instructions_remaining_) duration_ += cycle.length; - - using Microcycle = CPU::MC68000::Microcycle; - if(cycle.data_select_active()) { - if(cycle.operation & Microcycle::InterruptAcknowledge) { - cycle.value->halves.low = 10; - } else { - switch(cycle.operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read)) { - default: break; - - case Microcycle::SelectWord | Microcycle::Read: - cycle.value->full = ram_[word_address % ram_.size()]; - break; - case Microcycle::SelectByte | Microcycle::Read: - cycle.value->halves.low = ram_[word_address % ram_.size()] >> cycle.byte_shift(); - break; - case Microcycle::SelectWord: - ram_[word_address % ram_.size()] = cycle.value->full; - break; - case Microcycle::SelectByte: - ram_[word_address % ram_.size()] = uint16_t( - (cycle.value->halves.low << cycle.byte_shift()) | - (ram_[word_address % ram_.size()] & cycle.untouched_byte_mask()) - ); - break; - } - } - } - - return HalfCycles(0); - } - - CPU::MC68000::Processor::State get_processor_state() { - return m68000_.get_state(); - } - - void set_processor_state(const CPU::MC68000::Processor::State &state) { - m68000_.set_state(state); - } - - CPU::MC68000::Processor &processor() { - return m68000_; - } - - int get_cycle_count() { - return duration_.as_int() >> 1; - } - - private: - CPU::MC68000::Processor m68000_; - std::array ram_; - int instructions_remaining_; - HalfCycles duration_; - bool has_run_ = false; -}; +#include "TestRunner68000.hpp" class CPU::MC68000::ProcessorStorageTests { public: @@ -1075,88 +948,6 @@ class CPU::MC68000::ProcessorStorageTests { XCTAssertEqual(16, _machine->get_cycle_count()); } -// MARK: ANDI - -- (void)testANDIb { - _machine->set_program({ - 0x0201, 0x0012 // ANDI.B #$12, D1 - }); - - 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], 0x12345610); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0); - XCTAssertEqual(8, _machine->get_cycle_count()); -} - -- (void)testANDIl { - _machine->set_program({ - 0x02b8, 0xffff, 0x0000, 0x3000 // ANDI.L #$ffff0000, ($3000).W - }); - - *_machine->ram_at(0x3000) = 0x0000; - *_machine->ram_at(0x3002) = 0xffff; - - _machine->run_for_instructions(1); - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(*_machine->ram_at(0x3000), 0x0000); - XCTAssertEqual(*_machine->ram_at(0x3002), 0x0000); - XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); - XCTAssertEqual(32, _machine->get_cycle_count()); -} - -// MARK: ANDI CCR - -- (void)testANDICCR { - _machine->set_program({ - 0x023c, 0x001b // ANDI.b #$1b, CCR - }); - auto state = _machine->get_processor_state(); - state.status |= 0xc; - - _machine->set_processor_state(state); - _machine->run_for_instructions(1); - - state = _machine->get_processor_state(); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0xc & 0x1b); - XCTAssertEqual(20, _machine->get_cycle_count()); -} - -// MARK: ANDI SR - -- (void)testANDISR_supervisor { - _machine->set_program({ - 0x027c, 0x0700 // ANDI.W #$700, SR - }); - _machine->set_initial_stack_pointer(300); - - _machine->run_for_instructions(1); - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.program_counter, 0x1004 + 4); - XCTAssertEqual(20, _machine->get_cycle_count()); -} - -- (void)testANDISR_user { - _machine->set_program({ - 0x46fc, 0x0000, // MOVE 0, SR - 0x027c, 0x0700 // ANDI.W #$700, SR - }); - - _machine->run_for_instructions(2); - - const auto state = _machine->get_processor_state(); - XCTAssertNotEqual(state.program_counter, 0x1008 + 4); -// XCTAssertEqual(34, _machine->get_cycle_count()); -} - - // MARK: ASL - (void)testASLb_Dn_2 { @@ -1435,249 +1226,6 @@ class CPU::MC68000::ProcessorStorageTests { XCTAssertEqual(16, _machine->get_cycle_count()); } -// MARK: BCHG - -- (void)performBCHGD0D1:(uint32_t)d1 { - _machine->set_program({ - 0x0340 // BCHG D1, D0 - }); - auto state = _machine->get_processor_state(); - state.data[0] = 0x12345678; - state.data[1] = d1; - - _machine->set_processor_state(state); - _machine->run_for_instructions(1); - - state = _machine->get_processor_state(); - XCTAssertEqual(state.data[1], d1); -} - -- (void)testBCHG_D0D1_0 { - [self performBCHGD0D1:0]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.data[0], 0x12345679); - XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); - XCTAssertEqual(_machine->get_cycle_count(), 6); -} - -- (void)testBCHG_D0D1_10 { - [self performBCHGD0D1:10]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.data[0], 0x12345278); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0); - XCTAssertEqual(_machine->get_cycle_count(), 6); -} - -- (void)testBCHG_D0D1_48 { - [self performBCHGD0D1:48]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.data[0], 0x12355678); - XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); - XCTAssertEqual(_machine->get_cycle_count(), 8); -} - -- (void)performBCHGD1Ind:(uint32_t)d1 { - _machine->set_program({ - 0x0350 // BCHG D1, (A0) - }); - auto state = _machine->get_processor_state(); - state.address[0] = 0x3000; - state.data[1] = d1; - *_machine->ram_at(0x3000) = 0x7800; - - _machine->set_processor_state(state); - _machine->run_for_instructions(1); - - state = _machine->get_processor_state(); - XCTAssertEqual(state.data[1], d1); - XCTAssertEqual(state.address[0], 0x3000); - XCTAssertEqual(_machine->get_cycle_count(), 12); -} - -- (void)testBCHG_D1Ind_48 { - [self performBCHGD1Ind:48]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); - XCTAssertEqual(*_machine->ram_at(0x3000), 0x7900); -} - -- (void)testBCHG_D1Ind_7 { - [self performBCHGD1Ind:7]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); - XCTAssertEqual(*_machine->ram_at(0x3000), 0xf800); -} - -- (void)performBCHGImm:(uint16_t)immediate { - _machine->set_program({ - 0x0840, immediate // BCHG #, D0 - }); - auto state = _machine->get_processor_state(); - state.data[0] = 0x12345678; - - _machine->set_processor_state(state); - _machine->run_for_instructions(1); -} - -- (void)testBCHG_Imm_31 { - [self performBCHGImm:31]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.data[0], 0x92345678); - XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); - XCTAssertEqual(_machine->get_cycle_count(), 12); -} - -- (void)testBCHG_Imm_4 { - [self performBCHGImm:4]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.data[0], 0x12345668); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0); - XCTAssertEqual(_machine->get_cycle_count(), 10); -} - -- (void)testBCHG_ImmWWWx { - _machine->set_program({ - 0x0878, 0x0006, 0x3000 // BCHG #6, ($3000).W - }); - *_machine->ram_at(0x3000) = 0x7800; - - _machine->run_for_instructions(1); - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0); - XCTAssertEqual(_machine->get_cycle_count(), 20); - XCTAssertEqual(*_machine->ram_at(0x3000), 0x3800); -} - -// MARK: BCLR - -- (void)performBCLRD0D1:(uint32_t)d1 { - _machine->set_program({ - 0x0380 // BCLR D1, D0 - }); - auto state = _machine->get_processor_state(); - state.data[0] = 0x12345678; - state.data[1] = d1; - - _machine->set_processor_state(state); - _machine->run_for_instructions(1); - - state = _machine->get_processor_state(); - XCTAssertEqual(state.data[1], d1); -} - -- (void)testBCLR_D0D1_0 { - [self performBCLRD0D1:0]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.data[0], 0x12345678); - XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); - XCTAssertEqual(_machine->get_cycle_count(), 8); -} - -- (void)testBCLR_D0D1_10 { - [self performBCLRD0D1:10]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.data[0], 0x12345278); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0); - XCTAssertEqual(_machine->get_cycle_count(), 8); -} - -- (void)testBCLR_D0D1_50 { - [self performBCLRD0D1:50]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.data[0], 0x12305678); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0); - XCTAssertEqual(_machine->get_cycle_count(), 10); -} - -- (void)performBCLRD1Ind:(uint32_t)d1 { - _machine->set_program({ - 0x0390 // BCLR D1, (A0) - }); - auto state = _machine->get_processor_state(); - state.address[0] = 0x3000; - state.data[1] = d1; - *_machine->ram_at(0x3000) = 0x7800; - - _machine->set_processor_state(state); - _machine->run_for_instructions(1); - - state = _machine->get_processor_state(); - XCTAssertEqual(state.data[1], d1); - XCTAssertEqual(state.address[0], 0x3000); - XCTAssertEqual(_machine->get_cycle_count(), 12); -} - -- (void)testBCLR_D1Ind_50 { - [self performBCLRD1Ind:50]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); - XCTAssertEqual(*_machine->ram_at(0x3000), 0x7800); -} - -- (void)testBCLR_D1Ind_3 { - [self performBCLRD1Ind:3]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0); - XCTAssertEqual(*_machine->ram_at(0x3000), 0x7000); -} - -- (void)performBCLRImm:(uint16_t)immediate { - _machine->set_program({ - 0x0880, immediate // BCLR #, D0 - }); - auto state = _machine->get_processor_state(); - state.data[0] = 0x12345678; - - _machine->set_processor_state(state); - _machine->run_for_instructions(1); - - state = _machine->get_processor_state(); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0); -} - -- (void)testBCLR_Imm_28 { - [self performBCLRImm:28]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.data[0], 0x02345678); - XCTAssertEqual(_machine->get_cycle_count(), 14); -} - -- (void)testBCLR_Imm_4 { - [self performBCLRImm:4]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.data[0], 0x12345668); - XCTAssertEqual(_machine->get_cycle_count(), 12); -} - -- (void)testBCLR_ImmWWWx { - _machine->set_program({ - 0x08b8, 0x0006, 0x3000 // BCLR #6, ($3000).W - }); - *_machine->ram_at(0x3000) = 0x7800; - - _machine->run_for_instructions(1); - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0); - XCTAssertEqual(_machine->get_cycle_count(), 20); - XCTAssertEqual(*_machine->ram_at(0x3000), 0x3800); -} - // MARK: BRA - (void)testBRAb { @@ -1704,127 +1252,6 @@ class CPU::MC68000::ProcessorStorageTests { XCTAssertEqual(_machine->get_cycle_count(), 10); } -// MARK: BSET - -- (void)performBSETD0D1:(uint32_t)d1 { - _machine->set_program({ - 0x03c0 // BSET D1, D0 - }); - auto state = _machine->get_processor_state(); - state.data[0] = 0x12345678; - state.data[1] = d1; - - _machine->set_processor_state(state); - _machine->run_for_instructions(1); - - state = _machine->get_processor_state(); - XCTAssertEqual(state.data[1], d1); -} - -- (void)testBSET_D0D1_0 { - [self performBSETD0D1:0]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.data[0], 0x12345679); - XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); - XCTAssertEqual(_machine->get_cycle_count(), 6); -} - -- (void)testBSET_D0D1_10 { - [self performBSETD0D1:10]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.data[0], 0x12345678); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0); - XCTAssertEqual(_machine->get_cycle_count(), 6); -} - -- (void)testBSET_D0D1_49 { - [self performBSETD0D1:49]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.data[0], 0x12365678); - XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); - XCTAssertEqual(_machine->get_cycle_count(), 8); -} - -- (void)performBSETD1Ind:(uint32_t)d1 { - _machine->set_program({ - 0x03d0 // BSET D1, (A0) - }); - auto state = _machine->get_processor_state(); - state.address[0] = 0x3000; - state.data[1] = d1; - *_machine->ram_at(0x3000) = 0x7800; - - _machine->set_processor_state(state); - _machine->run_for_instructions(1); - - state = _machine->get_processor_state(); - XCTAssertEqual(state.data[1], d1); - XCTAssertEqual(state.address[0], 0x3000); - XCTAssertEqual(_machine->get_cycle_count(), 12); -} - -- (void)testBSET_D1Ind_50 { - [self performBSETD1Ind:50]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); - XCTAssertEqual(*_machine->ram_at(0x3000), 0x7c00); -} - -- (void)testBSET_D1Ind_3 { - [self performBSETD1Ind:3]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0); - XCTAssertEqual(*_machine->ram_at(0x3000), 0x7800); -} - -- (void)performBSETImm:(uint16_t)immediate { - _machine->set_program({ - 0x08c0, immediate // BSET #, D0 - }); - auto state = _machine->get_processor_state(); - state.data[0] = 0x12345678; - - _machine->set_processor_state(state); - _machine->run_for_instructions(1); -} - -- (void)testBSET_Imm_28 { - [self performBSETImm:28]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.data[0], 0x12345678); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0); - XCTAssertEqual(_machine->get_cycle_count(), 12); -} - -- (void)testBSET_Imm_2 { - [self performBSETImm:2]; - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.data[0], 0x1234567c); - XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Zero); - XCTAssertEqual(_machine->get_cycle_count(), 10); -} - -- (void)testBSET_ImmWWWx { - _machine->set_program({ - 0x08f8, 0x0006, 0x3000 // BSET #6, ($3000).W - }); - *_machine->ram_at(0x3000) = 0x7800; - - _machine->run_for_instructions(1); - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0); - XCTAssertEqual(_machine->get_cycle_count(), 20); - XCTAssertEqual(*_machine->ram_at(0x3000), 0x7800); -} - // MARK: BSR - (void)testBSRw { @@ -2702,132 +2129,6 @@ class CPU::MC68000::ProcessorStorageTests { // Omitted: divide by zero test. -// MARK: EOR - -- (void)testEORw { - _machine->set_program({ - 0xb744 // EOR.w D3, D4 - }); - - auto state = _machine->get_processor_state(); - state.status |= Flag::Extend | Flag::Carry | Flag::Overflow; - state.data[3] = 0x54ff0056; - state.data[4] = 0x9853abcd; - - _machine->set_processor_state(state); - _machine->run_for_instructions(1); - - state = _machine->get_processor_state(); - XCTAssertEqual(state.data[3], 0x54ff0056); - XCTAssertEqual(state.data[4], 0x9853ab9b); - XCTAssertEqual(4, _machine->get_cycle_count()); -} - -- (void)testEORl { - _machine->set_program({ - 0xb792 // EOR.l D3, (A2) - }); - - auto state = _machine->get_processor_state(); - state.address[2] = 0x3000; - state.data[3] = 0x54ff0056; - *_machine->ram_at(0x3000) = 0x0f0f; - *_machine->ram_at(0x3002) = 0x0f11; - - _machine->set_processor_state(state); - _machine->run_for_instructions(1); - - state = _machine->get_processor_state(); - XCTAssertEqual(state.data[3], 0x54ff0056); - XCTAssertEqual(state.address[2], 0x3000); - XCTAssertEqual(*_machine->ram_at(0x3000), 0x5bf0); - XCTAssertEqual(*_machine->ram_at(0x3002), 0x0f47); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0); - XCTAssertEqual(20, _machine->get_cycle_count()); -} - -// MARK: EORI - -- (void)testEORIb { - _machine->set_program({ - 0x0a01, 0x0012 // EORI.B #$12, D1 - }); - - 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], 0x1234566a); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0); - XCTAssertEqual(8, _machine->get_cycle_count()); -} - -- (void)testEORIl { - _machine->set_program({ - 0x0ab8, 0xffff, 0x0000, 0x3000 // EORI.L #$ffff0000, ($3000).W - }); - - *_machine->ram_at(0x3000) = 0x0000; - *_machine->ram_at(0x3002) = 0xffff; - - _machine->run_for_instructions(1); - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(*_machine->ram_at(0x3000), 0xffff); - XCTAssertEqual(*_machine->ram_at(0x3002), 0xffff); - XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Negative); - XCTAssertEqual(32, _machine->get_cycle_count()); -} - -// MARK: EORI to CCR - -- (void)testEORICCR { - _machine->set_program({ - 0x0a3c, 0x001b // EORI.b #$1b, CCR - }); - - auto state = _machine->get_processor_state(); - state.status |= 0xc; - - _machine->set_processor_state(state); - _machine->run_for_instructions(1); - - state = _machine->get_processor_state(); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0xc ^ 0x1b); - XCTAssertEqual(20, _machine->get_cycle_count()); -} - -// MARK: EORI to SR - -- (void)testEORISR_supervisor { - _machine->set_program({ - 0x0a7c, 0x0700 // EORI.W #$700, SR - }); - _machine->set_initial_stack_pointer(300); - - _machine->run_for_instructions(1); - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.program_counter, 0x1004 + 4); - XCTAssertEqual(20, _machine->get_cycle_count()); -} - -- (void)testEORISR_user { - _machine->set_program({ - 0x46fc, 0x0000, // MOVE 0, SR - 0x0a7c, 0x0700 // EORI.W #$700, SR - }); - - _machine->run_for_instructions(2); - - const auto state = _machine->get_processor_state(); - XCTAssertNotEqual(state.program_counter, 0x1008 + 4); -// XCTAssertEqual(34, _machine->get_cycle_count()); -} - // MARK: EXG - (void)testEXG_D1D2 { @@ -4491,224 +3792,6 @@ class CPU::MC68000::ProcessorStorageTests { XCTAssertEqual(4, _machine->get_cycle_count()); } -// MARK: NOT - -- (void)testNOTb { - _machine->set_program({ - 0x4600 // NOT.B D0 - }); - auto state = _machine->get_processor_state(); - state.data[0] = 0x12345678; - - _machine->set_processor_state(state); - _machine->run_for_instructions(1); - - state = _machine->get_processor_state(); - XCTAssertEqual(state.data[0], 0x12345687); - XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Negative); - XCTAssertEqual(4, _machine->get_cycle_count()); -} - -- (void)testNOTw { - _machine->set_program({ - 0x4640 // NOT.w D0 - }); - auto state = _machine->get_processor_state(); - state.data[0] = 0x12340000; - state.status |= Flag::ConditionCodes; - - _machine->set_processor_state(state); - _machine->run_for_instructions(1); - - state = _machine->get_processor_state(); - XCTAssertEqual(state.data[0], 0x1234ffff); - XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Negative | Flag::Extend); - XCTAssertEqual(4, _machine->get_cycle_count()); -} - -- (void)testNOTl_Dn { - _machine->set_program({ - 0x4680 // NOT.l D0 - }); - auto state = _machine->get_processor_state(); - state.data[0] = 0xffffff00; - state.status |= Flag::ConditionCodes; - - _machine->set_processor_state(state); - _machine->run_for_instructions(1); - - state = _machine->get_processor_state(); - XCTAssertEqual(state.data[0], 0x000000ff); - XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend); - XCTAssertEqual(6, _machine->get_cycle_count()); -} - -- (void)testNOTl_XXXl { - _machine->set_program({ - 0x46b9, 0x0000, 0x3000 // NOT.L ($3000).L - }); - *_machine->ram_at(0x3000) = 0xf001; - *_machine->ram_at(0x3002) = 0x2311; - auto state = _machine->get_processor_state(); - state.status |= Flag::Extend; - - _machine->set_processor_state(state); - _machine->run_for_instructions(1); - - state = _machine->get_processor_state(); - XCTAssertEqual(*_machine->ram_at(0x3000), 0x0ffe); - XCTAssertEqual(*_machine->ram_at(0x3002), 0xdcee); - XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend); - XCTAssertEqual(28, _machine->get_cycle_count()); -} - -// MARK: OR - -- (void)testORb { - _machine->set_program({ - 0x8604 // OR.b D4, D3 - }); - auto state = _machine->get_processor_state(); - state.data[3] = 0x54ff0056; - state.data[4] = 0x9853abcd; - 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[3], 0x54ff00df); - XCTAssertEqual(state.data[4], 0x9853abcd); - XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Extend | Flag::Negative); - XCTAssertEqual(4, _machine->get_cycle_count()); -} - -- (void)testORl_toDn { - _machine->set_program({ - 0x86ac, 0xfffa // OR.l -6(A4), D3 - }); - auto state = _machine->get_processor_state(); - state.data[3] = 0x54fff856; - state.address[4] = 0x3006; - *_machine->ram_at(0x3000) = 0x1253; - *_machine->ram_at(0x3002) = 0xfb34; - - _machine->set_processor_state(state); - _machine->run_for_instructions(1); - - state = _machine->get_processor_state(); - XCTAssertEqual(state.data[3], 0x56fffb76); - XCTAssertEqual(state.address[4], 0x3006); - XCTAssertEqual(*_machine->ram_at(0x3000), 0x1253); - XCTAssertEqual(*_machine->ram_at(0x3002), 0xfb34); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0); - XCTAssertEqual(18, _machine->get_cycle_count()); -} - -- (void)testORl_fromDn { - _machine->set_program({ - 0x87ac, 0xfffa // OR.l D3, -6(A4) - }); - auto state = _machine->get_processor_state(); - state.data[3] = 0x54fff856; - state.address[4] = 0x3006; - *_machine->ram_at(0x3000) = 0x1253; - *_machine->ram_at(0x3002) = 0xfb34; - - _machine->set_processor_state(state); - _machine->run_for_instructions(1); - - state = _machine->get_processor_state(); - XCTAssertEqual(state.data[3], 0x54fff856); - XCTAssertEqual(state.address[4], 0x3006); - XCTAssertEqual(*_machine->ram_at(0x3000), 0x56ff); - XCTAssertEqual(*_machine->ram_at(0x3002), 0xfb76); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0); - XCTAssertEqual(24, _machine->get_cycle_count()); -} - -// MARK: ORI - -- (void)testORIb { - _machine->set_program({ - 0x0001, 0x0012 // ORI.B #$12, D1 - }); - - 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], 0x1234567a); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0); - XCTAssertEqual(8, _machine->get_cycle_count()); -} - -- (void)testORIl { - _machine->set_program({ - 0x00b8, 0xffff, 0x0000, 0x3000 // ORI.L #$ffff0000, ($3000).W - }); - - *_machine->ram_at(0x3000) = 0x0000; - *_machine->ram_at(0x3002) = 0xffff; - - _machine->run_for_instructions(1); - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(*_machine->ram_at(0x3000), 0xffff); - XCTAssertEqual(*_machine->ram_at(0x3002), 0xffff); - XCTAssertEqual(state.status & Flag::ConditionCodes, Flag::Negative); - XCTAssertEqual(32, _machine->get_cycle_count()); -} - -// MARK: ORI to CCR - -- (void)testORICCR { - _machine->set_program({ - 0x003c, 0x001b // ORI.b #$1b, CCR - }); - - auto state = _machine->get_processor_state(); - state.status |= 0xc; - - _machine->set_processor_state(state); - _machine->run_for_instructions(1); - - state = _machine->get_processor_state(); - XCTAssertEqual(state.status & Flag::ConditionCodes, 0xc | 0x1b); - XCTAssertEqual(20, _machine->get_cycle_count()); -} - -// MARK: ORI to SR - -- (void)testORISR_supervisor { - _machine->set_program({ - 0x007c, 0x0700 // ORI.W #$700, SR - }); - _machine->set_initial_stack_pointer(300); - - _machine->run_for_instructions(1); - - const auto state = _machine->get_processor_state(); - XCTAssertEqual(state.program_counter, 0x1004 + 4); - XCTAssertEqual(20, _machine->get_cycle_count()); -} - -- (void)testORISR_user { - _machine->set_program({ - 0x46fc, 0x0000, // MOVE 0, SR - 0x007c, 0x0700 // ORI.W #$700, SR - }); - - _machine->run_for_instructions(2); - - const auto state = _machine->get_processor_state(); - XCTAssertNotEqual(state.program_counter, 0x1008 + 4); -// XCTAssertEqual(34, _machine->get_cycle_count()); -} - // MARK: PEA - (void)testPEA_A1 { diff --git a/OSBindings/Mac/Clock SignalTests/TestRunner68000.hpp b/OSBindings/Mac/Clock SignalTests/TestRunner68000.hpp new file mode 100644 index 000000000..1ee6bcb0e --- /dev/null +++ b/OSBindings/Mac/Clock SignalTests/TestRunner68000.hpp @@ -0,0 +1,142 @@ +// +// TestRunner68000.hpp +// Clock Signal +// +// Created by Thomas Harte on 28/06/2019. +// Copyright © 2019 Thomas Harte. All rights reserved. +// + +#ifndef TestRunner68000_h +#define TestRunner68000_h + +#include + +#define LOG_TRACE +#include "../../../Processors/68000/68000.hpp" + +using Flag = CPU::MC68000::Flag; + +/*! + Provides a 68000 with 64kb of RAM in its low address space; + /RESET will put the supervisor stack pointer at 0xFFFF and + begin execution at 0x0400. +*/ +class RAM68000: public CPU::MC68000::BusHandler { + public: + RAM68000() : m68000_(*this) { + // Setup the /RESET vector. + ram_[0] = 0; + ram_[1] = 0x206; // Supervisor stack pointer. + ram_[2] = 0; + ram_[3] = 0x1000; // Initial PC. + + // Ensure the condition codes start unset. + auto state = get_processor_state(); + state.status &= ~Flag::ConditionCodes; + set_processor_state(state); + } + + void set_program(const std::vector &program) { + memcpy(&ram_[0x1000 >> 1], program.data(), program.size() * sizeof(uint16_t)); + + // Add a NOP suffix, to avoid corrupting flags should the attempt to + // run for a certain number of instructions overrun. + ram_[(0x1000 >> 1) + program.size()] = 0x4e71; + } + + void set_initial_stack_pointer(uint32_t sp) { + ram_[0] = sp >> 16; + ram_[1] = sp & 0xffff; + } + + void will_perform(uint32_t address, uint16_t opcode) { + --instructions_remaining_; + } + + void run_for_instructions(int count) { + instructions_remaining_ = count + (has_run_ ? 0 : 1); + finish_reset_if_needed(); + + while(instructions_remaining_) { + run_for(HalfCycles(2)); + } + } + + void run_for(HalfCycles cycles) { + finish_reset_if_needed(); + m68000_.run_for(cycles); + } + + void finish_reset_if_needed() { + // If the 68000 hasn't run yet, build in the necessary + // cycles to finish the reset program, and set the stored state. + if(!has_run_) { + has_run_ = true; + m68000_.run_for(HalfCycles(76)); + duration_ -= HalfCycles(76); + } + } + + uint16_t *ram_at(uint32_t address) { + return &ram_[(address >> 1) % ram_.size()]; + } + + HalfCycles perform_bus_operation(const CPU::MC68000::Microcycle &cycle, int is_supervisor) { + const uint32_t word_address = cycle.word_address(); + if(instructions_remaining_) duration_ += cycle.length; + + using Microcycle = CPU::MC68000::Microcycle; + if(cycle.data_select_active()) { + if(cycle.operation & Microcycle::InterruptAcknowledge) { + cycle.value->halves.low = 10; + } else { + switch(cycle.operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read)) { + default: break; + + case Microcycle::SelectWord | Microcycle::Read: + cycle.value->full = ram_[word_address % ram_.size()]; + break; + case Microcycle::SelectByte | Microcycle::Read: + cycle.value->halves.low = ram_[word_address % ram_.size()] >> cycle.byte_shift(); + break; + case Microcycle::SelectWord: + ram_[word_address % ram_.size()] = cycle.value->full; + break; + case Microcycle::SelectByte: + ram_[word_address % ram_.size()] = uint16_t( + (cycle.value->halves.low << cycle.byte_shift()) | + (ram_[word_address % ram_.size()] & cycle.untouched_byte_mask()) + ); + break; + } + } + } + + return HalfCycles(0); + } + + CPU::MC68000::Processor::State get_processor_state() { + return m68000_.get_state(); + } + + void set_processor_state(const CPU::MC68000::Processor::State &state) { + m68000_.set_state(state); + } + + CPU::MC68000::Processor &processor() { + return m68000_; + } + + int get_cycle_count() { + return duration_.as_int() >> 1; + } + + private: + CPU::MC68000::Processor m68000_; + std::array ram_; + int instructions_remaining_; + HalfCycles duration_; + bool has_run_ = false; +}; + +#endif /* TestRunner68000_h */