mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-23 03:32:32 +00:00
Merge branch '68000Mk2' into InMacintosh
This commit is contained in:
commit
5937737bb7
@ -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
@ -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 ®isters){
|
||||
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 ®isters){
|
||||
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 ®isters){
|
||||
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 ®isters){
|
||||
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 ®isters){
|
||||
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 ®isters){
|
||||
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 ®isters){
|
||||
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 ®isters){
|
||||
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 ®isters){
|
||||
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 ®isters){
|
||||
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
@ -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
|
||||
|
@ -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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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
@ -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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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 ®isters) {
|
||||
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());
|
||||
|
@ -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 ®isters){
|
||||
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);
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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.
|
||||
|
@ -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 ®isters) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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) {}
|
||||
|
Loading…
Reference in New Issue
Block a user