mirror of
https://github.com/TomHarte/CLK.git
synced 2025-04-09 00:37:27 +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:
parent
1d801acf72
commit
412a1eb7ee
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user