1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-05 10:28:58 +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:
std::cerr << "Should do something with program operation " << int(active_program_->operation) << std::endl;
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;
}

View File

@ -31,8 +31,11 @@ ProcessorStorage::ProcessorStorage() {
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();
auto address_iterator = addresses.begin();
RegisterPair32 *scratch_data_read = bus_data_;
RegisterPair32 *scratch_data_write = bus_data_;
// Parse the access pattern to build microcycles.
while(*access_pattern) {
@ -105,6 +108,28 @@ size_t ProcessorStorage::assemble_program(const char *access_pattern) {
access_pattern += 2;
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;
@ -128,6 +153,14 @@ ProcessorStorage::BusStepCollection ProcessorStorage::assemble_standard_bus_step
collection.four_step_Dn = assemble_program("np");
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;
}
@ -183,22 +216,45 @@ void ProcessorStorage::install_instructions(const BusStepCollection &bus_step_co
{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.
for(int instruction = 0; instruction < 65536; ++instruction) {
for(size_t instruction = 0; instruction < 65536; ++instruction) {
for(const auto &mapping: mappings) {
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) {
case Decoder::Decimal: {
const int destination = (instruction >> 8) & 7;
const int source = instruction & 7;
all_micro_ops_.emplace_back();
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 {
instructions[instruction].operation = mapping.operation;
// Install source and destination.
instructions[instruction].source = &data_[source];
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;
@ -210,8 +266,16 @@ void ProcessorStorage::install_instructions(const BusStepCollection &bus_step_co
break;
}
// Don't search further through the list of possibilities.
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:
RegisterPair32 data_[8];
RegisterPair32 address_[7];
RegisterPair32 stack_pointers_[2]; // [0] = user stack pointer; [1] = supervisor
RegisterPair32 address_[8];
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];
bool dtack_ = true;
@ -27,7 +29,7 @@ class ProcessorStorage {
// Generic sources and targets for memory operations.
uint32_t effective_address_;
RegisterPair32 bus_data_;
RegisterPair32 bus_data_[2];
enum class Operation {
ABCD, SBCD,
@ -70,7 +72,11 @@ class ProcessorStorage {
struct MicroOp {
enum class Action {
None,
PerformOperation
PerformOperation,
PredecrementSourceAndDestination1,
PredecrementSourceAndDestination2,
PredecrementSourceAndDestination4,
} action = Action::None;
BusStep *bus_program = nullptr;
};
@ -82,9 +88,9 @@ class ProcessorStorage {
*/
struct Program {
MicroOp *micro_operations = nullptr;
Operation operation;
RegisterPair32 *source;
RegisterPair32 *destination;
Operation operation;
};
// 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
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 {
size_t six_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();