mirror of
https://github.com/TomHarte/CLK.git
synced 2024-07-09 06:29:33 +00:00
Shuffle mildly, primarily to avoid repeated 16mb allocations.
This commit is contained in:
parent
da9fb216b1
commit
c35200fbd0
@ -22,12 +22,11 @@
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/// Binds a 68000 executor to 16mb of RAM.
|
/// Binds a 68000 executor to 16mb of RAM.
|
||||||
struct Test68000 {
|
struct TestExecutor {
|
||||||
std::array<uint8_t, 16*1024*1024> ram;
|
uint8_t *const ram;
|
||||||
InstructionSet::M68k::Executor<InstructionSet::M68k::Model::M68000, Test68000> processor;
|
InstructionSet::M68k::Executor<InstructionSet::M68k::Model::M68000, TestExecutor> processor;
|
||||||
|
|
||||||
Test68000() : processor(*this) {
|
TestExecutor(uint8_t *ram) : ram(ram), processor(*this) {}
|
||||||
}
|
|
||||||
|
|
||||||
void run_for_instructions(int instructions) {
|
void run_for_instructions(int instructions) {
|
||||||
processor.run_for_instructions(instructions);
|
processor.run_for_instructions(instructions);
|
||||||
@ -83,6 +82,39 @@ struct Test68000 {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Binds a bus-accurate 68000 to 16mb of RAM.
|
||||||
|
struct TestProcessor: public CPU::MC68000Mk2::BusHandler {
|
||||||
|
uint8_t *const ram;
|
||||||
|
CPU::MC68000Mk2::Processor<TestProcessor, true, false, true> processor;
|
||||||
|
std::function<void(void)> comparitor;
|
||||||
|
|
||||||
|
TestProcessor(uint8_t *ram) : ram(ram), processor(*this) {}
|
||||||
|
|
||||||
|
void will_perform(uint32_t, uint16_t) {
|
||||||
|
--instructions_remaining_;
|
||||||
|
if(!instructions_remaining_) comparitor();
|
||||||
|
}
|
||||||
|
|
||||||
|
HalfCycles perform_bus_operation(const CPU::MC68000Mk2::Microcycle &cycle, int) {
|
||||||
|
using Microcycle = CPU::MC68000Mk2::Microcycle;
|
||||||
|
if(cycle.data_select_active()) {
|
||||||
|
cycle.apply(&ram[cycle.host_endian_byte_address()]);
|
||||||
|
}
|
||||||
|
return HalfCycles(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_for_instructions(int instructions, const std::function<void(void)> &compare) {
|
||||||
|
instructions_remaining_ = instructions + 1; // i.e. run up to the will_perform of the instruction after.
|
||||||
|
comparitor = std::move(compare);
|
||||||
|
while(instructions_remaining_) {
|
||||||
|
processor.run_for(HalfCycles(2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int instructions_remaining_;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@interface M68000ComparativeTests : XCTestCase
|
@interface M68000ComparativeTests : XCTestCase
|
||||||
@ -97,10 +129,16 @@ struct Test68000 {
|
|||||||
NSMutableDictionary<NSNumber *, NSMutableArray<NSString *> *> *_suggestedCorrections;
|
NSMutableDictionary<NSNumber *, NSMutableArray<NSString *> *> *_suggestedCorrections;
|
||||||
|
|
||||||
InstructionSet::M68k::Predecoder<InstructionSet::M68k::Model::M68000> _decoder;
|
InstructionSet::M68k::Predecoder<InstructionSet::M68k::Model::M68000> _decoder;
|
||||||
Test68000 _test68000;
|
|
||||||
|
std::array<uint8_t, 16*1024*1024> _ram;
|
||||||
|
std::unique_ptr<TestExecutor> _testExecutor;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setUp {
|
- (void)setUp {
|
||||||
|
#ifdef USE_EXECUTOR
|
||||||
|
_testExecutor = std::make_unique<TestExecutor>(_ram.data());
|
||||||
|
#endif
|
||||||
|
|
||||||
// These will accumulate a list of failing tests and associated opcodes.
|
// These will accumulate a list of failing tests and associated opcodes.
|
||||||
_failures = [[NSMutableSet alloc] init];
|
_failures = [[NSMutableSet alloc] init];
|
||||||
_failingOpcodes = [[NSMutableArray alloc] init];
|
_failingOpcodes = [[NSMutableArray alloc] init];
|
||||||
@ -177,42 +215,9 @@ struct Test68000 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)testOperationClassic:(NSDictionary *)test name:(NSString *)name {
|
- (void)testOperationClassic:(NSDictionary *)test name:(NSString *)name {
|
||||||
|
auto uniqueTest68000 = std::make_unique<TestProcessor>(_ram.data());
|
||||||
// This is the test class for 68000 execution.
|
|
||||||
struct Test68000: public CPU::MC68000Mk2::BusHandler {
|
|
||||||
std::array<uint8_t, 16*1024*1024> ram;
|
|
||||||
CPU::MC68000Mk2::Processor<Test68000, true, false, true> processor;
|
|
||||||
std::function<void(void)> comparitor;
|
|
||||||
|
|
||||||
Test68000() : processor(*this) {}
|
|
||||||
|
|
||||||
void will_perform(uint32_t, uint16_t) {
|
|
||||||
--instructions_remaining_;
|
|
||||||
if(!instructions_remaining_) comparitor();
|
|
||||||
}
|
|
||||||
|
|
||||||
HalfCycles perform_bus_operation(const CPU::MC68000Mk2::Microcycle &cycle, int) {
|
|
||||||
using Microcycle = CPU::MC68000Mk2::Microcycle;
|
|
||||||
if(cycle.data_select_active()) {
|
|
||||||
cycle.apply(&ram[cycle.host_endian_byte_address()]);
|
|
||||||
}
|
|
||||||
return HalfCycles(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void run_for_instructions(int instructions, const std::function<void(void)> &compare) {
|
|
||||||
instructions_remaining_ = instructions + 1; // i.e. run up to the will_perform of the instruction after.
|
|
||||||
comparitor = std::move(compare);
|
|
||||||
while(instructions_remaining_) {
|
|
||||||
processor.run_for(HalfCycles(2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
int instructions_remaining_;
|
|
||||||
};
|
|
||||||
auto uniqueTest68000 = std::make_unique<Test68000>();
|
|
||||||
auto test68000 = uniqueTest68000.get();
|
auto test68000 = uniqueTest68000.get();
|
||||||
memset(test68000->ram.data(), 0xce, test68000->ram.size());
|
memset(_ram.data(), 0xce, _ram.size());
|
||||||
|
|
||||||
{
|
{
|
||||||
// Apply initial memory state.
|
// Apply initial memory state.
|
||||||
@ -294,7 +299,7 @@ struct Test68000 {
|
|||||||
// Definitively erase any prior memory contents;
|
// Definitively erase any prior memory contents;
|
||||||
// 0xce is arbitrary but hopefully easier to spot
|
// 0xce is arbitrary but hopefully easier to spot
|
||||||
// in potential errors than e.g. 0x00 or 0xff.
|
// in potential errors than e.g. 0x00 or 0xff.
|
||||||
memset(_test68000.ram.data(), 0xce, _test68000.ram.size());
|
memset(_ram.data(), 0xce, _ram.size());
|
||||||
|
|
||||||
// Apply initial memory state.
|
// Apply initial memory state.
|
||||||
NSArray<NSNumber *> *const initialMemory = test[@"initial memory"];
|
NSArray<NSNumber *> *const initialMemory = test[@"initial memory"];
|
||||||
@ -304,12 +309,12 @@ struct Test68000 {
|
|||||||
NSNumber *const value = [enumerator nextObject];
|
NSNumber *const value = [enumerator nextObject];
|
||||||
|
|
||||||
if(!address || !value) break;
|
if(!address || !value) break;
|
||||||
_test68000.ram[address.integerValue] = value.integerValue;
|
_testExecutor->ram[address.integerValue] = value.integerValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply initial processor state.
|
// Apply initial processor state.
|
||||||
NSDictionary *const initialState = test[@"initial state"];
|
NSDictionary *const initialState = test[@"initial state"];
|
||||||
auto state = _test68000.processor.get_state();
|
auto state = _testExecutor->processor.get_state();
|
||||||
for(int c = 0; c < 8; ++c) {
|
for(int c = 0; c < 8; ++c) {
|
||||||
const NSString *dX = [@"d" stringByAppendingFormat:@"%d", c];
|
const NSString *dX = [@"d" stringByAppendingFormat:@"%d", c];
|
||||||
const NSString *aX = [@"a" stringByAppendingFormat:@"%d", c];
|
const NSString *aX = [@"a" stringByAppendingFormat:@"%d", c];
|
||||||
@ -322,18 +327,18 @@ struct Test68000 {
|
|||||||
state.user_stack_pointer = uint32_t([initialState[@"usp"] integerValue]);
|
state.user_stack_pointer = uint32_t([initialState[@"usp"] integerValue]);
|
||||||
state.status = [initialState[@"sr"] integerValue];
|
state.status = [initialState[@"sr"] integerValue];
|
||||||
state.program_counter = uint32_t([initialState[@"pc"] integerValue]);
|
state.program_counter = uint32_t([initialState[@"pc"] integerValue]);
|
||||||
_test68000.processor.set_state(state);
|
_testExecutor->processor.set_state(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testOperationExecutor:(NSDictionary *)test name:(NSString *)name {
|
- (void)testOperationExecutor:(NSDictionary *)test name:(NSString *)name {
|
||||||
[self setInitialState:test];
|
[self setInitialState:test];
|
||||||
|
|
||||||
// Run the thing.
|
// Run the thing.
|
||||||
_test68000.run_for_instructions(1);
|
_testExecutor->run_for_instructions(1);
|
||||||
|
|
||||||
// Test the end state.
|
// Test the end state.
|
||||||
NSDictionary *const finalState = test[@"final state"];
|
NSDictionary *const finalState = test[@"final state"];
|
||||||
const auto state = _test68000.processor.get_state();
|
const auto state = _testExecutor->processor.get_state();
|
||||||
for(int c = 0; c < 8; ++c) {
|
for(int c = 0; c < 8; ++c) {
|
||||||
const NSString *dX = [@"d" stringByAppendingFormat:@"%d", c];
|
const NSString *dX = [@"d" stringByAppendingFormat:@"%d", c];
|
||||||
const NSString *aX = [@"a" stringByAppendingFormat:@"%d", c];
|
const NSString *aX = [@"a" stringByAppendingFormat:@"%d", c];
|
||||||
@ -346,7 +351,7 @@ struct Test68000 {
|
|||||||
|
|
||||||
const uint16_t correctSR = [finalState[@"sr"] integerValue];
|
const uint16_t correctSR = [finalState[@"sr"] integerValue];
|
||||||
if(state.status != correctSR) {
|
if(state.status != correctSR) {
|
||||||
const uint16_t opcode = _test68000.read<uint16_t>(0x100, InstructionSet::M68k::FunctionCode());
|
const uint16_t opcode = _testExecutor->read<uint16_t>(0x100, InstructionSet::M68k::FunctionCode());
|
||||||
const auto instruction = _decoder.decode(opcode);
|
const auto instruction = _decoder.decode(opcode);
|
||||||
|
|
||||||
// For DIVU and DIVS, for now, test only the well-defined flags.
|
// For DIVU and DIVS, for now, test only the well-defined flags.
|
||||||
@ -379,13 +384,13 @@ struct Test68000 {
|
|||||||
NSNumber *const value = [enumerator nextObject];
|
NSNumber *const value = [enumerator nextObject];
|
||||||
|
|
||||||
if(!address || !value) break;
|
if(!address || !value) break;
|
||||||
if(_test68000.ram[address.integerValue] != value.integerValue) [_failures addObject:name];
|
if(_testExecutor->ram[address.integerValue] != value.integerValue) [_failures addObject:name];
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this test is now in the failures set, add the corresponding opcode for
|
// If this test is now in the failures set, add the corresponding opcode for
|
||||||
// later logging.
|
// later logging.
|
||||||
if([_failures containsObject:name]) {
|
if([_failures containsObject:name]) {
|
||||||
NSNumber *const opcode = @(_test68000.read<uint16_t>(0x100, InstructionSet::M68k::FunctionCode()));
|
NSNumber *const opcode = @(_testExecutor->read<uint16_t>(0x100, InstructionSet::M68k::FunctionCode()));
|
||||||
|
|
||||||
// Add this opcode to the failing list.
|
// Add this opcode to the failing list.
|
||||||
[_failingOpcodes addObject:opcode];
|
[_failingOpcodes addObject:opcode];
|
||||||
|
Loading…
Reference in New Issue
Block a user