1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-02-10 23:31:24 +00:00

I'm still dithering on address management, but this seeks fully to implement ABCD and SUBD bus programs.

This commit is contained in:
Thomas Harte 2019-03-13 21:08:13 -04:00
parent 57898ed6dd
commit bb04981280
3 changed files with 102 additions and 12 deletions

View File

@ -22,6 +22,21 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
case MicroOp::Action::PerformOperation: case MicroOp::Action::PerformOperation:
std::cerr << "Should do something with program operation " << int(active_program_->operation) << std::endl; std::cerr << "Should do something with program operation " << int(active_program_->operation) << std::endl;
break; break;
case MicroOp::Action::PredecrementSourceAndDestination1:
-- active_program_->source->full;
-- active_program_->destination->full;
break;
case MicroOp::Action::PredecrementSourceAndDestination1:
active_program_->source->full -= 2;
active_program_->destination->full -= 2;
break;
case MicroOp::Action::PredecrementSourceAndDestination1:
active_program_->source->full -= 4;
active_program_->destination->full -= 4;
break;
} }
active_step_ = active_micro_op_->bus_program; active_step_ = active_micro_op_->bus_program;
} }

View File

@ -31,8 +31,11 @@ ProcessorStorage::ProcessorStorage() {
is_supervisor_ = 1; is_supervisor_ = 1;
} }
size_t ProcessorStorage::assemble_program(const char *access_pattern) { size_t ProcessorStorage::assemble_program(const char *access_pattern, const std::vector<uint32_t *> &addresses, int data_mask) {
const size_t start = all_bus_steps_.size(); const size_t start = all_bus_steps_.size();
auto address_iterator = addresses.begin();
RegisterPair32 *scratch_data_read = bus_data_;
RegisterPair32 *scratch_data_write = bus_data_;
// Parse the access pattern to build microcycles. // Parse the access pattern to build microcycles.
while(*access_pattern) { while(*access_pattern) {
@ -105,6 +108,28 @@ size_t ProcessorStorage::assemble_program(const char *access_pattern) {
access_pattern += 2; access_pattern += 2;
break; break;
case 'r': // Fetch LSW (or only) word (/byte)
case 'R': // Fetch MSW word
case 'w': // Store LSW (or only) word (/byte)
case 'W': { // Store MSW word
const bool is_read = tolower(access_pattern[1]) == 'r';
RegisterPair32 **scratch_data = is_read ? &scratch_data_read : &scratch_data_write;
step.microcycle.length = HalfCycles(5);
step.microcycle.operation = Microcycle::Address | (is_read ? Microcycle::ReadWrite : 0);
step.microcycle.address = *address_iterator;
step.microcycle.value = isupper(access_pattern[1]) ? &(*scratch_data)->halves.high : &(*scratch_data)->halves.low;
all_bus_steps_.push_back(step);
step.microcycle.length = HalfCycles(3);
step.microcycle.operation |= data_mask;
all_bus_steps_.push_back(step);
++address_iterator;
if(!isupper(access_pattern[1])) ++(*scratch_data);
access_pattern += 2;
} break;
} }
break; break;
@ -128,6 +153,14 @@ ProcessorStorage::BusStepCollection ProcessorStorage::assemble_standard_bus_step
collection.four_step_Dn = assemble_program("np"); collection.four_step_Dn = assemble_program("np");
collection.six_step_Dn = assemble_program("np n"); collection.six_step_Dn = assemble_program("np n");
for(int s = 0; s < 8; ++s) {
for(int d = 0; d < 8; ++d) {
collection.double_predec_byte[s][d] = assemble_program("n nr nr np nw", { &address_[s].full, &address_[d].full, &address_[d].full }, Microcycle::LowerData);
collection.double_predec_word[s][d] = assemble_program("n nr nr np nw", { &address_[s].full, &address_[d].full, &address_[d].full });
// collection.double_predec_long[s][d] = assemble_program("n nr nR nr nR nw np nW", { &address_[s].full, &address_[d].full, &address_[d].full });
}
}
return collection; return collection;
} }
@ -183,22 +216,45 @@ void ProcessorStorage::install_instructions(const BusStepCollection &bus_step_co
{0xff00, 0x0600, Operation::ADD, Decoder::DataSizeModeQuick}, // 4-11 (p115) {0xff00, 0x0600, Operation::ADD, Decoder::DataSizeModeQuick}, // 4-11 (p115)
}; };
std::vector<size_t> micro_op_pointers(65536, std::numeric_limits<size_t>::max());
// Perform a linear search of the mappings above for this instruction. // Perform a linear search of the mappings above for this instruction.
for(int instruction = 0; instruction < 65536; ++instruction) { for(size_t instruction = 0; instruction < 65536; ++instruction) {
for(const auto &mapping: mappings) { for(const auto &mapping: mappings) {
if((instruction & mapping.mask) == mapping.value) { if((instruction & mapping.mask) == mapping.value) {
// Install the operation and make a note of where micro-ops begin.
instructions[instruction].operation = mapping.operation;
micro_op_pointers[instruction] = all_micro_ops_.size();
switch(mapping.decoder) { switch(mapping.decoder) {
case Decoder::Decimal: { case Decoder::Decimal: {
const int destination = (instruction >> 8) & 7; const int destination = (instruction >> 8) & 7;
const int source = instruction & 7; const int source = instruction & 7;
all_micro_ops_.emplace_back();
if(instruction & 8) { if(instruction & 8) {
std::cout << "Address to address (both predecrement) from " << source << " to " << destination << std::endl; // Install source and destination.
instructions[instruction].source = &bus_data_[0];
instructions[instruction].destination = &bus_data_[1];
all_micro_ops_.emplace_back();
all_micro_ops_.back().bus_program = &all_bus_steps_[bus_step_collection.double_predec_byte[source][destination]];
all_micro_ops_.back().action = MicroOp::Action::PredecrementSourceAndDestination1;
all_micro_ops_.emplace_back();
all_micro_ops_.back().action = MicroOp::Action::PerformOperation;
all_micro_ops_.emplace_back();
} else { } else {
instructions[instruction].operation = mapping.operation; // Install source and destination.
instructions[instruction].source = &data_[source]; instructions[instruction].source = &data_[source];
instructions[instruction].destination = &data_[destination]; instructions[instruction].destination = &data_[destination];
// instructions[instruction].destination.micro_operations =
std::cout << "Data register to data register from " << source << " to " << destination << std::endl; // For micro-ops, just schedule the proper bus cycle to get the next thing into the prefetch queue,
// then perform the actual operation.
all_micro_ops_.emplace_back();
all_micro_ops_.back().bus_program = &all_bus_steps_[bus_step_collection.six_step_Dn];
all_micro_ops_.back().action = MicroOp::Action::PerformOperation;
all_micro_ops_.emplace_back();
} }
} break; } break;
@ -210,8 +266,16 @@ void ProcessorStorage::install_instructions(const BusStepCollection &bus_step_co
break; break;
} }
// Don't search further through the list of possibilities.
break; break;
} }
} }
} }
// Finalise micro-op pointers.
for(size_t instruction = 0; instruction < 65536; ++instruction) {
if(micro_op_pointers[instruction] != std::numeric_limits<size_t>::max()) {
instructions[instruction].micro_operations = &all_micro_ops_[micro_op_pointers[instruction]];
}
}
} }

