1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-16 22:28:57 +00:00

Merge branch '68000Mk2' into InMacintosh

This commit is contained in:
Thomas Harte 2022-05-26 19:37:44 -04:00
commit 5937737bb7
13 changed files with 1255 additions and 1395 deletions

View File

@ -40,6 +40,27 @@ All initial register contents are random except that the lowest bit is never set
So the output is very scattergun approach, with a lot of redundancy.
## Known Issues
Errors in generation mean that:
1. MOVE is mostly untested; MOVEq is well-tested and other MOVEs appear within the test set as per the approximate generation algorithm above but due to an error in the generation of move.json, all of its opcodes are $2000 less than they should be, causing them to hit various instructions other than MOVE;
2. there is sparse coverage of the rotates and shifts: LS[L/R], AS[L/R], RO[L/R] and ROX[L/R]; and
3. there are similarly few tests of MULU.
Issues with comparing results between multiple emulators in the case of unusual instructions mean that no tests have been generated for:
1. MOVE [to or from] SR;
2. TRAP;
3. TRAPV;
4. MOVE [to or from] USP;
5. STOP;
6. RTE;
7. Bcc where the offset is an odd number; or
8. BSR where the offset is an odd number.
For both Bcc and BSR, there is good coverage of even-quantity offsets.
Lack of good documentation for the meaning of N and Z flags for DIVU and DIVS in the case of overflow means that the results here may or may not be correct; there was no consensus between emulators and I have been unable to find information on what the proper answers should be.
## Questionable Results
Values for the undocumented flags of DIVU and DIVS have not yet been verified, due to a lack of documentation.
Values for the undocumented flags of DIVU and DIVS have not yet been verified, due to a lack of documentation.

File diff suppressed because it is too large Load Diff

View File

