mirror of
https://github.com/TomHarte/CLK.git
synced 2024-07-09 06:29:33 +00:00
Factors out the [unit testing] stuff of being a trace-checking 68000 bus handler.
This commit is contained in:
parent
407643c575
commit
c466b6f9e7
@ -963,6 +963,7 @@
|
|||||||
4B83348E1F5DBA6E0097E338 /* 6522Storage.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = 6522Storage.hpp; path = Implementation/6522Storage.hpp; sourceTree = "<group>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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 */ = {
|
4BB73EB51B587A5100552FC2 /* Clock SignalTests */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
4B85322922778E4200F26553 /* Comparative68000.hpp */,
|
||||||
4BD388872239E198002D14B5 /* 68000Tests.mm */,
|
4BD388872239E198002D14B5 /* 68000Tests.mm */,
|
||||||
4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */,
|
4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */,
|
||||||
4BB2A9AE1E13367E001A5C23 /* CRCTests.mm */,
|
4BB2A9AE1E13367E001A5C23 /* CRCTests.mm */,
|
||||||
|
59
OSBindings/Mac/Clock SignalTests/Comparative68000.hpp
Normal file
59
OSBindings/Mac/Clock SignalTests/Comparative68000.hpp
Normal 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 */
|
@ -17,53 +17,26 @@
|
|||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
#include "68000.hpp"
|
#include "68000.hpp"
|
||||||
|
#include "Comparative68000.hpp"
|
||||||
#include "CSROMFetcher.hpp"
|
#include "CSROMFetcher.hpp"
|
||||||
|
|
||||||
class QL: public CPU::MC68000::BusHandler {
|
class QL: public ComparativeBusHandler {
|
||||||
public:
|
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));
|
assert(!(rom.size() & 1));
|
||||||
rom_.resize(rom.size() / 2);
|
rom_.resize(rom.size() / 2);
|
||||||
|
|
||||||
for(size_t c = 0; c < rom_.size(); ++c) {
|
for(size_t c = 0; c < rom_.size(); ++c) {
|
||||||
rom_[c] = (rom[c << 1] << 8) | rom[(c << 1) + 1];
|
rom_[c] = (rom[c << 1] << 8) | rom[(c << 1) + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
trace = gzopen(trace_name, "rt");
|
|
||||||
}
|
|
||||||
|
|
||||||
~QL() {
|
|
||||||
gzclose(trace);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void run_for(HalfCycles cycles) {
|
void run_for(HalfCycles cycles) {
|
||||||
m68000_.run_for(cycles);
|
m68000_.run_for(cycles);
|
||||||
}
|
}
|
||||||
|
|
||||||
void will_perform(uint32_t address, uint16_t opcode) {
|
CPU::MC68000::ProcessorState get_state() override {
|
||||||
// Obtain the next line from the trace file.
|
return m68000_.get_state();
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HalfCycles perform_bus_operation(const CPU::MC68000::Microcycle &cycle, int is_supervisor) {
|
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::vector<uint16_t> rom_;
|
||||||
std::array<uint16_t, 64*1024> ram_;
|
std::array<uint16_t, 64*1024> ram_;
|
||||||
|
|
||||||
int line_count = 0;
|
|
||||||
gzFile trace;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@interface QLTests : XCTestCase
|
@interface QLTests : XCTestCase
|
||||||
|
@ -149,10 +149,10 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
|||||||
active_micro_op_ = active_program_->micro_operations;
|
active_micro_op_ = active_program_->micro_operations;
|
||||||
} else {
|
} else {
|
||||||
active_program_ = nullptr;
|
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
|
// The vector used depends on whether this is a vanilla unrecognised instruction,
|
||||||
// one on the A or F lines.
|
// or one on the A or F lines.
|
||||||
switch(decoded_instruction_ >> 12) {
|
switch(decoded_instruction_ >> 12) {
|
||||||
default: populate_trap_steps(get_status(), 4); break;
|
default: populate_trap_steps(get_status(), 4); break;
|
||||||
case 0xa: populate_trap_steps(get_status(), 10); break;
|
case 0xa: populate_trap_steps(get_status(), 10); break;
|
||||||
|
@ -3497,6 +3497,11 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() {
|
|||||||
// Target addresses and values will be filled in by TRAP/illegal too.
|
// 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] });
|
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.
|
// Install operations.
|
||||||
constructor.install_instructions();
|
constructor.install_instructions();
|
||||||
|
|
||||||
@ -3535,6 +3540,10 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() {
|
|||||||
steps[4].microcycle.value = steps[5].microcycle.value = &program_counter_.halves.low;
|
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.
|
// Set initial state.
|
||||||
active_step_ = reset_bus_steps_;
|
active_step_ = reset_bus_steps_;
|
||||||
effective_address_[0] = 0;
|
effective_address_[0] = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user