mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-27 22:30:49 +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:
|
||||
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;
|
||||
}
|
||||
|
@ -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]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user