@ -32,13 +32,13 @@
_machine->set_program({
0xc302, // ABCD D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0x1234567a;
state.registers.data[2] = 0xf745ff78;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers){
registers.data[1] = 0x1234567a;
registers.data[2] = 0xf745ff78;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssert(state.registers.status & ConditionCode::Carry);
XCTAssertEqual(state.registers.data[1], 0x12345658);
XCTAssertEqual(state.registers.data[2], 0xf745ff78);
@ -48,14 +48,14 @@
_machine->set_program({
0xc302, // ABCD D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0x12345600;
state.registers.data[2] = 0x12345600;
state.registers.status = ConditionCode::Zero;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers){
registers.data[1] = 0x12345600;
registers.data[2] = 0x12345600;
registers.status = ConditionCode::Zero;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssert(state.registers.status & ConditionCode::Zero);
XCTAssertEqual(state.registers.data[1], 0x12345600);
XCTAssertEqual(state.registers.data[2], 0x12345600);
@ -65,14 +65,14 @@
_machine->set_program({
0xc302, // ABCD D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0x12345645;
state.registers.data[2] = 0x12345654;
state.registers.status = ConditionCode::Zero;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers){
registers.data[1] = 0x12345645;
registers.data[2] = 0x12345654;
registers.status = ConditionCode::Zero;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssert(state.registers.status & ConditionCode::Negative);
XCTAssertEqual(state.registers.data[1], 0x12345699);
XCTAssertEqual(state.registers.data[2], 0x12345654);
@ -82,14 +82,14 @@
_machine->set_program({
0xc302, // ABCD D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0x12345645;
state.registers.data[2] = 0x12345654;
state.registers.status = ConditionCode::Extend;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers){
registers.data[1] = 0x12345645;
registers.data[2] = 0x12345654;
registers.status = ConditionCode::Extend;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssert(state.registers.status & ConditionCode::Carry);
XCTAssertEqual(state.registers.data[1], 0x12345600);
XCTAssertEqual(state.registers.data[2], 0x12345654);
@ -99,14 +99,14 @@
_machine->set_program({
0xc302, // ABCD D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0x1234563e;
state.registers.data[2] = 0x1234563e;
state.registers.status = ConditionCode::Extend;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers){
registers.data[1] = 0x1234563e;
registers.data[2] = 0x1234563e;
registers.status = ConditionCode::Extend;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssert(state.registers.status & ConditionCode::Overflow);
XCTAssertEqual(state.registers.data[1], 0x12345683);
XCTAssertEqual(state.registers.data[2], 0x1234563e);
@ -116,17 +116,16 @@
_machine->set_program({
0xc30a, // ABCD -(A2), -(A1)
});
_machine->set_registers([=](auto &registers){
registers.address[1] = 0x3001;
registers.address[2] = 0x4001;
registers.status = ConditionCode::Extend;
});
*_machine->ram_at(0x3000) = 0xa200;
*_machine->ram_at(0x4000) = 0x1900;
auto state = _machine->get_processor_state();
state.registers.address[1] = 0x3001;
state.registers.address[2] = 0x4001;
state.registers.status = ConditionCode::Extend;
_machine->set_processor_state(state);
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssert(state.registers.status & ConditionCode::Carry);
XCTAssert(state.registers.status & ConditionCode::Extend);
XCTAssertEqual(state.registers.address[1], 0x3000);
@ -139,15 +138,14 @@
_machine->set_program({
0xc309, // ABCD -(A1), -(A1)
});
_machine->set_registers([=](auto &registers){
registers.address[1] = 0x3002;
registers.status = ConditionCode::Extend;
});
*_machine->ram_at(0x3000) = 0x19a2;
auto state = _machine->get_processor_state();
state.registers.address[1] = 0x3002;
state.registers.status = ConditionCode::Extend;
_machine->set_processor_state(state);
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssert(state.registers.status & ConditionCode::Carry);
XCTAssert(state.registers.status & ConditionCode::Extend);
XCTAssertEqual(state.registers.address[1], 0x3000);
@ -160,11 +158,10 @@
_machine->set_program({
0x4801 // NBCD D1
});
auto state = _machine->get_processor_state();
state.registers.status |= ccr;
state.registers.data[1] = d1;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers){
registers.status |= ccr;
registers.data[1] = d1;
});
_machine->run_for_instructions(1);
XCTAssertEqual(6, _machine->get_cycle_count());
@ -222,15 +219,14 @@
_machine->set_program({
0x8302 // SBCD D2, D1
});
auto state = _machine->get_processor_state();
state.registers.status |= ccr;
state.registers.data[1] = d1;
state.registers.data[2] = d2;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers){
registers.status |= ccr;
registers.data[1] = d1;
registers.data[2] = d2;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(6, _machine->get_cycle_count());
XCTAssertEqual(state.registers.data[2], d2);
}
@ -273,15 +269,14 @@
});
*_machine->ram_at(0x3000) = 0xa200;
*_machine->ram_at(0x4000) = 0x1900;
auto state = _machine->get_processor_state();
state.registers.address[1] = 0x3001;
state.registers.address[2] = 0x4001;
state.registers.status |= ConditionCode::Extend;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers){
registers.address[1] = 0x3001;
registers.address[2] = 0x4001;
registers.status |= ConditionCode::Extend;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(18, _machine->get_cycle_count());
XCTAssertEqual(*_machine->ram_at(0x3000), 0x8200);
XCTAssertEqual(*_machine->ram_at(0x4000), 0x1900);

File diff suppressed because it is too large Load Diff

View File

@ -18,6 +18,7 @@
//#define USE_EXECUTOR
//#define MAKE_SUGGESTIONS
//#define LOG_UNTESTED
namespace {
@ -127,6 +128,7 @@ struct TestProcessor: public CPU::MC68000Mk2::BusHandler {
NSMutableSet<NSString *> *_failures;
NSMutableArray<NSNumber *> *_failingOpcodes;
NSMutableDictionary<NSNumber *, NSMutableArray<NSString *> *> *_suggestedCorrections;
NSMutableSet<NSNumber *> *_testedOpcodes;
InstructionSet::M68k::Predecoder<InstructionSet::M68k::Model::M68000> _decoder;
@ -150,6 +152,10 @@ struct TestProcessor: public CPU::MC68000Mk2::BusHandler {
_failures = [[NSMutableSet alloc] init];
_failingOpcodes = [[NSMutableArray alloc] init];
// This will simply accumulate a list of all tested opcodes, in order to report
// on those that are missing.
_testedOpcodes = [[NSMutableSet alloc] init];
#ifdef MAKE_SUGGESTIONS
_suggestedCorrections = [[NSMutableDictionary alloc] init];
#endif
@ -190,6 +196,25 @@ struct TestProcessor: public CPU::MC68000Mk2::BusHandler {
}
}
}
#ifdef LOG_UNTESTED
// Output a list of untested opcodes.
NSMutableArray<NSString *> *untested = [[NSMutableArray alloc] init];
for(int opcode = 0; opcode < 65536; opcode++) {
const auto instruction = _decoder.decode(uint16_t(opcode));
if(instruction.operation == InstructionSet::M68k::Operation::Undefined) {
continue;
}
if([_testedOpcodes containsObject:@(opcode)]) {
continue;
}
[untested addObject:[NSString stringWithFormat:@"%04x %s", opcode, instruction.to_string(uint16_t(opcode)).c_str()]];
}
NSLog(@"Untested: %@", untested);
#endif
}
- (void)testJSONAtURL:(NSURL *)url {
@ -213,6 +238,20 @@ struct TestProcessor: public CPU::MC68000Mk2::BusHandler {
// Compare against a test set if one has been supplied.
if(_testSet && ![_testSet containsObject:name]) continue;
// Pull out the opcode and record it.
NSArray<NSNumber *> *const initialMemory = test[@"initial memory"];
uint16_t opcode = 0;
NSEnumerator<NSNumber *> *enumerator = [initialMemory objectEnumerator];
while(true) {
NSNumber *const address = [enumerator nextObject];
NSNumber *const value = [enumerator nextObject];
if(!address || !value) break;
if(address.integerValue == 0x100) opcode |= value.integerValue << 8;
if(address.integerValue == 0x101) opcode |= value.integerValue;
}
[_testedOpcodes addObject:@(opcode)];
#ifdef USE_EXECUTOR
[self testOperationExecutor:test name:name];
#else

View File

@ -108,8 +108,7 @@
- (void)testBSRw {
_machine->set_program({
0x6100, 0x0006 // BSR.w $1008
});
_machine->set_initial_stack_pointer(0x3000);
}, 0x3000);
_machine->run_for_instructions(1);
@ -126,8 +125,7 @@
- (void)testBSRb {
_machine->set_program({
0x6106 // BSR.b $1008
});
_machine->set_initial_stack_pointer(0x3000);
}, 0x3000);
_machine->run_for_instructions(1);
@ -146,17 +144,15 @@
- (void)performCHKd1:(uint32_t)d1 d2:(uint32_t)d2 {
_machine->set_program({
0x4581 // CHK D1, D2
}, 0);
_machine->set_registers([=](auto &registers) {
registers.data[1] = d1;
registers.data[2] = d2;
registers.status |= ConditionCode::AllConditions;
});
auto state = _machine->get_processor_state();
state.registers.data[1] = d1;
state.registers.data[2] = d2;
state.registers.status |= ConditionCode::AllConditions;
_machine->set_initial_stack_pointer(0);
_machine->set_processor_state(state);
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], d1);
XCTAssertEqual(state.registers.data[2], d2);
}
@ -204,14 +200,13 @@
_machine->set_program({
opcode, 0x0008 // DBcc D2, +8
});
auto state = _machine->get_processor_state();
state.registers.status = status;
state.registers.data[2] = 1;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.status = status;
registers.data[2] = 1;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[2], d2Output);
XCTAssertEqual(state.registers.status, status);
}
@ -385,13 +380,12 @@
0x4ed1 // JMP (A1)
});
auto state = _machine->get_processor_state();
state.registers.address[1] = 0x3000;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.address[1] = 0x3000;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.address[1], 0x3000);
XCTAssertEqual(state.registers.program_counter, 0x3000 + 4);
XCTAssertEqual(8, _machine->get_cycle_count());
@ -414,8 +408,7 @@
- (void)testJSR_PC {
_machine->set_program({
0x4eba, 0x000a // JSR (+a)PC ; JSR to $100c
});
_machine->set_initial_stack_pointer(0x2000);
}, 0x2000);
_machine->run_for_instructions(1);
@ -430,8 +423,7 @@
- (void)testJSR_XXXl {
_machine->set_program({
0x4eb9, 0x0000, 0x1008 // JSR ($1008).l
});
_machine->set_initial_stack_pointer(0x2000);
}, 0x2000);
_machine->run_for_instructions(1);
@ -458,8 +450,7 @@
- (void)testRTR {
_machine->set_program({
0x4e77 // RTR
});
_machine->set_initial_stack_pointer(0x2000);
}, 0x2000);
*_machine->ram_at(0x2000) = 0x7fff;
*_machine->ram_at(0x2002) = 0;
*_machine->ram_at(0x2004) = 0xc;
@ -478,8 +469,7 @@
- (void)testRTS {
_machine->set_program({
0x4e75 // RTS
});
_machine->set_initial_stack_pointer(0x2000);
}, 0x2000);
*_machine->ram_at(0x2000) = 0x0000;
*_machine->ram_at(0x2002) = 0x000c;
@ -497,17 +487,16 @@
_machine->set_program({
0x4e41 // TRAP #1
});
auto state = _machine->get_processor_state();
state.registers.status = 0x700;
state.registers.user_stack_pointer = 0x200;
state.registers.supervisor_stack_pointer = 0x206;
_machine->set_registers([=](auto &registers) {
registers.status = 0x700;
registers.user_stack_pointer = 0x200;
registers.supervisor_stack_pointer = 0x206;
});
*_machine->ram_at(0x84) = 0xfffe;
*_machine->ram_at(0xfffe) = 0x4e71;
_machine->set_processor_state(state);
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.status, 0x2700);
XCTAssertEqual(*_machine->ram_at(0x200), 0x700);
XCTAssertEqual(*_machine->ram_at(0x202), 0x0000);
@ -521,19 +510,18 @@
- (void)testTRAPV_taken {
_machine->set_program({
0x4e76 // TRAPV
});
_machine->set_initial_stack_pointer(0x206);
}, 0x206);
auto state = _machine->get_processor_state();
state.registers.status = 0x702;
state.registers.supervisor_stack_pointer = 0x206;
_machine->set_registers([=](auto &registers) {
registers.status = 0x702;
registers.supervisor_stack_pointer = 0x206;
});
*_machine->ram_at(0x1e) = 0xfffe;
*_machine->ram_at(0xfffe) = 0x4e71;
_machine->set_processor_state(state);
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.status, 0x2702);
XCTAssertEqual(state.registers.stack_pointer(), 0x200);
XCTAssertEqual(*_machine->ram_at(0x202), 0x0000);

