mirror of
https://github.com/TomHarte/CLK.git
synced 2024-07-24 12:29:06 +00:00
Randomise all parts of memory other than the opcode.
This commit is contained in:
parent
079c3fd263
commit
dd0a7533ab
@ -13,9 +13,42 @@
|
|||||||
#include "68000Mk2.hpp"
|
#include "68000Mk2.hpp"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
struct RandomStore {
|
||||||
|
using CollectionT = std::unordered_map<uint32_t, std::pair<uint8_t, uint8_t>>;
|
||||||
|
CollectionT values;
|
||||||
|
|
||||||
|
void flag(uint32_t address, uint8_t participant) {
|
||||||
|
values[address].first |= participant;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has(uint32_t address, uint8_t participant) {
|
||||||
|
auto entry = values.find(address);
|
||||||
|
if(entry == values.end()) return false;
|
||||||
|
return entry->second.first & participant;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t value(uint32_t address, uint8_t participant) {
|
||||||
|
auto entry = values.find(address);
|
||||||
|
if(entry != values.end()) {
|
||||||
|
entry->second.first |= participant;
|
||||||
|
return entry->second.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t value = uint8_t(rand() >> 8);
|
||||||
|
values[address] = std::make_pair(participant, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
values.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
struct Transaction {
|
struct Transaction {
|
||||||
HalfCycles timestamp;
|
HalfCycles timestamp;
|
||||||
uint8_t function_code = 0;
|
uint8_t function_code = 0;
|
||||||
@ -25,8 +58,8 @@ struct Transaction {
|
|||||||
bool data_strobe = false;
|
bool data_strobe = false;
|
||||||
|
|
||||||
bool operator !=(const Transaction &rhs) const {
|
bool operator !=(const Transaction &rhs) const {
|
||||||
if(timestamp != rhs.timestamp) return true;
|
// if(timestamp != rhs.timestamp) return true;
|
||||||
if(function_code != rhs.function_code) return true;
|
// if(function_code != rhs.function_code) return true;
|
||||||
if(address != rhs.address) return true;
|
if(address != rhs.address) return true;
|
||||||
if(value != rhs.value) return true;
|
if(value != rhs.value) return true;
|
||||||
if(address_strobe != rhs.address_strobe) return true;
|
if(address_strobe != rhs.address_strobe) return true;
|
||||||
@ -48,6 +81,8 @@ struct Transaction {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct BusHandler {
|
struct BusHandler {
|
||||||
|
BusHandler(RandomStore &_store, uint8_t _participant) : store(_store), participant(_participant) {}
|
||||||
|
|
||||||
template <typename Microcycle> HalfCycles perform_bus_operation(const Microcycle &cycle, bool is_supervisor) {
|
template <typename Microcycle> HalfCycles perform_bus_operation(const Microcycle &cycle, bool is_supervisor) {
|
||||||
Transaction transaction;
|
Transaction transaction;
|
||||||
|
|
||||||
@ -66,18 +101,26 @@ struct BusHandler {
|
|||||||
|
|
||||||
time += cycle.length;
|
time += cycle.length;
|
||||||
|
|
||||||
// TODO: generate a random value if this is a read from an address not yet written to;
|
|
||||||
// use a shared store in order to ensure that both devices get the same random values.
|
|
||||||
|
|
||||||
// Do the operation...
|
// Do the operation...
|
||||||
const uint32_t address = cycle.address ? (*cycle.address & 0xffff'ff) : 0;
|
const uint32_t address = cycle.address ? (*cycle.address & 0xffff'ff) : 0;
|
||||||
switch(cycle.operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read)) {
|
switch(cycle.operation & (Microcycle::SelectWord | Microcycle::SelectByte | Microcycle::Read)) {
|
||||||
default: break;
|
default: break;
|
||||||
|
|
||||||
case Microcycle::SelectWord | Microcycle::Read:
|
case Microcycle::SelectWord | Microcycle::Read:
|
||||||
|
if(!store.has(address, participant)) {
|
||||||
|
ram[address] = store.value(address, participant);
|
||||||
|
}
|
||||||
|
if(!store.has(address+1, participant)) {
|
||||||
|
ram[address+1] = store.value(address+1, participant);
|
||||||
|
}
|
||||||
|
|
||||||
cycle.set_value16((ram[address] << 8) | ram[address + 1]);
|
cycle.set_value16((ram[address] << 8) | ram[address + 1]);
|
||||||
break;
|
break;
|
||||||
case Microcycle::SelectByte | Microcycle::Read:
|
case Microcycle::SelectByte | Microcycle::Read:
|
||||||
|
if(!store.has(address, participant)) {
|
||||||
|
ram[address] = store.value(address, participant);
|
||||||
|
}
|
||||||
|
|
||||||
if(address & 1) {
|
if(address & 1) {
|
||||||
cycle.set_value8_low(ram[address]);
|
cycle.set_value8_low(ram[address]);
|
||||||
} else {
|
} else {
|
||||||
@ -87,9 +130,12 @@ struct BusHandler {
|
|||||||
case Microcycle::SelectWord:
|
case Microcycle::SelectWord:
|
||||||
ram[address] = cycle.value8_high();
|
ram[address] = cycle.value8_high();
|
||||||
ram[address+1] = cycle.value8_low();
|
ram[address+1] = cycle.value8_low();
|
||||||
|
store.flag(address, participant);
|
||||||
|
store.flag(address+1, participant);
|
||||||
break;
|
break;
|
||||||
case Microcycle::SelectByte:
|
case Microcycle::SelectByte:
|
||||||
ram[address] = (address & 1) ? cycle.value8_low() : cycle.value8_high();
|
ram[address] = (address & 1) ? cycle.value8_low() : cycle.value8_high();
|
||||||
|
store.flag(address, participant);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,21 +176,29 @@ struct BusHandler {
|
|||||||
void set_default_vectors() {
|
void set_default_vectors() {
|
||||||
// Establish that all exception vectors point to 1024-byte blocks of memory.
|
// Establish that all exception vectors point to 1024-byte blocks of memory.
|
||||||
for(int c = 0; c < 256; c++) {
|
for(int c = 0; c < 256; c++) {
|
||||||
const uint32_t target = (c + 1) << 10;
|
const uint32_t target = (c + 2) << 10;
|
||||||
ram[(c << 2) + 0] = uint8_t(target >> 24);
|
const uint32_t address = c << 2;
|
||||||
ram[(c << 2) + 1] = uint8_t(target >> 16);
|
ram[address + 0] = uint8_t(target >> 24);
|
||||||
ram[(c << 2) + 2] = uint8_t(target >> 8);
|
ram[address + 1] = uint8_t(target >> 16);
|
||||||
ram[(c << 2) + 3] = uint8_t(target >> 0);
|
ram[address + 2] = uint8_t(target >> 8);
|
||||||
|
ram[address + 3] = uint8_t(target >> 0);
|
||||||
|
|
||||||
|
store.flag(address+0, participant);
|
||||||
|
store.flag(address+1, participant);
|
||||||
|
store.flag(address+2, participant);
|
||||||
|
store.flag(address+3, participant);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RandomStore &store;
|
||||||
|
const uint8_t participant;
|
||||||
};
|
};
|
||||||
|
|
||||||
using OldProcessor = CPU::MC68000::Processor<BusHandler, true>;
|
using OldProcessor = CPU::MC68000::Processor<BusHandler, true>;
|
||||||
using NewProcessor = CPU::MC68000Mk2::Processor<BusHandler, true, true>;
|
using NewProcessor = CPU::MC68000Mk2::Processor<BusHandler, true, true>;
|
||||||
|
|
||||||
template <typename M68000> struct Tester {
|
template <typename M68000> struct Tester {
|
||||||
Tester() : processor(bus_handler) {
|
Tester(RandomStore &store, uint8_t participant) : bus_handler(store, participant), processor(bus_handler) {}
|
||||||
}
|
|
||||||
|
|
||||||
void advance(int cycles, HalfCycles time_cutoff) {
|
void advance(int cycles, HalfCycles time_cutoff) {
|
||||||
bus_handler.time_cutoff = time_cutoff;
|
bus_handler.time_cutoff = time_cutoff;
|
||||||
@ -155,11 +209,16 @@ template <typename M68000> struct Tester {
|
|||||||
bus_handler.transactions.clear();
|
bus_handler.transactions.clear();
|
||||||
bus_handler.set_default_vectors();
|
bus_handler.set_default_vectors();
|
||||||
|
|
||||||
bus_handler.ram[(2 << 10) + 0] = uint8_t(opcode >> 8);
|
const uint32_t address = 3 << 10;
|
||||||
bus_handler.ram[(2 << 10) + 1] = uint8_t(opcode >> 0);
|
bus_handler.ram[address + 0] = uint8_t(opcode >> 8);
|
||||||
|
bus_handler.ram[address + 1] = uint8_t(opcode >> 0);
|
||||||
|
bus_handler.store.flag(address, bus_handler.participant);
|
||||||
|
bus_handler.store.flag(address+1, bus_handler.participant);
|
||||||
|
|
||||||
bus_handler.transaction_delay = 12; // i.e. ignore the first eight transactions,
|
bus_handler.transaction_delay = 8; // i.e. ignore the first eight transactions,
|
||||||
// which will just be the reset procedure.
|
// which will just be the vector fetch part of
|
||||||
|
// the reset procedure. Instead assume logging
|
||||||
|
// at the initial prefetch fill.
|
||||||
bus_handler.time = HalfCycles(0);
|
bus_handler.time = HalfCycles(0);
|
||||||
|
|
||||||
processor.reset();
|
processor.reset();
|
||||||
@ -174,14 +233,17 @@ template <typename M68000> struct Tester {
|
|||||||
@interface M68000OldVsNewTests : XCTestCase
|
@interface M68000OldVsNewTests : XCTestCase
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation M68000OldVsNewTests {
|
@implementation M68000OldVsNewTests
|
||||||
}
|
|
||||||
|
|
||||||
- (void)testOldVsNew {
|
- (void)testOldVsNew {
|
||||||
auto oldTester = std::make_unique<Tester<OldProcessor>>();
|
RandomStore random_store;
|
||||||
auto newTester = std::make_unique<Tester<NewProcessor>>();
|
auto oldTester = std::make_unique<Tester<OldProcessor>>(random_store, 0x01);
|
||||||
|
auto newTester = std::make_unique<Tester<NewProcessor>>(random_store, 0x02);
|
||||||
InstructionSet::M68k::Predecoder<InstructionSet::M68k::Model::M68000> decoder;
|
InstructionSet::M68k::Predecoder<InstructionSet::M68k::Model::M68000> decoder;
|
||||||
|
|
||||||
|
// Use a fixed seed to guarantee continuity across repeated runs.
|
||||||
|
srand(68000);
|
||||||
|
|
||||||
for(int c = 0; c < 65536; c++) {
|
for(int c = 0; c < 65536; c++) {
|
||||||
// Test only defined opcodes.
|
// Test only defined opcodes.
|
||||||
const auto instruction = decoder.decode(uint16_t(c));
|
const auto instruction = decoder.decode(uint16_t(c));
|
||||||
@ -191,6 +253,7 @@ template <typename M68000> struct Tester {
|
|||||||
|
|
||||||
// Test each 1000 times.
|
// Test each 1000 times.
|
||||||
for(int test = 0; test < 1000; test++) {
|
for(int test = 0; test < 1000; test++) {
|
||||||
|
random_store.clear();
|
||||||
newTester->reset_with_opcode(c);
|
newTester->reset_with_opcode(c);
|
||||||
oldTester->reset_with_opcode(c);
|
oldTester->reset_with_opcode(c);
|
||||||
|
|
||||||
@ -214,8 +277,9 @@ template <typename M68000> struct Tester {
|
|||||||
++repeatIt;
|
++repeatIt;
|
||||||
}
|
}
|
||||||
printf("---\n");
|
printf("---\n");
|
||||||
printf("< "); oldIt->print();
|
printf("o: "); oldIt->print();
|
||||||
printf("> "); newIt->print();
|
printf("n: "); newIt->print();
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user