1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-05 10:28:58 +00:00

Takes an initial run at (An)+, -(An), (d16,An) and (d8,An,Xn) addressing modes.

With only MOVEs from those to a data register implemented so far.
This commit is contained in:
Thomas Harte 2019-03-18 22:51:32 -04:00
parent 1d801acf72
commit 412a1eb7ee
3 changed files with 193 additions and 32 deletions

View File

@ -40,7 +40,8 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
case BusStep::Action::None: break;
case BusStep::Action::IncrementEffectiveAddress: effective_address_ += 2; break;
case BusStep::Action::IncrementEffectiveAddress0: effective_address_[0] += 2; break;
case BusStep::Action::IncrementEffectiveAddress1: effective_address_[1] += 2; break;
case BusStep::Action::IncrementProgramCounter: program_counter_.full += 2; break;
case BusStep::Action::AdvancePrefetch:
@ -80,6 +81,10 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
}
switch(active_micro_op_->action) {
default:
std::cerr << "Unhandled 68000 micro op action " << std::hex << active_micro_op_->action << std::endl;
break;
case MicroOp::Action::None: break;
case MicroOp::Action::PerformOperation:
@ -147,25 +152,97 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
}
break;
case MicroOp::Action::PredecrementSourceAndDestination1:
-- active_program_->source->full;
-- active_program_->destination->full;
case MicroOp::Action::Decrement1:
if(active_micro_op_->action & MicroOp::SourceMask) active_program_->source->full -= 1;
if(active_micro_op_->action & MicroOp::DestinationMask) active_program_->destination->full -= 1;
break;
case MicroOp::Action::PredecrementSourceAndDestination2:
active_program_->source->full -= 2;
active_program_->destination->full -= 2;
case MicroOp::Action::Decrement2:
if(active_micro_op_->action & MicroOp::SourceMask) active_program_->source->full -= 2;
if(active_micro_op_->action & MicroOp::DestinationMask) active_program_->destination->full -= 2;
break;
case MicroOp::Action::PredecrementSourceAndDestination4:
active_program_->source->full -= 4;
active_program_->destination->full -= 4;
case MicroOp::Action::Decrement4:
if(active_micro_op_->action & MicroOp::SourceMask) active_program_->source->full -= 4;
if(active_micro_op_->action & MicroOp::DestinationMask) active_program_->destination->full -= 4;
break;
case MicroOp::Action::SignExtendDestinationWord:
active_program_->destination->halves.high.full =
(active_program_->destination->halves.low.full & 0x8000) ? 0xffff : 0x0000;
case MicroOp::Action::Increment1:
if(active_micro_op_->action & MicroOp::SourceMask) active_program_->source->full += 1;
if(active_micro_op_->action & MicroOp::DestinationMask) active_program_->destination->full += 1;
break;
case MicroOp::Action::Increment2:
if(active_micro_op_->action & MicroOp::SourceMask) active_program_->source->full += 2;
if(active_micro_op_->action & MicroOp::DestinationMask) active_program_->destination->full += 2;
break;
case MicroOp::Action::Increment4:
if(active_micro_op_->action & MicroOp::SourceMask) active_program_->source->full += 4;
if(active_micro_op_->action & MicroOp::DestinationMask) active_program_->destination->full += 4;
break;
case MicroOp::Action::SignExtendWord:
if(active_micro_op_->action & MicroOp::SourceMask) {
active_program_->source->halves.high.full =
(active_program_->source->halves.low.full & 0x8000) ? 0xffff : 0x0000;
}
if(active_micro_op_->action & MicroOp::DestinationMask) {
active_program_->destination->halves.high.full =
(active_program_->destination->halves.low.full & 0x8000) ? 0xffff : 0x0000;
}
break;
case MicroOp::Action::SignExtendByte:
if(active_micro_op_->action & MicroOp::SourceMask) {
active_program_->source->full = (active_program_->source->full & 0xff) |
(active_program_->source->full & 0x80) ? 0xffffff : 0x000000;
}
if(active_micro_op_->action & MicroOp::DestinationMask) {
active_program_->destination->full = (active_program_->destination->full & 0xff) |
(active_program_->destination->full & 0x80) ? 0xffffff : 0x000000;
}
break;
case int(MicroOp::Action::CalcD16An) | MicroOp::SourceMask:
effective_address_[0] = int16_t(prefetch_queue_[0].full) + active_program_->source->full;
break;
case int(MicroOp::Action::CalcD16An) | MicroOp::DestinationMask:
effective_address_[1] = int16_t(prefetch_queue_[0].full) + active_program_->destination->full;
break;
case int(MicroOp::Action::CalcD16An) | MicroOp::SourceMask | MicroOp::DestinationMask:
effective_address_[0] = int16_t(prefetch_queue_[0].full) + active_program_->source->full;
effective_address_[1] = int16_t(prefetch_queue_[1].full) + active_program_->destination->full;
break;
// TODO: permit as below for DestinationMask and SourceMask|DestinationMask; would prefer to test first.
#define CalculateD8AnXn(data, source, target) {\
const auto register_index = (data.full >> 12) & 7; \
const RegisterPair32 &displacement = (data.full & 0x8000) ? address_[register_index] : data_[register_index]; \
target = int8_t(data.halves.low) + source->full; \
\
if(data.full & 0x800) { \
effective_address_[0] += displacement.halves.low; \
} else { \
effective_address_[0] += displacement.full; \
} \
}
case int(MicroOp::Action::CalcD8AnXn) | MicroOp::SourceMask: {
CalculateD8AnXn(prefetch_queue_[0], active_program_->source, effective_address_[0]);
} break;
case int(MicroOp::Action::CalcD8AnXn) | MicroOp::DestinationMask: {
CalculateD8AnXn(prefetch_queue_[0], active_program_->destination, effective_address_[1]);
} break;
case int(MicroOp::Action::CalcD8AnXn) | MicroOp::SourceMask | MicroOp::DestinationMask: {
CalculateD8AnXn(prefetch_queue_[0], active_program_->source, effective_address_[0]);
CalculateD8AnXn(prefetch_queue_[1], active_program_->destination, effective_address_[1]);
} break;
#undef CalculateD8AnXn
}
// If we've got to a micro-op that includes bus steps, break out of this loop.

