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:
parent
57898ed6dd
commit
bb04981280
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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]];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user