View File

@ -15,10 +15,12 @@ class ProcessorStorage {
protected: protected:
RegisterPair32 data_[8]; RegisterPair32 data_[8];
RegisterPair32 address_[7]; RegisterPair32 address_[8];
RegisterPair32 stack_pointers_[2]; // [0] = user stack pointer; [1] = supervisor
RegisterPair32 program_counter_; RegisterPair32 program_counter_;
RegisterPair32 stack_pointers_[2]; // [0] = user stack pointer; [1] = supervisor; the values from here
// are copied into/out of address_[7] upon mode switches.
RegisterPair16 prefetch_queue_[2]; RegisterPair16 prefetch_queue_[2];
bool dtack_ = true; bool dtack_ = true;
@ -27,7 +29,7 @@ class ProcessorStorage {
// Generic sources and targets for memory operations. // Generic sources and targets for memory operations.
uint32_t effective_address_; uint32_t effective_address_;
RegisterPair32 bus_data_; RegisterPair32 bus_data_[2];
enum class Operation { enum class Operation {
ABCD, SBCD, ABCD, SBCD,
@ -70,7 +72,11 @@ class ProcessorStorage {
struct MicroOp { struct MicroOp {
enum class Action { enum class Action {
None, None,
PerformOperation PerformOperation,
PredecrementSourceAndDestination1,
PredecrementSourceAndDestination2,
PredecrementSourceAndDestination4,
} action = Action::None; } action = Action::None;
BusStep *bus_program = nullptr; BusStep *bus_program = nullptr;
}; };
@ -82,9 +88,9 @@ class ProcessorStorage {
*/ */
struct Program { struct Program {
MicroOp *micro_operations = nullptr; MicroOp *micro_operations = nullptr;
Operation operation;
RegisterPair32 *source; RegisterPair32 *source;
RegisterPair32 *destination; RegisterPair32 *destination;
Operation operation;
}; };
// Storage for all the sequences of bus steps and micro-ops used throughout // Storage for all the sequences of bus steps and micro-ops used throughout
@ -146,11 +152,16 @@ class ProcessorStorage {
The user should fill in the steps necessary to get data into or extract The user should fill in the steps necessary to get data into or extract
data from those. data from those.
*/ */
size_t assemble_program(const char *access_pattern); size_t assemble_program(const char *access_pattern, const std::vector<uint32_t *> &addresses = {}, int data_mask = Microcycle::UpperData | Microcycle::LowerData);
struct BusStepCollection { struct BusStepCollection {
size_t six_step_Dn; size_t six_step_Dn;
size_t four_step_Dn; size_t four_step_Dn;
// The next two are indexed as [source][destination].
size_t double_predec_byte[8][8];
size_t double_predec_word[8][8];
size_t double_predec_long[8][8];
}; };
BusStepCollection assemble_standard_bus_steps(); BusStepCollection assemble_standard_bus_steps();