View File

@ -96,13 +96,13 @@ struct ProcessorStorageConstructor {
case 'f': // Fetch SSP LSW.
step.microcycle.length = HalfCycles(5);
step.microcycle.operation = Microcycle::NewAddress | Microcycle::Read | Microcycle::IsProgram; // IsProgram is a guess.
step.microcycle.address = &storage_.effective_address_;
step.microcycle.address = &storage_.effective_address_[0];
step.microcycle.value = isupper(access_pattern[1]) ? &storage_.stack_pointers_[1].halves.high : &storage_.stack_pointers_[1].halves.low;
steps.push_back(step);
step.microcycle.length = HalfCycles(3);
step.microcycle.operation = Microcycle::SelectWord | Microcycle::Read | Microcycle::IsProgram;
step.action = Action::IncrementEffectiveAddress;
step.action = Action::IncrementEffectiveAddress0;
steps.push_back(step);
access_pattern += 2;
@ -112,13 +112,13 @@ struct ProcessorStorageConstructor {
case 'v': // Fetch exception vector high.
step.microcycle.length = HalfCycles(5);
step.microcycle.operation = Microcycle::NewAddress | Microcycle::Read | Microcycle::IsProgram; // IsProgram is a guess.
step.microcycle.address = &storage_.effective_address_;
step.microcycle.address = &storage_.effective_address_[0];
step.microcycle.value = isupper(access_pattern[1]) ? &storage_.program_counter_.halves.high : &storage_.program_counter_.halves.low;
steps.push_back(step);
step.microcycle.length = HalfCycles(3);
step.microcycle.operation |= Microcycle::SelectWord | Microcycle::Read | Microcycle::IsProgram;
step.action = Action::IncrementEffectiveAddress;
step.action = Action::IncrementEffectiveAddress0;
steps.push_back(step);
access_pattern += 2;
@ -213,6 +213,7 @@ struct ProcessorStorageConstructor {
using Operation = ProcessorStorage::Operation;
using Action = ProcessorStorage::MicroOp::Action;
using MicroOp = ProcessorBase::MicroOp;
struct PatternMapping {
uint16_t mask, value;
Operation operation;
@ -273,7 +274,7 @@ struct ProcessorStorageConstructor {
storage_.instructions[instruction].destination = &storage_.bus_data_[1];
storage_.all_micro_ops_.emplace_back(
Action::PredecrementSourceAndDestination1,
int(Action::Decrement1) | MicroOp::SourceMask | MicroOp::DestinationMask,
&arbitrary_base + assemble_program("n nr nr np nw", { &storage_.address_[source].full, &storage_.address_[destination].full, &storage_.address_[destination].full }, false));
storage_.all_micro_ops_.emplace_back(Action::PerformOperation);
} else {
@ -327,7 +328,7 @@ struct ProcessorStorageConstructor {
storage_.all_micro_ops_.emplace_back(Action::PerformOperation, &arbitrary_base + assemble_program("np"));
storage_.all_micro_ops_.emplace_back(
(mapping.operation == Operation::MOVEw) ? Action::SignExtendDestinationWord : Action::None
(mapping.operation == Operation::MOVEw) ? int(Action::SignExtendWord) | MicroOp::DestinationMask : int(Action::None)
);
break;
@ -340,6 +341,43 @@ struct ProcessorStorageConstructor {
}
break;
case 0x30: // MOVE (As)+, Dd
if(mapping.operation == Operation::MOVEl) {
continue;
} else {
storage_.all_micro_ops_.emplace_back(Action::None, &arbitrary_base + assemble_program("nr np", { &storage_.address_[source_register].full }, !is_byte_access));
storage_.all_micro_ops_.emplace_back(int(is_byte_access ? Action::Increment1 : Action::Increment2) | MicroOp::SourceMask);
storage_.all_micro_ops_.emplace_back(Action::PerformOperation);
}
break;
case 0x40: // MOVE -(As), Dd
if(mapping.operation == Operation::MOVEl) {
continue;
} else {
storage_.all_micro_ops_.emplace_back(int(is_byte_access ? Action::Decrement1 : Action::Decrement2) | MicroOp::SourceMask, &arbitrary_base + assemble_program("n nr np", { &storage_.address_[source_register].full }, !is_byte_access));
storage_.all_micro_ops_.emplace_back(Action::PerformOperation);
}
break;
case 0x50: // MOVE (d16,As), Dd
if(mapping.operation == Operation::MOVEl) {
continue;
} else {
storage_.all_micro_ops_.emplace_back(int(Action::CalcD16An) | MicroOp::SourceMask, &arbitrary_base + assemble_program("n np nr np", { &storage_.effective_address_[0] }, !is_byte_access));
storage_.all_micro_ops_.emplace_back(Action::PerformOperation);
}
break;
case 0x60: // MOVE (d8,As,Xn), Dd
if(mapping.operation == Operation::MOVEl) {
continue;
} else {
storage_.all_micro_ops_.emplace_back(int(Action::CalcD8AnXn) | MicroOp::SourceMask, &arbitrary_base + assemble_program("n np nr np", { &storage_.effective_address_[0] }, !is_byte_access));
storage_.all_micro_ops_.emplace_back(Action::PerformOperation);
}
break;
default:
// TODO: all other types of mode.
continue;
@ -398,7 +436,7 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() {
// Set initial state. Largely TODO.
active_step_ = reset_program_;
effective_address_ = 0;
effective_address_[0] = 0;
is_supervisor_ = 1;
}

View File

@ -32,8 +32,9 @@ class ProcessorStorage {
uint_fast32_t overflow_flag_; // The overflow flag is set if this value is non-zero.
uint_fast32_t negative_flag_; // The negative flag is set if this value is non-zero.
// Generic sources and targets for memory operations.
uint32_t effective_address_;
// Generic sources and targets for memory operations;
// by convention: [0] = source, [1] = destination.
uint32_t effective_address_[2];
RegisterPair32 bus_data_[2];
enum class Operation {
@ -52,8 +53,11 @@ class ProcessorStorage {
enum class Action {
None,
/// Performs effective_address_ += 2.
IncrementEffectiveAddress,
/// Performs effective_address_[0] += 2.
IncrementEffectiveAddress0,
/// Performs effective_address_[1] += 2.
IncrementEffectiveAddress1,
/// Performs program_counter_ += 2.
IncrementProgramCounter,
@ -92,21 +96,63 @@ class ProcessorStorage {
be performed.
*/
struct MicroOp {
enum class Action {
enum class Action: int {
None,
PerformOperation,
PredecrementSourceAndDestination1,
PredecrementSourceAndDestination2,
PredecrementSourceAndDestination4,
/*
All of the below will honour the source and destination masks
in deciding where to apply their actions.
*/
/// Subtracts 1.
Decrement1,
/// Subtracts 2.
Decrement2,
/// Subtracts 4.
Decrement4,
/// Adds 1.
Increment1,
/// Adds 2.
Increment2,
/// Adds 4.
Increment4,
/// Peeking into the prefetch queue, calculates the proper target of (d16,An) addressing.
CalcD16An,
/// Peeking into the prefetch queue, calculates the proper target of (d8,An,Xn) addressing.
CalcD8AnXn,
/// Peeking into the prefetch queue, calculates the proper target of (d16,PC) addressing,
/// adjusting as though it had been performed after the proper PC fetches. The source
/// and destination mask flags affect only the destination of the result.
CalcD16PC,
/// Peeking into the prefetch queue, calculates the proper target of (d8,An,Xn) addressing,
/// adjusting as though it had been performed after the proper PC fetches. The source
/// and destination mask flags affect only the destination of the result.
CalcD8PCXn,
/// Sets the high word according to the MSB of the low word.
SignExtendWord,
/// Sets the high three bytes according to the MSB of the low byte.
SignExtendByte,
};
static const int SourceMask = 1 << 30;
static const int DestinationMask = 1 << 29;
int action = int(Action::None);
SignExtendDestinationWord,
} action = Action::None;
BusStep *bus_program = nullptr;
MicroOp() {}
MicroOp(Action action) : action(action) {}
MicroOp(Action action, BusStep *bus_program) : action(action), bus_program(bus_program) {}
MicroOp(int action) : action(action) {}
MicroOp(int action, BusStep *bus_program) : action(action), bus_program(bus_program) {}
MicroOp(Action action) : MicroOp(int(action)) {}
MicroOp(Action action, BusStep *bus_program) : MicroOp(int(action), bus_program) {}
inline bool is_terminal() const {
return bus_program == nullptr;