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

Factors out the [unit testing] stuff of being a trace-checking 68000 bus handler.

This commit is contained in:
Thomas Harte 2019-04-29 16:11:01 -04:00
parent 407643c575
commit c466b6f9e7
5 changed files with 78 additions and 38 deletions

View File

@ -963,6 +963,7 @@
4B83348E1F5DBA6E0097E338 /* 6522Storage.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = 6522Storage.hpp; path = Implementation/6522Storage.hpp; sourceTree = "<group>"; };
4B8334911F5E24FF0097E338 /* C1540Base.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = C1540Base.hpp; path = Implementation/C1540Base.hpp; sourceTree = "<group>"; };
4B8334941F5E25B60097E338 /* C1540.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = C1540.cpp; path = Implementation/C1540.cpp; sourceTree = "<group>"; };
4B85322922778E4200F26553 /* Comparative68000.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Comparative68000.hpp; sourceTree = "<group>"; };
4B86E2591F8C628F006FAA45 /* Keyboard.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Keyboard.cpp; sourceTree = "<group>"; };
4B86E25A1F8C628F006FAA45 /* Keyboard.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Keyboard.hpp; sourceTree = "<group>"; };
4B8805EE1DCFC99C003085B1 /* Acorn.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Acorn.cpp; path = Parsers/Acorn.cpp; sourceTree = "<group>"; };
@ -2842,6 +2843,7 @@
4BB73EB51B587A5100552FC2 /* Clock SignalTests */ = {
isa = PBXGroup;
children = (
4B85322922778E4200F26553 /* Comparative68000.hpp */,
4BD388872239E198002D14B5 /* 68000Tests.mm */,
4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */,
4BB2A9AE1E13367E001A5C23 /* CRCTests.mm */,

View File

@ -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 <zlib.h>
#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 */

View File

@ -17,53 +17,26 @@
#include <zlib.h>
#include "68000.hpp"
#include "Comparative68000.hpp"
#include "CSROMFetcher.hpp"
class QL: public CPU::MC68000::BusHandler {
class QL: public ComparativeBusHandler {
public:
QL(const std::vector<uint8_t> &rom, const char *trace_name) : m68000_(*this) {
QL(const std::vector<uint8_t> &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<uint16_t> rom_;
std::array<uint16_t, 64*1024> ram_;
int line_count = 0;
gzFile trace;
};
@interface QLTests : XCTestCase

View File

@ -149,10 +149,10 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> 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;

View File

@ -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;