mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +00:00
Ensures intended 65816 exception behaviour.
i.e. the relevant micro-op sequence exists, and its operation isn't lost. Also sets the 65816 by default to jump straight into power-on, not to execute an instruction first. That shouldn't make a functional difference, but it makes debugging easier because it makes startup fully deterministic.
This commit is contained in:
parent
69509f6502
commit
99eba2f8ba
@ -48,11 +48,6 @@
|
|||||||
BlueprintName = "Clock SignalTests"
|
BlueprintName = "Clock SignalTests"
|
||||||
ReferencedContainer = "container:Clock Signal.xcodeproj">
|
ReferencedContainer = "container:Clock Signal.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
<SkippedTests>
|
|
||||||
<Test
|
|
||||||
Identifier = "ZexallTests">
|
|
||||||
</Test>
|
|
||||||
</SkippedTests>
|
|
||||||
</TestableReference>
|
</TestableReference>
|
||||||
<TestableReference
|
<TestableReference
|
||||||
skipped = "YES">
|
skipped = "YES">
|
||||||
|
@ -50,8 +50,10 @@ template <typename BusHandler, bool uses_ready_line> void Processor<BusHandler,
|
|||||||
// The exception program will determine the appropriate way to respond
|
// The exception program will determine the appropriate way to respond
|
||||||
// based on the pending exception if one exists; otherwise just do a
|
// based on the pending exception if one exists; otherwise just do a
|
||||||
// standard fetch-decode-execute.
|
// standard fetch-decode-execute.
|
||||||
const auto offset = instructions[selected_exceptions_ ? size_t(OperationSlot::Exception) : size_t(OperationSlot::FetchDecodeExecute)].program_offsets[0];
|
const size_t slot = size_t(selected_exceptions_ ? OperationSlot::Exception : OperationSlot::FetchDecodeExecute);
|
||||||
next_op_ = µ_ops_[offset];
|
active_instruction_ = &instructions[slot];
|
||||||
|
|
||||||
|
next_op_ = µ_ops_[active_instruction_->program_offsets[0]];
|
||||||
instruction_buffer_.clear();
|
instruction_buffer_.clear();
|
||||||
data_buffer_.clear();
|
data_buffer_.clear();
|
||||||
last_operation_pc_ = registers_.pc;
|
last_operation_pc_ = registers_.pc;
|
||||||
@ -954,6 +956,7 @@ void ProcessorBase::set_power_on(bool active) {
|
|||||||
pending_exceptions_ |= PowerOn;
|
pending_exceptions_ |= PowerOn;
|
||||||
} else {
|
} else {
|
||||||
pending_exceptions_ &= ~PowerOn;
|
pending_exceptions_ &= ~PowerOn;
|
||||||
|
selected_exceptions_ &= ~PowerOn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,8 @@ struct CPU::WDC65816::ProcessorStorageConstructor {
|
|||||||
|
|
||||||
typedef void (* Generator)(AccessType, bool, const std::function<void(MicroOp)>&);
|
typedef void (* Generator)(AccessType, bool, const std::function<void(MicroOp)>&);
|
||||||
using GeneratorKey = std::tuple<AccessType, Generator>;
|
using GeneratorKey = std::tuple<AccessType, Generator>;
|
||||||
std::map<GeneratorKey, std::pair<size_t, size_t>> installed_patterns;
|
using PatternTable = std::map<GeneratorKey, std::pair<size_t, size_t>>;
|
||||||
|
PatternTable installed_patterns;
|
||||||
|
|
||||||
int opcode = 0;
|
int opcode = 0;
|
||||||
enum class AccessMode {
|
enum class AccessMode {
|
||||||
@ -51,27 +52,60 @@ struct CPU::WDC65816::ProcessorStorageConstructor {
|
|||||||
Always8Bit,
|
Always8Bit,
|
||||||
Always16Bit
|
Always16Bit
|
||||||
};
|
};
|
||||||
|
|
||||||
void install(Generator generator, Operation operation, AccessMode access_mode = AccessMode::Mixed) {
|
void install(Generator generator, Operation operation, AccessMode access_mode = AccessMode::Mixed) {
|
||||||
// Determine the access type implied by this operation.
|
// Determine the access type implied by this operation.
|
||||||
const AccessType access_type = access_type_for_operation(operation);
|
const AccessType access_type = access_type_for_operation(operation);
|
||||||
|
|
||||||
|
// Install the bus pattern.
|
||||||
|
const auto map_entry = install(generator, access_type);
|
||||||
|
const size_t micro_op_location_8 = map_entry->second.first;
|
||||||
|
const size_t micro_op_location_16 = map_entry->second.second;
|
||||||
|
|
||||||
|
// Fill in the proper table entries and increment the opcode pointer.
|
||||||
|
storage_.instructions[opcode].program_offsets[0] = (access_mode == AccessMode::Always8Bit) ? uint16_t(micro_op_location_8) : uint16_t(micro_op_location_16);
|
||||||
|
storage_.instructions[opcode].program_offsets[1] = (access_mode == AccessMode::Always16Bit) ? uint16_t(micro_op_location_16) : uint16_t(micro_op_location_8);
|
||||||
|
storage_.instructions[opcode].operation = operation;
|
||||||
|
|
||||||
|
++opcode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_exception_generator(Generator generator) {
|
||||||
|
const auto map_entry = install(generator);
|
||||||
|
storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].program_offsets[0] =
|
||||||
|
storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].program_offsets[1] = uint16_t(map_entry->second.first);
|
||||||
|
storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].operation = JMPind;
|
||||||
|
}
|
||||||
|
|
||||||
|
void install_fetch_decode_execute() {
|
||||||
|
storage_.instructions[size_t(ProcessorStorage::OperationSlot::FetchDecodeExecute)].program_offsets[0] =
|
||||||
|
storage_.instructions[size_t(ProcessorStorage::OperationSlot::FetchDecodeExecute)].program_offsets[1] = uint16_t(storage_.micro_ops_.size());
|
||||||
|
storage_.micro_ops_.push_back(CycleFetchOpcode);
|
||||||
|
storage_.micro_ops_.push_back(OperationDecode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
PatternTable::iterator install(Generator generator, AccessType access_type = AccessType::Read) {
|
||||||
// Check whether this access type + addressing mode generator has already been generated.
|
// Check whether this access type + addressing mode generator has already been generated.
|
||||||
const auto key = std::make_pair(access_type, generator);
|
const auto key = std::make_pair(access_type, generator);
|
||||||
const auto map_entry = installed_patterns.find(key);
|
const auto map_entry = installed_patterns.find(key);
|
||||||
size_t micro_op_location_8, micro_op_location_16;
|
|
||||||
|
|
||||||
// If it wasn't found, generate it now in both 8- and 16-bit variants.
|
// If it wasn't found, generate it now in both 8- and 16-bit variants.
|
||||||
// Otherwise, get the location of the existing entries.
|
// Otherwise, get the location of the existing entries.
|
||||||
if(map_entry == installed_patterns.end()) {
|
if(map_entry != installed_patterns.end()) {
|
||||||
|
return map_entry;
|
||||||
|
}
|
||||||
|
|
||||||
// Generate 8-bit steps.
|
// Generate 8-bit steps.
|
||||||
micro_op_location_8 = storage_.micro_ops_.size();
|
const size_t micro_op_location_8 = storage_.micro_ops_.size();
|
||||||
(*generator)(access_type, true, [this] (MicroOp op) {
|
(*generator)(access_type, true, [this] (MicroOp op) {
|
||||||
this->storage_.micro_ops_.push_back(op);
|
this->storage_.micro_ops_.push_back(op);
|
||||||
});
|
});
|
||||||
storage_.micro_ops_.push_back(OperationMoveToNextProgram);
|
storage_.micro_ops_.push_back(OperationMoveToNextProgram);
|
||||||
|
|
||||||
// Generate 16-bit steps.
|
// Generate 16-bit steps.
|
||||||
micro_op_location_16 = storage_.micro_ops_.size();
|
size_t micro_op_location_16 = storage_.micro_ops_.size();
|
||||||
(*generator)(access_type, false, [this] (MicroOp op) {
|
(*generator)(access_type, false, [this] (MicroOp op) {
|
||||||
this->storage_.micro_ops_.push_back(op);
|
this->storage_.micro_ops_.push_back(op);
|
||||||
});
|
});
|
||||||
@ -95,34 +129,11 @@ struct CPU::WDC65816::ProcessorStorageConstructor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Insert into the map.
|
// Insert into the map.
|
||||||
installed_patterns[key] = std::make_pair(micro_op_location_8, micro_op_location_16);
|
auto [iterator, _] = installed_patterns.insert(std::make_pair(key, std::make_pair(micro_op_location_8, micro_op_location_16)));
|
||||||
} else {
|
return iterator;
|
||||||
micro_op_location_8 = map_entry->second.first;
|
|
||||||
micro_op_location_16 = map_entry->second.second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill in the proper table entries and increment the opcode pointer.
|
public:
|
||||||
storage_.instructions[opcode].program_offsets[0] = (access_mode == AccessMode::Always8Bit) ? uint16_t(micro_op_location_8) : uint16_t(micro_op_location_16);
|
|
||||||
storage_.instructions[opcode].program_offsets[1] = (access_mode == AccessMode::Always16Bit) ? uint16_t(micro_op_location_16) : uint16_t(micro_op_location_8);
|
|
||||||
storage_.instructions[opcode].operation = operation;
|
|
||||||
|
|
||||||
++opcode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_exception_generator(Generator generator) {
|
|
||||||
const auto key = std::make_pair(AccessType::Read, generator);
|
|
||||||
const auto map_entry = installed_patterns.find(key);
|
|
||||||
storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].program_offsets[0] =
|
|
||||||
storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].program_offsets[1] = uint16_t(map_entry->second.first);
|
|
||||||
storage_.instructions[size_t(ProcessorStorage::OperationSlot::Exception)].operation = JMPind;
|
|
||||||
}
|
|
||||||
|
|
||||||
void install_fetch_decode_execute() {
|
|
||||||
storage_.instructions[size_t(ProcessorStorage::OperationSlot::FetchDecodeExecute)].program_offsets[0] =
|
|
||||||
storage_.instructions[size_t(ProcessorStorage::OperationSlot::FetchDecodeExecute)].program_offsets[1] = uint16_t(storage_.micro_ops_.size());
|
|
||||||
storage_.micro_ops_.push_back(CycleFetchOpcode);
|
|
||||||
storage_.micro_ops_.push_back(OperationDecode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Code below is structured to ease translation from Table 5-7 of the 2018
|
Code below is structured to ease translation from Table 5-7 of the 2018
|
||||||
|
@ -292,8 +292,10 @@ struct ProcessorStorage {
|
|||||||
static constexpr int IRQ = Flag::Interrupt; // This makes masking a lot easier later on; this is 1 << 2.
|
static constexpr int IRQ = Flag::Interrupt; // This makes masking a lot easier later on; this is 1 << 2.
|
||||||
static constexpr int NMI = 1 << 3;
|
static constexpr int NMI = 1 << 3;
|
||||||
static constexpr int Abort = 1 << 4;
|
static constexpr int Abort = 1 << 4;
|
||||||
int pending_exceptions_ = PowerOn; // By default.
|
|
||||||
int selected_exceptions_ = 0;
|
static constexpr int default_exceptions = PowerOn;
|
||||||
|
int pending_exceptions_ = default_exceptions;
|
||||||
|
int selected_exceptions_ = default_exceptions;
|
||||||
|
|
||||||
bool ready_line_ = false;
|
bool ready_line_ = false;
|
||||||
bool memory_lock_ = false;
|
bool memory_lock_ = false;
|
||||||
|
Loading…
Reference in New Issue
Block a user