File diff suppressed because it is too large Load Diff

View File

@ -33,14 +33,13 @@
_machine->set_program({
0xe521 // ASL.B D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 2;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 2;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xce3dd59c);
XCTAssertEqual(state.registers.data[2], 2);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative | ConditionCode::Overflow | ConditionCode::Carry);
@ -51,14 +50,13 @@
_machine->set_program({
0xe521 // ASL.B D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 105;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 105;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xce3dd500);
XCTAssertEqual(state.registers.data[2], 105);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Overflow | ConditionCode::Zero);
@ -69,14 +67,13 @@
_machine->set_program({
0xe561 // ASL.w D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 0;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 0;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xce3dd567);
XCTAssertEqual(state.registers.data[2], 0);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative);
@ -87,14 +84,13 @@
_machine->set_program({
0xe561 // ASL.w D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 0xb;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 0xb;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xce3d3800);
XCTAssertEqual(state.registers.data[2], 0xb);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Overflow | ConditionCode::Carry);
@ -105,14 +101,13 @@
_machine->set_program({
0xe5a1 // ASL.l D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 0x20;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 0x20;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0);
XCTAssertEqual(state.registers.data[2], 0x20);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Overflow | ConditionCode::Carry | ConditionCode::Zero);
@ -123,14 +118,13 @@
_machine->set_program({
0xe181 // ASL.l #8, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 0x20;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 0x20;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x3dd56700);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Overflow);
XCTAssertEqual(24, _machine->get_cycle_count());
@ -172,14 +166,13 @@
_machine->set_program({
0xe421 // ASR.B D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 2;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 2;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xce3dd519);
XCTAssertEqual(state.registers.data[2], 2);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Carry);
@ -190,14 +183,13 @@
_machine->set_program({
0xe421 // ASR.B D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 105;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 105;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xce3dd500);
XCTAssertEqual(state.registers.data[2], 105);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Zero);
@ -208,14 +200,13 @@
_machine->set_program({
0xe461 // ASR.w D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 0;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 0;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xce3dd567);
XCTAssertEqual(state.registers.data[2], 0);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative);
@ -226,14 +217,13 @@
_machine->set_program({
0xe461 // ASR.w D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 0xb;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 0xb;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xce3dfffa);
XCTAssertEqual(state.registers.data[2], 0xb);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative | ConditionCode::Carry);
@ -244,14 +234,13 @@
_machine->set_program({
0xe4a1 // ASR.l D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 0x20;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 0x20;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xffffffff);
XCTAssertEqual(state.registers.data[2], 0x20);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative | ConditionCode::Carry);
@ -262,14 +251,13 @@
_machine->set_program({
0xe081 // ASR.l #8, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 0x20;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 0x20;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xffce3dd5);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative);
XCTAssertEqual(24, _machine->get_cycle_count());
@ -311,14 +299,13 @@
_machine->set_program({
0xe529 // LSL.b D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 2;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 2;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xce3dd59c);
XCTAssertEqual(state.registers.data[2], 2);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Negative | ConditionCode::Carry);
@ -329,14 +316,13 @@
_machine->set_program({
0xe529 // LSL.b D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 0x69;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 0x69;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xce3dd500);
XCTAssertEqual(state.registers.data[2], 0x69);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Zero);
@ -347,14 +333,13 @@
_machine->set_program({
0xe569 // LSL.w D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 0;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 0;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xce3dd567);
XCTAssertEqual(state.registers.data[2], 0);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative);
@ -365,14 +350,13 @@
_machine->set_program({
0xe569 // LSL.w D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 0xb;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 0xb;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xce3d3800);
XCTAssertEqual(state.registers.data[2], 0xb);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Carry);
@ -383,14 +367,13 @@
_machine->set_program({
0xe5a9 // LSL.l D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 0x20;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 0x20;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0);
XCTAssertEqual(state.registers.data[2], 0x20);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Carry | ConditionCode::Zero);
@ -401,13 +384,12 @@
_machine->set_program({
0xe189 // LSL.l #8, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0x3dd56700);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(24, _machine->get_cycle_count());
@ -433,14 +415,13 @@
_machine->set_program({
0xe429 // LSR.b D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 2;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 2;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xce3dd519);
XCTAssertEqual(state.registers.data[2], 2);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Carry);
@ -451,14 +432,13 @@
_machine->set_program({
0xe429 // LSR.b D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 0x69;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 0x69;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xce3dd500);
XCTAssertEqual(state.registers.data[2], 0x69);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Zero);
@ -469,14 +449,13 @@
_machine->set_program({
0xe469 // LSR.w D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 0;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 0;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xce3dd567);
XCTAssertEqual(state.registers.data[2], 0);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative);
@ -487,14 +466,13 @@
_machine->set_program({
0xe469 // LSR.w D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 0xb;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 0xb;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xce3d001a);
XCTAssertEqual(state.registers.data[2], 0xb);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Carry);
@ -505,14 +483,13 @@
_machine->set_program({
0xe4a9 // LSR.l D2, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
state.registers.data[2] = 0x20;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
registers.data[2] = 0x20;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0);
XCTAssertEqual(state.registers.data[2], 0x20);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Carry | ConditionCode::Zero);
@ -523,13 +500,12 @@
_machine->set_program({
0xe089 // LSR.L #8, D1
});
auto state = _machine->get_processor_state();
state.registers.data[1] = 0xce3dd567;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[1] = 0xce3dd567;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], 0xce3dd5);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(24, _machine->get_cycle_count());
@ -555,13 +531,12 @@
_machine->set_program({
0xe118 // ROL.B #8, D0
});
auto state = _machine->get_processor_state();
state.registers.data[0] = 0xce3dd567;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0xce3dd567;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0xce3dd567);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry);
XCTAssertEqual(22, _machine->get_cycle_count());
@ -571,13 +546,12 @@
_machine->set_program({
0xe318 // ROL.B #1, D0
});
auto state = _machine->get_processor_state();
state.registers.data[0] = 0xce3dd567;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0xce3dd567;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0xce3dd5ce);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative);
XCTAssertEqual(8, _machine->get_cycle_count());
@ -587,14 +561,13 @@
_machine->set_program({
0xe518 // ROL.B #2, D0
});
auto state = _machine->get_processor_state();
state.registers.data[0] = 0xce3dd567;
state.registers.status = ConditionCode::AllConditions;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0xce3dd567;
registers.status = ConditionCode::AllConditions;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0xce3dd59d);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative | ConditionCode::Extend | ConditionCode::Carry);
XCTAssertEqual(10, _machine->get_cycle_count());
@ -604,14 +577,13 @@
_machine->set_program({
0xef18 // ROL.B #7, D0
});
auto state = _machine->get_processor_state();
state.registers.data[0] = 0xce3dd567;
state.registers.status = ConditionCode::AllConditions;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0xce3dd567;
registers.status = ConditionCode::AllConditions;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0xce3dd5b3);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative | ConditionCode::Extend | ConditionCode::Carry);
XCTAssertEqual(20, _machine->get_cycle_count());
@ -621,14 +593,13 @@
_machine->set_program({
0xe158 // ROL.w #7, D0
});
auto state = _machine->get_processor_state();
state.registers.data[0] = 0xce3dd567;
state.registers.status = ConditionCode::AllConditions;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0xce3dd567;
registers.status = ConditionCode::AllConditions;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0xce3d67d5);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Carry);
XCTAssertEqual(22, _machine->get_cycle_count());
@ -638,14 +609,13 @@
_machine->set_program({
0xe798 // ROL.l #3, D0
});
auto state = _machine->get_processor_state();
state.registers.data[0] = 0xce3dd567;
state.registers.status = ConditionCode::AllConditions;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0xce3dd567;
registers.status = ConditionCode::AllConditions;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0x71eeab3e);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend);
XCTAssertEqual(14, _machine->get_cycle_count());
@ -655,12 +625,11 @@
_machine->set_program({
0xe378 // ROL.l D1, D0
});
auto state = _machine->get_processor_state();
state.registers.data[0] = 0xce3dd567;
state.registers.data[1] = d1;
state.registers.status = ConditionCode::AllConditions;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0xce3dd567;
registers.data[1] = d1;
registers.status = ConditionCode::AllConditions;
});
_machine->run_for_instructions(1);
}
@ -695,15 +664,14 @@
_machine->set_program({
0xe3b8 // ROL.l D1, D0
});
auto state = _machine->get_processor_state();
state.registers.data[0] = 0xce3dd567;
state.registers.data[1] = 200;
state.registers.status = ConditionCode::AllConditions;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0xce3dd567;
registers.data[1] = 200;
registers.status = ConditionCode::AllConditions;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0x3dd567ce);
XCTAssertEqual(state.registers.data[1], 200);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend);
@ -744,10 +712,9 @@
_machine->set_program({
uint16_t(0xe018 | (immediate << 9)) // ROR.b #, D0
});
auto state = _machine->get_processor_state();
state.registers.data[0] = 0xce3dd599;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0xce3dd599;
});
_machine->run_for_instructions(1);
}
@ -791,13 +758,12 @@
_machine->set_program({
0xec58 // ROR.w #6, D0
});
auto state = _machine->get_processor_state();
state.registers.data[0] = 0xce3dd599;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0xce3dd599;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0xce3d6756);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(18, _machine->get_cycle_count());
@ -807,13 +773,12 @@
_machine->set_program({
0xea98 // ROR.l #5, D0
});
auto state = _machine->get_processor_state();
state.registers.data[0] = 0xce3dd599;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0xce3dd599;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0xce71eeac);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Negative);
XCTAssertEqual(18, _machine->get_cycle_count());
@ -823,14 +788,13 @@
_machine->set_program({
0xe238 // ROR.b D1, D0
});
auto state = _machine->get_processor_state();
state.registers.data[0] = 0xce3dd599;
state.registers.data[1] = 20;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0xce3dd599;
registers.data[1] = 20;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0xce3dd599);
XCTAssertEqual(state.registers.data[1], 20);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Negative);
@ -841,14 +805,13 @@
_machine->set_program({
0xe2b8 // ROR.l D1, D0
});
auto state = _machine->get_processor_state();
state.registers.data[0] = 0xce3dd599;
state.registers.data[1] = 26;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0xce3dd599;
registers.data[1] = 26;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0x8f756673);
XCTAssertEqual(state.registers.data[1], 26);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Negative);
@ -888,15 +851,14 @@
_machine->set_program({
0xe330 // ROXL.b D1, D0
});
auto state = _machine->get_processor_state();
state.registers.data[0] = 0xce3dd567;
state.registers.data[1] = 9;
state.registers.status |= ccr;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0xce3dd567;
registers.data[1] = 9;
registers.status |= ccr;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(24, _machine->get_cycle_count());
XCTAssertEqual(state.registers.data[0], 0xce3dd567);
XCTAssertEqual(state.registers.data[1], 9);
@ -920,15 +882,14 @@
_machine->set_program({
0xe370 // ROXL.w D1, D0
});
auto state = _machine->get_processor_state();
state.registers.data[0] = 0xce3dd567;
state.registers.data[1] = d1;
state.registers.status |= ccr;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0xce3dd567;
registers.data[1] = d1;
registers.status |= ccr;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], d1);
}
@ -963,15 +924,14 @@
_machine->set_program({
0xe3b0 // ROXL.l D1, D0
});
auto state = _machine->get_processor_state();
state.registers.data[0] = 0xce3dd567;
state.registers.data[1] = 33;
state.registers.status |= ConditionCode::Extend;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0xce3dd567;
registers.data[1] = 33;
registers.status |= ConditionCode::Extend;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0xce3dd567);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Negative | ConditionCode::Carry | ConditionCode::Extend);
XCTAssertEqual(74, _machine->get_cycle_count());
@ -981,14 +941,13 @@
_machine->set_program({
0xe950 // ROXL.w #4, D0
});
auto state = _machine->get_processor_state();
state.registers.data[0] = 0xce3d3600;
state.registers.status |= ConditionCode::Extend;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0xce3d3600;
registers.status |= ConditionCode::Extend;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0xce3d6009);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Extend | ConditionCode::Carry);
XCTAssertEqual(14, _machine->get_cycle_count());
@ -1014,15 +973,14 @@
_machine->set_program({
0xe230 // ROXR.b D1, D0
});
auto state = _machine->get_processor_state();
state.registers.data[0] = 0xce3dd567;
state.registers.data[1] = 9;
state.registers.status |= ccr;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0xce3dd567;
registers.data[1] = 9;
registers.status |= ccr;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(24, _machine->get_cycle_count());
XCTAssertEqual(state.registers.data[0], 0xce3dd567);
XCTAssertEqual(state.registers.data[1], 9);
@ -1046,15 +1004,14 @@
_machine->set_program({
0xe270 // ROXR.w D1, D0
});
auto state = _machine->get_processor_state();
state.registers.data[0] = 0xce3dd567;
state.registers.data[1] = d1;
state.registers.status |= ccr;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0xce3dd567;
registers.data[1] = d1;
registers.status |= ccr;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[1], d1);
}
@ -1089,14 +1046,13 @@
_machine->set_program({
0xe890 // ROXR.L #4, D0
});
auto state = _machine->get_processor_state();
state.registers.data[0] = 0xce3d3600;
state.registers.status |= ConditionCode::Extend;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers) {
registers.data[0] = 0xce3d3600;
registers.status |= ConditionCode::Extend;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(state.registers.data[0], 0x1ce3d360);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, 0);
XCTAssertEqual(16, _machine->get_cycle_count());
@ -1106,14 +1062,13 @@
_machine->set_program({
0xe4f8, 0x3000 // ROXR.W ($3000).W
});
_machine->set_registers([=](auto &registers) {
registers.status |= ConditionCode::Extend;
});
*_machine->ram_at(0x3000) = 0xd567;
auto state = _machine->get_processor_state();
state.registers.status |= ConditionCode::Extend;
_machine->set_processor_state(state);
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
XCTAssertEqual(*_machine->ram_at(0x3000), 0xeab3);
XCTAssertEqual(state.registers.status & ConditionCode::AllConditions, ConditionCode::Carry | ConditionCode::Extend | ConditionCode::Negative);
XCTAssertEqual(16, _machine->get_cycle_count());

