1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-05 10:28:58 +00:00

Factor out register setup/testing, generalising the DIVU/DIVS flag check.

This commit is contained in:
Thomas Harte 2022-05-18 21:13:34 -04:00
parent 1bf7c0ae5f
commit 29f6b02c04

View File

@ -240,47 +240,15 @@ struct TestProcessor: public CPU::MC68000Mk2::BusHandler {
}
// Apply initial processor state.
NSDictionary *const initialState = test[@"initial state"];
auto state = test68000->processor.get_state();
for(int c = 0; c < 8; ++c) {
const NSString *dX = [@"d" stringByAppendingFormat:@"%d", c];
const NSString *aX = [@"a" stringByAppendingFormat:@"%d", c];
state.registers.data[c] = uint32_t([initialState[dX] integerValue]);
if(c < 7)
state.registers.address[c] = uint32_t([initialState[aX] integerValue]);
}
state.registers.supervisor_stack_pointer = uint32_t([initialState[@"a7"] integerValue]);
state.registers.user_stack_pointer = uint32_t([initialState[@"usp"] integerValue]);
state.registers.status = [initialState[@"sr"] integerValue];
state.registers = [self initialRegisters:test];
test68000->processor.set_state(state);
}
// Run the thing.
const auto comparitor = [=] {
// Test the end state.
NSDictionary *const finalState = test[@"final state"];
const auto state = test68000->processor.get_state();
for(int c = 0; c < 8; ++c) {
const NSString *dX = [@"d" stringByAppendingFormat:@"%d", c];
const NSString *aX = [@"a" stringByAppendingFormat:@"%d", c];
if(state.registers.data[c] != [finalState[dX] integerValue]) [_failures addObject:name];
if(c < 7 && state.registers.address[c] != [finalState[aX] integerValue]) [_failures addObject:name];
XCTAssertEqual(state.registers.data[c], [finalState[dX] integerValue], @"%@: D%d inconsistent", name, c);
if(c < 7) {
XCTAssertEqual(state.registers.address[c], [finalState[aX] integerValue], @"%@: A%d inconsistent", name, c);
}
}
if(state.registers.supervisor_stack_pointer != [finalState[@"a7"] integerValue]) [_failures addObject:name];
if(state.registers.user_stack_pointer != [finalState[@"usp"] integerValue]) [_failures addObject:name];
if(state.registers.status != [finalState[@"sr"] integerValue]) [_failures addObject:name];
XCTAssertEqual(state.registers.supervisor_stack_pointer, [finalState[@"a7"] integerValue], @"%@: A7 inconsistent", name);
XCTAssertEqual(state.registers.user_stack_pointer, [finalState[@"usp"] integerValue], @"%@: USP inconsistent", name);
XCTAssertEqual(state.registers.status, [finalState[@"sr"] integerValue], @"%@: Status inconsistent", name);
XCTAssertEqual(state.registers.program_counter - 4, [finalState[@"pc"] integerValue], @"%@: Program counter inconsistent", name);
[self test:test name:name compareFinalRegisters:state.registers];
// Test final memory state.
NSArray<NSNumber *> *const finalMemory = test[@"final memory"];
@ -321,21 +289,7 @@ struct TestProcessor: public CPU::MC68000Mk2::BusHandler {
}
// Apply initial processor state.
NSDictionary *const initialState = test[@"initial state"];
auto state = _testExecutor->processor.get_state();
for(int c = 0; c < 8; ++c) {
const NSString *dX = [@"d" stringByAppendingFormat:@"%d", c];
const NSString *aX = [@"a" stringByAppendingFormat:@"%d", c];
state.data[c] = uint32_t([initialState[dX] integerValue]);
if(c < 7)
state.address[c] = uint32_t([initialState[aX] integerValue]);
}
state.supervisor_stack_pointer = uint32_t([initialState[@"a7"] integerValue]);
state.user_stack_pointer = uint32_t([initialState[@"usp"] integerValue]);
state.status = [initialState[@"sr"] integerValue];
state.program_counter = uint32_t([initialState[@"pc"] integerValue]);
_testExecutor->processor.set_state(state);
_testExecutor->processor.set_state([self initialRegisters:test]);
}
- (void)testOperationExecutor:(NSDictionary *)test name:(NSString *)name {
@ -345,44 +299,8 @@ struct TestProcessor: public CPU::MC68000Mk2::BusHandler {
_testExecutor->run_for_instructions(1);
// Test the end state.
NSDictionary *const finalState = test[@"final state"];
const auto state = _testExecutor->processor.get_state();
for(int c = 0; c < 8; ++c) {
const NSString *dX = [@"d" stringByAppendingFormat:@"%d", c];
const NSString *aX = [@"a" stringByAppendingFormat:@"%d", c];
if(state.data[c] != [finalState[dX] integerValue]) [_failures addObject:name];
if(c < 7 && state.address[c] != [finalState[aX] integerValue]) [_failures addObject:name];
}
if(state.supervisor_stack_pointer != [finalState[@"a7"] integerValue]) [_failures addObject:name];
if(state.user_stack_pointer != [finalState[@"usp"] integerValue]) [_failures addObject:name];
const uint16_t correctSR = [finalState[@"sr"] integerValue];
if(state.status != correctSR) {
const uint16_t opcode = _testExecutor->read<uint16_t>(0x100, InstructionSet::M68k::FunctionCode());
const auto instruction = _decoder.decode(opcode);
// For DIVU and DIVS, for now, test only the well-defined flags.
if(
instruction.operation != InstructionSet::M68k::Operation::DIVS &&
instruction.operation != InstructionSet::M68k::Operation::DIVU
) {
[_failures addObject:name];
} else {
uint16_t status_mask = 0xff13; // i.e. extend, which should be unaffected, and overflow, which
// is well-defined unless there was a divide by zero. But this
// test set doesn't include any divide by zeroes.
if(!(correctSR & InstructionSet::M68k::ConditionCode::Overflow)) {
// If overflow didn't occur then negative and zero are also well-defined.
status_mask |= 0x000c;
}
if((state.status & status_mask) != (([finalState[@"sr"] integerValue]) & status_mask)) {
[_failures addObject:name];
}
}
}
[self test:test name:name compareFinalRegisters:state];
// Test final memory state.
NSArray<NSNumber *> *const finalMemory = test[@"final memory"];
@ -433,4 +351,65 @@ struct TestProcessor: public CPU::MC68000Mk2::BusHandler {
}
}
- (InstructionSet::M68k::RegisterSet)initialRegisters:(NSDictionary *)test {
InstructionSet::M68k::RegisterSet registers;
NSDictionary *const initialState = test[@"initial state"];
for(int c = 0; c < 8; ++c) {
const NSString *dX = [@"d" stringByAppendingFormat:@"%d", c];
const NSString *aX = [@"a" stringByAppendingFormat:@"%d", c];
registers.data[c] = uint32_t([initialState[dX] integerValue]);
if(c < 7)
registers.address[c] = uint32_t([initialState[aX] integerValue]);
}
registers.supervisor_stack_pointer = uint32_t([initialState[@"a7"] integerValue]);
registers.user_stack_pointer = uint32_t([initialState[@"usp"] integerValue]);
registers.status = [initialState[@"sr"] integerValue];
registers.program_counter = uint32_t([initialState[@"pc"] integerValue]);
return registers;
}
- (void)test:(NSDictionary *)test name:(NSString *)name compareFinalRegisters:(InstructionSet::M68k::RegisterSet)registers {
// Test the end state.
NSDictionary *const finalState = test[@"final state"];
for(int c = 0; c < 8; ++c) {
const NSString *dX = [@"d" stringByAppendingFormat:@"%d", c];
const NSString *aX = [@"a" stringByAppendingFormat:@"%d", c];
if(registers.data[c] != [finalState[dX] integerValue]) [_failures addObject:name];
if(c < 7 && registers.address[c] != [finalState[aX] integerValue]) [_failures addObject:name];
}
if(registers.supervisor_stack_pointer != [finalState[@"a7"] integerValue]) [_failures addObject:name];
if(registers.user_stack_pointer != [finalState[@"usp"] integerValue]) [_failures addObject:name];
const uint16_t correctSR = [finalState[@"sr"] integerValue];
if(registers.status != correctSR) {
const uint16_t opcode = _testExecutor->read<uint16_t>(0x100, InstructionSet::M68k::FunctionCode());
const auto instruction = _decoder.decode(opcode);
// For DIVU and DIVS, for now, test only the well-defined flags.
if(
instruction.operation != InstructionSet::M68k::Operation::DIVS &&
instruction.operation != InstructionSet::M68k::Operation::DIVU
) {
[_failures addObject:name];
} else {
uint16_t status_mask = 0xff13; // i.e. extend, which should be unaffected, and overflow, which
// is well-defined unless there was a divide by zero. But this
// test set doesn't include any divide by zeroes.
if(!(correctSR & InstructionSet::M68k::ConditionCode::Overflow)) {
// If overflow didn't occur then negative and zero are also well-defined.
status_mask |= 0x000c;
}
if((registers.status & status_mask) != (([finalState[@"sr"] integerValue]) & status_mask)) {
[_failures addObject:name];
}
}
}
}
@end