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

Establishes that the 48/128kb contention patterns can be derived from my partial machine cycles alone.

This commit is contained in:
Thomas Harte 2021-04-14 20:15:40 -04:00
parent 325e2b3941
commit a1511f9600

View File

@ -18,6 +18,12 @@ static constexpr uint16_t initial_bc_de_hl = 0xabcd;
static constexpr uint16_t initial_ix_iy = 0x3412; static constexpr uint16_t initial_ix_iy = 0x3412;
static constexpr uint16_t initial_sp = 0x6800; static constexpr uint16_t initial_sp = 0x6800;
struct ContentionCheck {
uint16_t address;
int length;
bool is_io = false;
};
struct CapturingZ80: public CPU::Z80::BusHandler { struct CapturingZ80: public CPU::Z80::BusHandler {
template <typename Collection> CapturingZ80(const Collection &code) : z80_(*this) { template <typename Collection> CapturingZ80(const Collection &code) : z80_(*this) {
@ -29,6 +35,7 @@ struct CapturingZ80: public CPU::Z80::BusHandler {
// purge them from the record. // purge them from the record.
run_for(3); run_for(3);
bus_records_.clear(); bus_records_.clear();
contentions_48k_.clear();
// Set the flags so that if this is a conditional operation, it'll succeed. // Set the flags so that if this is a conditional operation, it'll succeed.
if((*code.begin())&0x8) { if((*code.begin())&0x8) {
@ -75,7 +82,9 @@ struct CapturingZ80: public CPU::Z80::BusHandler {
}; };
HalfCycles perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) { HalfCycles perform_machine_cycle(const CPU::Z80::PartialMachineCycle &cycle) {
// Log the activity. //
// Log the plain bus activity.
//
const uint8_t *const bus_state = cycle.bus_state(); const uint8_t *const bus_state = cycle.bus_state();
for(int c = 0; c < cycle.length.as<int>(); c++) { for(int c = 0; c < cycle.length.as<int>(); c++) {
bus_records_.emplace_back(); bus_records_.emplace_back();
@ -91,7 +100,57 @@ struct CapturingZ80: public CPU::Z80::BusHandler {
bus_records_.back().refresh = bus_state[c] & CPU::Z80::PartialMachineCycle::Line::RFSH; bus_records_.back().refresh = bus_state[c] & CPU::Z80::PartialMachineCycle::Line::RFSH;
} }
// Provide only reads. //
// Attempt to predict how the 48kb would contend this, based on machine cycle alone.
//
switch(cycle.operation) {
default: assert(false);
case CPU::Z80::PartialMachineCycle::ReadStart:
case CPU::Z80::PartialMachineCycle::WriteStart:
contentions_48k_.emplace_back();
contentions_48k_.back().address = *cycle.address;
contentions_48k_.back().length = 3;
break;
case CPU::Z80::PartialMachineCycle::ReadOpcodeStart:
contentions_48k_.emplace_back();
contentions_48k_.back().address = *cycle.address;
contentions_48k_.back().length = 4;
break;
case CPU::Z80::PartialMachineCycle::InputStart:
case CPU::Z80::PartialMachineCycle::OutputStart:
contentions_48k_.emplace_back();
contentions_48k_.back().address = *cycle.address;
contentions_48k_.back().length = 4;
contentions_48k_.back().is_io = true;
break;
case CPU::Z80::PartialMachineCycle::Refresh:
case CPU::Z80::PartialMachineCycle::Read:
case CPU::Z80::PartialMachineCycle::Write:
case CPU::Z80::PartialMachineCycle::ReadOpcode:
case CPU::Z80::PartialMachineCycle::Input:
case CPU::Z80::PartialMachineCycle::Output:
case CPU::Z80::PartialMachineCycle::InputWait:
case CPU::Z80::PartialMachineCycle::OutputWait:
// All already accounted for.
break;
case CPU::Z80::PartialMachineCycle::Internal:
for(int c = 0; c < cycle.length.cycles().as<int>(); c++) {
contentions_48k_.emplace_back();
contentions_48k_.back().address = *cycle.address;
contentions_48k_.back().length = 1;
}
break;
}
//
// Do the actual action: albeit, only reads.
//
if( if(
cycle.operation == CPU::Z80::PartialMachineCycle::Read || cycle.operation == CPU::Z80::PartialMachineCycle::Read ||
cycle.operation == CPU::Z80::PartialMachineCycle::ReadOpcode cycle.operation == CPU::Z80::PartialMachineCycle::ReadOpcode
@ -116,12 +175,17 @@ struct CapturingZ80: public CPU::Z80::BusHandler {
return cycle_records; return cycle_records;
} }
const std::vector<ContentionCheck> &contention_predictions_48k() const {
return contentions_48k_;
}
private: private:
CPU::Z80::Processor<CapturingZ80, false, false> z80_; CPU::Z80::Processor<CapturingZ80, false, false> z80_;
uint8_t ram_[65536]; uint8_t ram_[65536];
uint16_t code_length_ = 0; uint16_t code_length_ = 0;
std::vector<BusRecord> bus_records_; std::vector<BusRecord> bus_records_;
std::vector<ContentionCheck> contentions_48k_;
}; };
} }
@ -136,22 +200,18 @@ struct CapturingZ80: public CPU::Z80::BusHandler {
*/ */
@implementation Z80ContentionTests @implementation Z80ContentionTests
struct ContentionCheck { template <typename LHSCollectionT, typename RHSCollectionT>
uint16_t address; void compareExpectedContentions(LHSCollectionT lhs, RHSCollectionT rhs, const char *label)
int length; {
bool is_io = false; XCTAssertEqual(lhs.size(), rhs.size(), "[%s] found %lu contentions but expected %zu", label, lhs.size(), rhs.size());
};
- (void)compareExpectedContentions:(const std::initializer_list<ContentionCheck> &)contentions found:(const std::vector<ContentionCheck> &)found label:(const char *)label { auto contention = lhs.begin();
XCTAssertEqual(contentions.size(), found.size(), "[%s] found %lu contentions but expected %zu", label, found.size(), contentions.size()); auto found_contention = rhs.begin();
auto contention = contentions.begin(); while(contention != lhs.end() && found_contention != rhs.end()) {
auto found_contention = found.begin(); XCTAssertEqual(contention->address, found_contention->address, "[%s] mismatched address at step %zu; expected %04x but found %04x", label, contention - lhs.begin(), contention->address, found_contention->address);
XCTAssertEqual(contention->length, found_contention->length, "[%s] mismatched length at step %zu; expected %d but found %d", label, contention - lhs.begin(), contention->length, found_contention->length);
while(contention != contentions.end() && found_contention != found.end()) { XCTAssertEqual(contention->is_io, found_contention->is_io, "[%s] mismatched IO flag at step %zu; expected %d but found %d", label, contention - lhs.begin(), contention->is_io, found_contention->is_io);
XCTAssertEqual(contention->address, found_contention->address, "[%s] mismatched address at step %zu; expected %04x but found %04x", label, contention - contentions.begin(), contention->address, found_contention->address);
XCTAssertEqual(contention->length, found_contention->length, "[%s] mismatched length at step %zu; expected %d but found %d", label, contention - contentions.begin(), contention->length, found_contention->length);
XCTAssertEqual(contention->is_io, found_contention->is_io, "[%s] mismatched IO flag at step %zu; expected %d but found %d", label, contention - contentions.begin(), contention->is_io, found_contention->is_io);
if(contention->address != found_contention->address || contention->length != found_contention->length) { if(contention->address != found_contention->address || contention->length != found_contention->length) {
break; break;
@ -201,7 +261,8 @@ struct ContentionCheck {
found_contentions.back().length = count; found_contentions.back().length = count;
found_contentions.back().is_io = is_io; found_contentions.back().is_io = is_io;
[self compareExpectedContentions:contentions found:found_contentions label:"48kb"]; compareExpectedContentions(contentions, found_contentions, "48kb");
compareExpectedContentions(z80.contention_predictions_48k(), found_contentions, "48kb prediction");
} }
/*! /*!
@ -245,7 +306,7 @@ struct ContentionCheck {
found_contentions.back().length = count; found_contentions.back().length = count;
found_contentions.back().is_io = is_io; found_contentions.back().is_io = is_io;
[self compareExpectedContentions:contentions found:found_contentions label:"+3"]; compareExpectedContentions(contentions, found_contentions, "+3");
} }
// MARK: - Opcode tests. // MARK: - Opcode tests.