diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 5a338aa6c..fb752c11b 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -306,6 +306,8 @@ 4B98A1CE1FFADEC500ADF63B /* MSX ROMs in Resources */ = {isa = PBXBuildFile; fileRef = 4B98A1CD1FFADEC400ADF63B /* MSX ROMs */; }; 4B9BE400203A0C0600FFAE60 /* MultiSpeaker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B9BE3FE203A0C0600FFAE60 /* MultiSpeaker.cpp */; }; 4B9BE401203A0C0600FFAE60 /* MultiSpeaker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B9BE3FE203A0C0600FFAE60 /* MultiSpeaker.cpp */; }; + 4B9F11C92272375400701480 /* qltrace.txt.gz in Resources */ = {isa = PBXBuildFile; fileRef = 4B9F11C82272375400701480 /* qltrace.txt.gz */; }; + 4B9F11CA2272433900701480 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B69FB451C4D950F00B5F0AA /* libz.tbd */; }; 4BA0F68E1EEA0E8400E9489E /* ZX8081.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BA0F68C1EEA0E8400E9489E /* ZX8081.cpp */; }; 4BA61EB01D91515900B3C876 /* NSData+StdVector.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BA61EAF1D91515900B3C876 /* NSData+StdVector.mm */; }; 4BA91E1D216D85BA00F79557 /* MasterSystemVDPTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4BA91E1C216D85BA00F79557 /* MasterSystemVDPTests.mm */; }; @@ -1037,6 +1039,7 @@ 4B98A1CD1FFADEC400ADF63B /* MSX ROMs */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "MSX ROMs"; sourceTree = ""; }; 4B9BE3FE203A0C0600FFAE60 /* MultiSpeaker.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MultiSpeaker.cpp; sourceTree = ""; }; 4B9BE3FF203A0C0600FFAE60 /* MultiSpeaker.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MultiSpeaker.hpp; sourceTree = ""; }; + 4B9F11C82272375400701480 /* qltrace.txt.gz */ = {isa = PBXFileReference; lastKnownFileType = archive.gzip; path = qltrace.txt.gz; sourceTree = ""; }; 4BA0F68C1EEA0E8400E9489E /* ZX8081.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ZX8081.cpp; path = Data/ZX8081.cpp; sourceTree = ""; }; 4BA0F68D1EEA0E8400E9489E /* ZX8081.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = ZX8081.hpp; path = Data/ZX8081.hpp; sourceTree = ""; }; 4BA141C12073100800A31EC9 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Target.hpp; sourceTree = ""; }; @@ -1495,6 +1498,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 4B9F11CA2272433900701480 /* libz.tbd in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1567,6 +1571,7 @@ 4B44EBF61DC9883B00A7820C /* 6502_functional_test.bin */, 4B44EBF41DC987AE00A7820C /* AllSuiteA.bin */, 4BBF49B41ED2881600AB3669 /* FUSE */, + 4B9F11C72272375400701480 /* QL Startup */, 4BB297E41B587D8300A49093 /* Wolfgang Lorenz 6502 test suite */, 4BE9A6B21EDE294200CBCB47 /* Zexall */, ); @@ -2444,6 +2449,14 @@ path = Implementation; sourceTree = ""; }; + 4B9F11C72272375400701480 /* QL Startup */ = { + isa = PBXGroup; + children = ( + 4B9F11C82272375400701480 /* qltrace.txt.gz */, + ); + path = "QL Startup"; + sourceTree = ""; + }; 4BAB62AA1D3272D200DF5BA0 /* Disk */ = { isa = PBXGroup; children = ( @@ -3633,6 +3646,7 @@ 4BB299A41B587D8400A49093 /* oraz in Resources */, 4BB299611B587D8400A49093 /* insax in Resources */, 4BB299351B587D8400A49093 /* cmpix in Resources */, + 4B9F11C92272375400701480 /* qltrace.txt.gz in Resources */, 4BB299041B587D8400A49093 /* aneb in Resources */, 4BB299BB1B587D8400A49093 /* rraa in Resources */, 4BB299091B587D8400A49093 /* aslz in Resources */, diff --git a/OSBindings/Mac/Clock SignalTests/QL Startup/qltrace.txt.gz b/OSBindings/Mac/Clock SignalTests/QL Startup/qltrace.txt.gz new file mode 100644 index 000000000..fa886ae8d Binary files /dev/null and b/OSBindings/Mac/Clock SignalTests/QL Startup/qltrace.txt.gz differ diff --git a/OSBindings/Mac/Clock SignalTests/QLTests.mm b/OSBindings/Mac/Clock SignalTests/QLTests.mm index 28f32d69a..5a3d1a731 100644 --- a/OSBindings/Mac/Clock SignalTests/QLTests.mm +++ b/OSBindings/Mac/Clock SignalTests/QLTests.mm @@ -14,24 +14,58 @@ #include #include +#include + #include "68000.hpp" #include "CSROMFetcher.hpp" class QL: public CPU::MC68000::BusHandler { public: - QL(const std::vector &rom) : m68000_(*this) { + QL(const std::vector &rom, const char *trace_name) : m68000_(*this) { assert(!(rom.size() & 1)); rom_.resize(rom.size() / 2); for(size_t c = 0; c < rom_.size(); ++c) { rom_[c] = (rom[c << 1] << 8) | rom[(c << 1) + 1]; } + + trace = gzopen(trace_name, "rt"); + } + + ~QL() { + gzclose(trace); } void run_for(HalfCycles cycles) { m68000_.run_for(cycles); } + void will_perform(uint32_t address, uint16_t opcode) { + // Obtain the next line from the trace file. + char correct_state[300]; + gzgets(trace, correct_state, sizeof(correct_state)); + ++line_count; + + // Generate state locally. + const auto state = m68000_.get_state(); + char local_state[300]; + sprintf(local_state, "%04x: %02x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x \n", + address, + state.status, + state.data[0], state.data[1], state.data[2], state.data[3], state.data[4], state.data[5], state.data[6], state.data[7], + state.address[0], state.address[1], state.address[2], state.address[3], state.address[4], state.address[5], state.address[6], + (state.status & 0x2000) ? state.supervisor_stack_pointer : state.user_stack_pointer + ); + + // Check that the two coincide. + if(strcmp(correct_state, local_state)) { + fprintf(stderr, "Diverges at line %d\n", line_count); + fprintf(stderr, "Good: %s", correct_state); + fprintf(stderr, "Bad: %s", local_state); + assert(false); + } + } + HalfCycles perform_bus_operation(const CPU::MC68000::Microcycle &cycle, int is_supervisor) { const uint32_t address = cycle.word_address(); uint32_t word_address = address; @@ -52,22 +86,6 @@ class QL: public CPU::MC68000::BusHandler { using Microcycle = CPU::MC68000::Microcycle; if(cycle.data_select_active()) { uint16_t peripheral_result = 0xffff; -/* if(is_peripheral) { - switch(address & 0x7ff) { - // A hard-coded value for TIMER B. - case (0xa21 >> 1): - peripheral_result = 0x00000001; - break; - } - printf("Peripheral: %c %08x", (cycle.operation & Microcycle::Read) ? 'r' : 'w', *cycle.address); - if(!(cycle.operation & Microcycle::Read)) { - if(cycle.operation & Microcycle::SelectByte) - printf(" %02x", cycle.value->halves.low); - else - printf(" %04x", cycle.value->full); - } - printf("\n"); - }*/ switch(cycle.operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read)) { default: break; @@ -93,10 +111,13 @@ class QL: public CPU::MC68000::BusHandler { } private: - CPU::MC68000::Processor m68000_; + CPU::MC68000::Processor m68000_; std::vector rom_; std::array ram_; + + int line_count = 0; + gzFile trace; }; @interface QLTests : XCTestCase @@ -106,18 +127,16 @@ class QL: public CPU::MC68000::BusHandler { std::unique_ptr _machine; } -std::streambuf *coutbuf; - -- (void)setUp { - const auto roms = CSROMFetcher()("SinclairQL", {"js.rom"}); - _machine.reset(new QL(*roms[0])); -} - +/*! + Tests the progression of Clock Signal's 68000 through the Sinclair QL's ROM against a known-good trace. +*/ - (void)testStartup { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - _machine->run_for(HalfCycles(40000000)); + const auto roms = CSROMFetcher()("SinclairQL", {"js.rom"}); + NSString *const traceLocation = [[NSBundle bundleForClass:[self class]] pathForResource:@"qltrace" ofType:@".txt.gz"]; + _machine.reset(new QL(*roms[0], traceLocation.UTF8String)); + + // This is how many cycles it takes to exhaust the supplied trace file. + _machine->run_for(HalfCycles(23923191)); } @end -