From c466b6f9e7769e1dc7479c9c9105f45227f1ad48 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 29 Apr 2019 16:11:01 -0400 Subject: [PATCH] Factors out the [unit testing] stuff of being a trace-checking 68000 bus handler. --- .../Clock Signal.xcodeproj/project.pbxproj | 2 + .../Clock SignalTests/Comparative68000.hpp | 59 +++++++++++++++++++ OSBindings/Mac/Clock SignalTests/QLTests.mm | 40 ++----------- .../Implementation/68000Implementation.hpp | 6 +- .../68000/Implementation/68000Storage.cpp | 9 +++ 5 files changed, 78 insertions(+), 38 deletions(-) create mode 100644 OSBindings/Mac/Clock SignalTests/Comparative68000.hpp diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index d4c4332ce..06da8a234 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -963,6 +963,7 @@ 4B83348E1F5DBA6E0097E338 /* 6522Storage.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = 6522Storage.hpp; path = Implementation/6522Storage.hpp; sourceTree = ""; }; 4B8334911F5E24FF0097E338 /* C1540Base.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = C1540Base.hpp; path = Implementation/C1540Base.hpp; sourceTree = ""; }; 4B8334941F5E25B60097E338 /* C1540.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = C1540.cpp; path = Implementation/C1540.cpp; sourceTree = ""; }; + 4B85322922778E4200F26553 /* Comparative68000.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Comparative68000.hpp; sourceTree = ""; }; 4B86E2591F8C628F006FAA45 /* Keyboard.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Keyboard.cpp; sourceTree = ""; }; 4B86E25A1F8C628F006FAA45 /* Keyboard.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Keyboard.hpp; sourceTree = ""; }; 4B8805EE1DCFC99C003085B1 /* Acorn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Acorn.cpp; path = Parsers/Acorn.cpp; sourceTree = ""; }; @@ -2842,6 +2843,7 @@ 4BB73EB51B587A5100552FC2 /* Clock SignalTests */ = { isa = PBXGroup; children = ( + 4B85322922778E4200F26553 /* Comparative68000.hpp */, 4BD388872239E198002D14B5 /* 68000Tests.mm */, 4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */, 4BB2A9AE1E13367E001A5C23 /* CRCTests.mm */, diff --git a/OSBindings/Mac/Clock SignalTests/Comparative68000.hpp b/OSBindings/Mac/Clock SignalTests/Comparative68000.hpp new file mode 100644 index 000000000..dd8ed7e82 --- /dev/null +++ b/OSBindings/Mac/Clock SignalTests/Comparative68000.hpp @@ -0,0 +1,59 @@ +// +// Comparative68000.hpp +// Clock SignalTests +// +// Created by Thomas Harte on 29/04/2019. +// Copyright © 2019 Thomas Harte. All rights reserved. +// + +#ifndef Comparative68000_hpp +#define Comparative68000_hpp + +#include + +#include "68000.hpp" + +class ComparativeBusHandler: public CPU::MC68000::BusHandler { + public: + ComparativeBusHandler(const char *trace_name) { + trace = gzopen(trace_name, "rt"); + } + + ~ComparativeBusHandler() { + gzclose(trace); + } + + void will_perform(uint32_t address, uint16_t opcode) { + // Obtain the next line from the trace file. + char correct_state[300] = "\n"; + gzgets(trace, correct_state, sizeof(correct_state)); + ++line_count; + + // Generate state locally. + const auto state = 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\n", correct_state); + fprintf(stderr, "Bad: %s\n", local_state); + assert(false); + } + } + + virtual CPU::MC68000::ProcessorState get_state() = 0; + + private: + int line_count = 0; + gzFile trace; +}; + +#endif /* Comparative68000_hpp */ diff --git a/OSBindings/Mac/Clock SignalTests/QLTests.mm b/OSBindings/Mac/Clock SignalTests/QLTests.mm index 90de0365c..08b208311 100644 --- a/OSBindings/Mac/Clock SignalTests/QLTests.mm +++ b/OSBindings/Mac/Clock SignalTests/QLTests.mm @@ -17,53 +17,26 @@ #include #include "68000.hpp" +#include "Comparative68000.hpp" #include "CSROMFetcher.hpp" -class QL: public CPU::MC68000::BusHandler { +class QL: public ComparativeBusHandler { public: - QL(const std::vector &rom, const char *trace_name) : m68000_(*this) { + QL(const std::vector &rom, const char *trace_name) : ComparativeBusHandler(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] = "\n"; - 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\n", correct_state); - fprintf(stderr, "Bad: %s\n", local_state); - assert(false); - } + CPU::MC68000::ProcessorState get_state() override { + return m68000_.get_state(); } HalfCycles perform_bus_operation(const CPU::MC68000::Microcycle &cycle, int is_supervisor) { @@ -115,9 +88,6 @@ class QL: public CPU::MC68000::BusHandler { std::vector rom_; std::array ram_; - - int line_count = 0; - gzFile trace; }; @interface QLTests : XCTestCase diff --git a/Processors/68000/Implementation/68000Implementation.hpp b/Processors/68000/Implementation/68000Implementation.hpp index 56fdef9ab..930932768 100644 --- a/Processors/68000/Implementation/68000Implementation.hpp +++ b/Processors/68000/Implementation/68000Implementation.hpp @@ -149,10 +149,10 @@ template void Proces active_micro_op_ = active_program_->micro_operations; } else { active_program_ = nullptr; - active_micro_op_ = exception_micro_ops_; // TODO. + active_micro_op_ = exception_micro_ops_; - // The vector used dependds on whether this is a vanilla unrecognised instruction, or - // one on the A or F lines. + // The vector used depends on whether this is a vanilla unrecognised instruction, + // or one on the A or F lines. switch(decoded_instruction_ >> 12) { default: populate_trap_steps(get_status(), 4); break; case 0xa: populate_trap_steps(get_status(), 10); break; diff --git a/Processors/68000/Implementation/68000Storage.cpp b/Processors/68000/Implementation/68000Storage.cpp index 56d052f1a..22f652a37 100644 --- a/Processors/68000/Implementation/68000Storage.cpp +++ b/Processors/68000/Implementation/68000Storage.cpp @@ -3497,6 +3497,11 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() { // Target addresses and values will be filled in by TRAP/illegal too. const size_t trap_offset = constructor.assemble_program("r nw nw nW nV nv np np", { &precomputed_addresses_[0], &precomputed_addresses_[1], &precomputed_addresses_[2] }); + // Chuck in the proper micro-ops for handling an exception. + const auto exception_offset = all_micro_ops_.size(); + all_micro_ops_.emplace_back(ProcessorBase::MicroOp::Action::None); + all_micro_ops_.emplace_back(); + // Install operations. constructor.install_instructions(); @@ -3535,6 +3540,10 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() { steps[4].microcycle.value = steps[5].microcycle.value = &program_counter_.halves.low; } + // Complete linkage of the exception micro program. + exception_micro_ops_ = &all_micro_ops_[exception_offset]; + exception_micro_ops_->bus_program = trap_steps_; + // Set initial state. active_step_ = reset_bus_steps_; effective_address_[0] = 0;