1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-03 11:30:02 +00:00

Factors the bitwise tests out of the main bundle, as that pushes up towards 6,000 lines.

This commit is contained in:
Thomas Harte 2019-06-28 21:58:38 -04:00
parent 9eb51f164c
commit 7cc91e1bc5
4 changed files with 968 additions and 918 deletions

View File

@ -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 = "<group>"; };
4B8FE2251DA1DE2D0090D3CE /* NSBundle+DataResource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+DataResource.h"; sourceTree = "<group>"; };
4B8FE2261DA1DE2D0090D3CE /* NSBundle+DataResource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+DataResource.m"; sourceTree = "<group>"; };
4B90467222C6FA31000E2074 /* TestRunner68000.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = TestRunner68000.hpp; sourceTree = "<group>"; };
4B90467322C6FADD000E2074 /* 68000BitwiseTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = 68000BitwiseTests.mm; sourceTree = "<group>"; };
4B92294222B04A3D00A1458F /* MouseMachine.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MouseMachine.hpp; sourceTree = "<group>"; };
4B92294422B04ACB00A1458F /* Mouse.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Mouse.hpp; sourceTree = "<group>"; };
4B92294A22B064FD00A1458F /* QuadratureMouse.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = QuadratureMouse.hpp; sourceTree = "<group>"; };
@ -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 */,

View File

@ -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 <XCTest/XCTest.h>
#include "TestRunner68000.hpp"
@interface M68000BitwiseTests : XCTestCase
@end
@implementation M68000BitwiseTests {
std::unique_ptr<RAM68000> _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

View File

@ -8,136 +8,9 @@
#import <XCTest/XCTest.h>
#include <array>
#include <cassert>
#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<uint16_t> &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<RAM68000, true>::State get_processor_state() {
return m68000_.get_state();
}
void set_processor_state(const CPU::MC68000::Processor<RAM68000, true>::State &state) {
m68000_.set_state(state);
}
CPU::MC68000::Processor<RAM68000, true, true> &processor() {
return m68000_;
}
int get_cycle_count() {
return duration_.as_int() >> 1;
}
private:
CPU::MC68000::Processor<RAM68000, true, true> m68000_;
std::array<uint16_t, 256*1024> 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 {

View File

@ -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 <array>
#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<uint16_t> &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<RAM68000, true>::State get_processor_state() {
return m68000_.get_state();
}
void set_processor_state(const CPU::MC68000::Processor<RAM68000, true>::State &state) {
m68000_.set_state(state);
}
CPU::MC68000::Processor<RAM68000, true, true> &processor() {
return m68000_;
}
int get_cycle_count() {
return duration_.as_int() >> 1;
}
private:
CPU::MC68000::Processor<RAM68000, true, true> m68000_;
std::array<uint16_t, 256*1024> ram_;
int instructions_remaining_;
HalfCycles duration_;
bool has_run_ = false;
};
#endif /* TestRunner68000_h */