View File

@ -125,15 +125,13 @@ class CPU::MC68000::ProcessorStorageTests {
_machine->set_program({
0xc100 // ABCD D0, D0
});
auto state = _machine->get_processor_state();
const uint8_t bcd_d = ((d / 10) * 16) + (d % 10);
state.registers.data[0] = bcd_d;
_machine->set_processor_state(state);
_machine->set_registers([=](auto &registers){
registers.data[0] = bcd_d;
});
_machine->run_for_instructions(1);
state = _machine->get_processor_state();
const auto state = _machine->get_processor_state();
const uint8_t double_d = (d * 2) % 100;
const uint8_t bcd_double_d = ((double_d / 10) * 16) + (double_d % 10);
XCTAssert(state.registers.data[0] == bcd_double_d, "%02x + %02x = %02x; should equal %02x", bcd_d, bcd_d, state.registers.data[0], bcd_double_d);
@ -148,8 +146,7 @@ class CPU::MC68000::ProcessorStorageTests {
0x82C0, // DIVU; location 0x404
/* Next instruction would be at 0x406 */
});
_machine->set_initial_stack_pointer(0x1000);
}, 0x1000);
_machine->run_for_instructions(4);

View File

@ -10,6 +10,7 @@
#define TestRunner68000_h
#include <array>
#include <functional>
#include <vector>
#include "../../../Processors/68000Mk2/68000Mk2.hpp"
@ -23,71 +24,63 @@ using namespace InstructionSet::M68k;
*/
class RAM68000: public CPU::MC68000Mk2::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.registers.status &= ~ConditionCode::AllConditions;
set_processor_state(state);
}
RAM68000() : m68000_(*this) {}
uint32_t initial_pc() const {
return 0x1000;
}
void set_program(const std::vector<uint16_t> &program) {
void set_program(
const std::vector<uint16_t> &program,
uint32_t stack_pointer = 0x206
) {
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;
// Ensure the condition codes start unset and set the initial program counter
// and supervisor stack pointer, as well as starting in supervisor mode.
auto registers = m68000_.get_state().registers;
registers.status = 0x2700;
registers.program_counter = initial_pc();
registers.supervisor_stack_pointer = stack_pointer;
m68000_.decode_from_state(registers);
}
void set_initial_stack_pointer(uint32_t sp) {
ram_[0] = sp >> 16;
ram_[1] = sp & 0xffff;
void set_registers(std::function<void(InstructionSet::M68k::RegisterSet &)> func) {
auto state = m68000_.get_state();
func(state.registers);
m68000_.set_state(state);
}
void will_perform(uint32_t, uint16_t) {
--instructions_remaining_;
if(instructions_remaining_ < 0) {
throw StopException();
}
}
void run_for_instructions(int count) {
instructions_remaining_ = count + (has_run_ ? 0 : 1);
finish_reset_if_needed();
duration_ = HalfCycles(0);
instructions_remaining_ = count;
if(!instructions_remaining_) return;
while(instructions_remaining_) {
run_for(HalfCycles(2));
}
try {
while(true) {
run_for(HalfCycles(2000));
}
} catch (const StopException &) {}
}
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::MC68000Mk2::Microcycle &cycle, int) {
const uint32_t word_address = cycle.word_address();
if(instructions_remaining_) duration_ += cycle.length;
duration_ += cycle.length;
using Microcycle = CPU::MC68000Mk2::Microcycle;
if(cycle.data_select_active()) {
@ -123,10 +116,6 @@ class RAM68000: public CPU::MC68000Mk2::BusHandler {
return m68000_.get_state();
}
void set_processor_state(const CPU::MC68000Mk2::State &state) {
m68000_.set_state(state);
}
auto &processor() {
return m68000_;
}
@ -140,11 +129,12 @@ class RAM68000: public CPU::MC68000Mk2::BusHandler {
}
private:
CPU::MC68000Mk2::Processor<RAM68000, true, false, true> m68000_;
struct StopException {};
CPU::MC68000Mk2::Processor<RAM68000, true, true, true> m68000_;
std::array<uint16_t, 256*1024> ram_{};
int instructions_remaining_;
HalfCycles duration_;
bool has_run_ = false;
};
#endif /* TestRunner68000_h */

View File

@ -397,9 +397,18 @@ class Processor: private ProcessorBase {
void run_for(HalfCycles duration);
/// @returns The current processor state.
CPU::MC68000Mk2::State get_state();
/// Sets the current processor state.
void set_state(const CPU::MC68000Mk2::State &);
/// Sets all registers to the values provided, fills the prefetch queue and ensures the
/// next action the processor will take is to decode whatever is in the queue.
///
/// The queue is filled synchronously, during this call, causing calls to the bus handler.
void decode_from_state(const InstructionSet::M68k::RegisterSet &);
// TODO: bus ack/grant, halt,
/// Sets the DTack line — @c true for active, @c false for inactive.

View File

@ -135,7 +135,8 @@ enum ExecutionState: int {
Bccb_branch_not_taken,
Bccw_branch_not_taken,
BSR,
BSRb,
BSRw,
JSRJMPAddressRegisterIndirect,
JSRJMPAddressRegisterIndirectWithDisplacement,
@ -244,7 +245,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
// Performs no bus activity for the specified number of microcycles.
#define IdleBus(n) \
idle.length = HalfCycles(n * 4); \
idle.length = HalfCycles((n) << 2); \
PerformBusOperation(idle)
// Spin until DTACK, VPA or BERR is asserted (unless DTACK is implicit),
@ -317,6 +318,12 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
prefetch_.high = prefetch_.low; \
ReadProgramWord(prefetch_.low)
// Raises the exception with integer vector x — x is the vector identifier,
// not its address.
#define RaiseException(x) \
exception_vector_ = x; \
MoveToStateSpecific(StandardException);
using Mode = InstructionSet::M68k::AddressingMode;
// Otherwise continue for all time, until back in debt.
@ -577,8 +584,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
// Potentially perform a trace.
if(should_trace_) {
exception_vector_ = InstructionSet::M68k::Exception::Trace;
MoveToStateSpecific(StandardException);
RaiseException(InstructionSet::M68k::Exception::Trace);
}
// Capture the current trace flag.
@ -809,8 +815,8 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
SpecialCASE(Bccb);
SpecialCASE(Bccw);
StdCASE(BSRb, perform_state_ = BSR);
StdCASE(BSRw, perform_state_ = BSR);
SpecialCASE(BSRb);
SpecialCASE(BSRw);
Duplicate(JMP, JSR)
StdCASE(JSR, {
@ -1745,14 +1751,12 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
BeginState(CHK_was_over):
IdleBus(2); // nn
instruction_address_.l = program_counter_.l - 4;
exception_vector_ = InstructionSet::M68k::Exception::CHK;
MoveToStateSpecific(StandardException);
RaiseException(InstructionSet::M68k::Exception::CHK);
BeginState(CHK_was_under):
IdleBus(3); // n nn
instruction_address_.l = program_counter_.l - 4;
exception_vector_ = InstructionSet::M68k::Exception::CHK;
MoveToStateSpecific(StandardException);
RaiseException(InstructionSet::M68k::Exception::CHK);
//
// Scc
@ -1863,22 +1867,22 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
//
// BSR
//
BeginState(BSR):
BeginState(BSRb):
BeginState(BSRw):
IdleBus(1); // n
// Calculate the address of the next instruction.
// Calculate the address of the next instruction and the next program counter.
if(instruction_.operand_size() == InstructionSet::M68k::DataSize::Word) {
temporary_address_.l = instruction_address_.l + 4;
program_counter_.l = instruction_address_.l + uint32_t(int16_t(prefetch_.w)) + 2;
} else {
temporary_address_.l = instruction_address_.l + 2;
program_counter_.l = instruction_address_.l + uint32_t(int8_t(opcode_)) + 2;
}
// Push it to the stack.
// Push the next instruction address to the stack.
Push(temporary_address_);
// Get the new PC.
PerformDynamic();
Prefetch(); // np
Prefetch(); // np
MoveToStateSpecific(Decode);
@ -2015,6 +2019,8 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
// [EORI/ORI/ANDI] #, [CCR/SR]
//
BeginState(LogicalToSR):
IdleBus(4);
// Perform the operation.
PerformDynamic();
@ -2425,8 +2431,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
BeginState(TRAP):
IdleBus(2);
instruction_address_.l += 2; // Push the address of the instruction after the trap.
exception_vector_ = (opcode_ & 15) + InstructionSet::M68k::Exception::TrapBase;
MoveToStateSpecific(StandardException);
RaiseException((opcode_ & 15) + InstructionSet::M68k::Exception::TrapBase);
BeginState(TRAPV):
Prefetch();
@ -2434,8 +2439,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
MoveToStateSpecific(Decode);
}
instruction_address_.l += 2; // Push the address of the instruction after the trap.
exception_vector_ = InstructionSet::M68k::Exception::TRAPV;
MoveToStateSpecific(StandardException);
RaiseException(InstructionSet::M68k::Exception::TRAPV);
default:
printf("Unhandled state: %d; opcode is %04x\n", state_, opcode_);
@ -2446,6 +2450,7 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
#undef Push
#undef PerformDynamic
#undef PerformSpecific
#undef RaiseException
#undef Prefetch
#undef ReadProgramWord
#undef ReadDataWord
@ -2510,10 +2515,6 @@ template <typename IntT> void ProcessorBase::complete_bcc(bool take_branch, IntT
Bccb_branch_not_taken : Bccw_branch_not_taken;
}
void ProcessorBase::bsr(uint32_t offset) {
program_counter_.l = instruction_address_.l + offset + 2;
}
void ProcessorBase::did_bit_op(int bit_position) {
dynamic_instruction_length_ = int(bit_position > 15);
}
@ -2612,6 +2613,29 @@ void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perfor
did_update_status();
}
template <class BusHandler, bool dtack_is_implicit, bool permit_overrun, bool signal_will_perform>
void Processor<BusHandler, dtack_is_implicit, permit_overrun, signal_will_perform>::decode_from_state(const InstructionSet::M68k::RegisterSet &registers) {
// Populate registers.
CPU::MC68000Mk2::State state;
state.registers = registers;
set_state(state);
// Ensure the state machine will resume at decode.
state_ = Decode;
// Fill the prefetch queue.
captured_interrupt_level_ = bus_interrupt_level_;
read_program.value = &prefetch_.high;
bus_handler_.perform_bus_operation(read_program_announce, is_supervisor_);
bus_handler_.perform_bus_operation(read_program, is_supervisor_);
program_counter_.l += 2;
read_program.value = &prefetch_.low;
bus_handler_.perform_bus_operation(read_program_announce, is_supervisor_);
bus_handler_.perform_bus_operation(read_program, is_supervisor_);
program_counter_.l += 2;
}
}
}

View File

@ -155,7 +155,6 @@ struct ProcessorBase: public InstructionSet::M68k::NullFlowController {
inline void did_update_status();
template <typename IntT> void complete_bcc(bool, IntT);
inline void complete_dbcc(bool, bool, int16_t);
inline void bsr(uint32_t);
inline void move_to_usp(uint32_t);
inline void move_from_usp(uint32_t &);
inline void tas(Preinstruction, uint32_t);
@ -167,6 +166,7 @@ struct ProcessorBase: public InstructionSet::M68k::NullFlowController {
template <typename IntT> void movem_toM(Preinstruction, uint32_t, uint32_t) {}
template <typename IntT> void movem_toR(Preinstruction, uint32_t, uint32_t) {}
void jsr(uint32_t) {}
void bsr(uint32_t) {}
void jmp(uint32_t) {}
inline void pea(uint32_t) {}
inline void link(Preinstruction, uint32_t) {}